diff --git a/README.md b/README.md index c5b4238..b7455c2 100644 --- a/README.md +++ b/README.md @@ -211,7 +211,7 @@ def neg_log_dens(q): system = systems.DenseConstrainedEuclideanMetricSystem(neg_log_dens, constr) # System is constrained therefore use constrained leapfrog integrator -integrator = integrators.ConstrainedLeapfrogIntegrator(system, step_size=0.2) +integrator = integrators.ConstrainedLeapfrogIntegrator(system) # Seed a random number generator rng = np.random.default_rng(seed=1234) @@ -233,9 +233,11 @@ def trace_func(state): x, y, z = state.pos return {'x': x, 'y': y, 'z': z} -# Sample four chains of 2500 samples in parallel -final_states, traces, stats = sampler.sample_chains( - n_sample=2500, init_states=q_init, n_process=4, trace_funcs=[trace_func]) +# Sample 4 chains in parallel with 500 adaptive warm up iterations in which the +# integrator step size is tuned, followed by 2000 non-adaptive iterations +final_states, traces, stats = sampler.sample_chains_with_adaptive_warm_up( + n_warm_up_iter=500, n_main_iter=2000, init_states=q_init, n_process=4, + trace_funcs=[trace_func]) # Print average accept probability and number of integrator steps per chain for c in range(n_chain): diff --git a/docs/docs/adapters.html b/docs/docs/adapters.html new file mode 100644 index 0000000..31cfad2 --- /dev/null +++ b/docs/docs/adapters.html @@ -0,0 +1,1766 @@ + + + + + + +mici.adapters API documentation + + + + + + + + + + +
+ +
+
+

Module mici.adapters

+
+
+

Methods for adaptively setting algorithmic parameters of transitions.

+
+ +Expand source code +Browse git + +
"""Methods for adaptively setting algorithmic parameters of transitions."""
+
+from abc import ABC, abstractmethod, abstractproperty
+from math import exp, log
+import numpy as np
+from mici.errors import IntegratorError, AdaptationError
+from mici.matrices import (
+    PositiveDiagonalMatrix, DensePositiveDefiniteMatrix)
+
+
+class Adapter(ABC):
+    """Abstract adapter for implementing schemes to adapt transition parameters.
+
+    Adaptation schemes are assumed to be based on updating a collection of
+    adaptation variables (collectively termed the adapter state here) after
+    each chain transition based on the sampled chain state and/or statistics of
+    the transition such as an acceptance probability statistic. After completing
+    a chain of one or more adaptive transitions, the final adapter state may be
+    used to perform a final update to the transition parameters.
+    """
+
+    @abstractmethod
+    def initialize(self, chain_state, transition):
+        """Initialize adapter state prior to starting adaptive transitions.
+
+        Args:
+            chain_state (mici.states.ChainState): Initial chain state adaptive
+                transition will be started from. May be used to calculate
+                initial adapter state but should not be mutated by method.
+            transition (mici.transitions.Transition): Markov transition being
+                adapted. Attributes of the transition or child objects may be
+                updated in-place by the method.
+
+        Returns:
+            adapt_state (Dict[str, Any]): Initial adapter state.
+        """
+
+    @abstractmethod
+    def update(self, adapt_state, chain_state, trans_stats, transition):
+        """Update adapter state after sampling transition being adapted.
+
+        Args:
+            adapt_state (Dict[str, Any]): Current adapter state. Entries will
+                be updated in-place by the method.
+            chain_state (mici.states.ChainState): Current chain state following
+                sampling from transition being adapted. May be used to calculate
+                adapter state updates but should not be mutated by method.
+            trans_stats (Dict[str, numeric]): Dictionary of statistics
+                associated with transition being adapted. May be used to
+                calculate adapter state updates but should not be mutated by
+                method.
+            transition (mici.transitions.Transition): Markov transition being
+                adapted. Attributes of the transition or child objects may be
+                updated in-place by the method.
+        """
+
+    @abstractmethod
+    def finalize(self, adapt_state, transition):
+        """Update transition parameters based on final adapter state or states.
+
+        Optionally, if multiple adapter states are available, e.g. from a set of
+        independent adaptive chains, then these adaptation information from all
+        the chains may be combined to set the transition parameter(s).
+
+        Args:
+            adapt_state (Dict[str, Any] or List[Dict[str, Any]]): Final adapter
+                state or a list of adapter states. Arrays / buffers associated
+                with the adapter state entries may be recycled to reduce memory
+                usage - if so the corresponding entries will be removed from
+                the adapter state dictionary / dictionaries.
+            transition (mici.transitions.Transition): Markov transition being
+                adapted. Attributes of the transition or child objects will be
+                updated in-place by the method.
+        """
+
+
+class DualAveragingStepSizeAdapter(Adapter):
+    """Dual averaging integrator step size adapter.
+
+    Implementation of the dual algorithm step size adaptation algorithm
+    described in [1], a modified version of the stochastic optimisation scheme
+    of [2]. By default the adaptation is performed to control the `accept_prob`
+    statistic of an integration transition to be close to a target value but
+    the statistic adapted on can be altered by changing the `adapt_stat_func`.
+
+
+    References:
+
+      1. Hoffman, M.D. and Gelman, A., 2014. The No-U-turn sampler:
+         adaptively setting path lengths in Hamiltonian Monte Carlo.
+         Journal of Machine Learning Research, 15(1), pp.1593-1623.
+      2. Nesterov, Y., 2009. Primal-dual subgradient methods for convex
+         problems. Mathematical programming 120(1), pp.221-259.
+    """
+
+    def __init__(self, adapt_stat_target=0.8, adapt_stat_func=None,
+                 log_step_size_reg_target=None,
+                 log_step_size_reg_coefficient=0.05, iter_decay_coeff=0.75,
+                 iter_offset=10, max_init_step_size_iters=100):
+        """
+        Args:
+            adapt_stat_target (float): Target value for the transition statistic
+                being controlled during adaptation.
+            adapt_stat_func (Callable[[Dict[str, numeric]], numeric]): Function
+                which given a dictionary of transition statistics outputs the
+                value of the statistic to control during adaptation. By default
+                this is set to a function which simply selects the 'accept_stat'
+                value in the statistics dictionary.
+            log_step_size_reg_target (float or None): Value to regularize the
+                controlled output (logarithm of the integrator step size)
+                towards. If `None` set to `log(10 * init_step_size)` where
+                `init_step_size` is the initial 'reasonable' step size found by
+                a coarse search as recommended in Hoffman and Gelman (2014).
+                This has the effect of giving the dual averaging algorithm a
+                tendency towards testing step sizes larger than the initial
+                value, with typically integrating with a larger step size having
+                a lower computational cost.
+            log_step_size_reg_coefficient (float): Coefficient controlling
+                amount of regularisation of controlled output (logarithm of the
+                integrator step size) towards `log_step_size_reg_target`.
+                Defaults to 0.05 as recommended in Hoffman and Gelman (2014).
+            iter_decay_coeff (float): Coefficient controlling exponent of
+                decay in schedule weighting stochastic updates to smoothed log
+                step size estimate. Should be in the interval (0.5, 1] to ensure
+                asymptotic convergence of adaptation. A value of 1 gives equal
+                weight to the whole history of updates while setting to a
+                smaller value increasingly highly weights recent updates, giving
+                a tendency to 'forget' early updates. Defaults to 0.75 as
+                recommended in Hoffman and Gelman (2014).
+            iter_offset (int): Offset used for the iteration based weighting of
+                the adaptation statistic error estimate. Should be set to a
+                non-negative value. A value > 0 has the effect of stabilising
+                early iterations. Defaults to the value of 10 as recommended in
+                Hoffman and Gelman (2014).
+            max_init_step_size_iters (int): Maximum number of iterations to use
+                in initial search for a reasonable step size with an
+                `AdaptationError` exception raised if a suitable step size is
+                not found within this many iterations.
+        """
+        self.adapt_stat_target = adapt_stat_target
+        if adapt_stat_func is None:
+            def adapt_stat_func(stats): return stats['accept_stat']
+        self.adapt_stat_func = adapt_stat_func
+        self.log_step_size_reg_target = log_step_size_reg_target
+        self.log_step_size_reg_coefficient = log_step_size_reg_coefficient
+        self.iter_decay_coeff = iter_decay_coeff
+        self.iter_offset = iter_offset
+        self.max_init_step_size_iters = max_init_step_size_iters
+
+    def initialize(self, chain_state, transition):
+        integrator = transition.integrator
+        system = transition.system
+        adapt_state = {
+            'iter': 0,
+            'smoothed_log_step_size': 0.,
+            'adapt_stat_error': 0.,
+        }
+        init_step_size = (self._find_and_set_init_step_size(
+            chain_state, system, integrator) if integrator.step_size is None
+            else integrator.step_size)
+        if self.log_step_size_reg_target is None:
+            adapt_state['log_step_size_reg_target'] = log(10 * init_step_size)
+        else:
+            adapt_state['log_step_size_reg_target'] = (
+                self.log_step_size_reg_target)
+        return adapt_state
+
+    def _find_and_set_init_step_size(self, state, system, integrator):
+        """Find initial step size by coarse search using single step statistics.
+
+        Adaptation of Algorithm 4 in Hoffman and Gelman (2014).
+
+        Compared to the Hoffman and Gelman algorithm, this version makes two
+        changes:
+
+          1. The absolute value of the change in Hamiltonian over a step being
+             larger or smaller than log(2) is used to determine whether the step
+             size is too big or small as opposed to the value of the equivalent
+             Metropolis accept probability being larger or smaller than 0.5.
+             Although a negative change in the Hamiltonian over a step of
+             magnitude more than log(2) will lead to an accept probability of 1
+             for the forward move, the corresponding reversed move will have an
+             accept probability less than 0.5, and so a change in the
+             Hamiltonian over a step of magnitude more than log(2) irrespective
+             of the sign of the change is indicative of the minimum acceptance
+             probability over both forward and reversed steps being less than
+             0.5.
+          2. To allow for integrators for which an integrator step may fail due
+             to e.g. a convergence error in an iterative solver, the step size
+             is also considered to be too big if any of the step sizes tried in
+             the search result in a failed integrator step, with in this case
+             the step size always being decreased on subsequent steps
+             irrespective of the initial Hamiltonian error, until a integrator
+             step successfully completes and the absolute value of the change in
+             Hamiltonian is below the threshold of log(2) (corresponding to a
+             minimum acceptance probability over forward and reversed steps of
+             0.5).
+        """
+        init_state = state.copy()
+        h_init = system.h(init_state)
+        integrator.step_size = 1
+        delta_h_threshold = log(2)
+        for s in range(self.max_init_step_size_iters):
+            try:
+                state = integrator.step(init_state)
+                delta_h = abs(h_init - system.h(state))
+                if s == 0:
+                    step_size_too_big = delta_h > delta_h_threshold
+                if (step_size_too_big and delta_h <= delta_h_threshold) or (
+                        not step_size_too_big and delta_h > delta_h_threshold):
+                    return integrator.step_size
+                elif step_size_too_big:
+                    integrator.step_size /= 2
+                else:
+                    integrator.step_size *= 2
+            except IntegratorError:
+                step_size_too_big = True
+                integrator.step_size /= 2
+        raise AdaptationError(
+            f'Could not find reasonable initial step size in '
+            f'{self.max_init_step_size_iters} iterations (final step size '
+            f'{integrator.step_size}). A very large final step size may '
+            f'indicate that the target distribution is improper such that the '
+            f'negative log density is flat in one or more directions while a '
+            f'very small final step size may indicate that the density function'
+            f' is insufficiently smooth at the point initialized at.')
+
+    def update(self, adapt_state, chain_state, trans_stats, transition):
+        adapt_state['iter'] += 1
+        error_weight = 1 / (self.iter_offset + adapt_state['iter'])
+        adapt_state['adapt_stat_error'] *= (1 - error_weight)
+        adapt_state['adapt_stat_error'] += error_weight * (
+            self.adapt_stat_target - self.adapt_stat_func(trans_stats))
+        smoothing_weight = (1 / adapt_state['iter'])**self.iter_decay_coeff
+        log_step_size = adapt_state['log_step_size_reg_target'] - (
+            adapt_state['adapt_stat_error'] * adapt_state['iter']**0.5 /
+            self.log_step_size_reg_coefficient)
+        adapt_state['smoothed_log_step_size'] *= (1 - smoothing_weight)
+        adapt_state['smoothed_log_step_size'] += (
+            smoothing_weight * log_step_size)
+        transition.integrator.step_size = exp(log_step_size)
+
+    def finalize(self, adapt_state, transition):
+        if isinstance(adapt_state, dict):
+            transition.integrator.step_size = exp(
+                adapt_state['smoothed_log_step_size'])
+        else:
+            transition.integrator.step_size = sum(
+                exp(a['smoothed_log_step_size'])
+                for a in adapt_state) / len(adapt_state)
+
+
+class OnlineVarianceMetricAdapter(Adapter):
+    """Diagonal metric adapter using online variance estimates.
+
+    Uses Welford's algorithm [1] to stably compute an online estimate of the
+    sample variances of the chain state position components during sampling. If
+    online estimates are available from multiple independent chains, the final
+    variance estimate is calculated from the per-chain statistics using the
+    parallel / batched incremental variance algorithm described by Chan et al.
+    [2]. The variance estimates are optionally regularized towards a common
+    scalar value, with increasing weight for small number of samples, to
+    decrease the effect of noisy estimates for small sample sizes, following the
+    approach in Stan [3]. The metric matrix representation is set to a diagonal
+    matrix with diagonal elements corresponding to the reciprocal of the
+    (regularized) variance estimates.
+
+    References:
+
+      1. Welford, B. P., 1962. Note on a method for calculating corrected sums
+         of squares and products. Technometrics, 4(3), pp. 419–420.
+      2. Chan, T. F., Golub, G. H., LeVeque, R. J., 1979. Updating formulae and
+         a pairwise algorithm for computing sample variances. Technical Report
+         STAN-CS-79-773, Department of Computer Science, Stanford University.
+      3. Carpenter, B., Gelman, A., Hoffman, M.D., Lee, D., Goodrich, B.,
+         Betancourt, M., Brubaker, M., Guo, J., Li, P. and Riddell, A., 2017.
+         Stan: A probabilistic programming language. Journal of Statistical
+         Software, 76(1).
+    """
+
+    def __init__(self, reg_iter_offset=5, reg_scale=1e-3):
+        """
+        Args:
+            reg_iter_offset (int): Iteration offset used for calculating
+                iteration dependent weighting between regularisation target and
+                current covariance estimate. Higher values cause stronger
+                regularisation during initial iterations. A value of zero
+                corresponds to no regularisation; this should only be used if
+                the sample covariance is guaranteed to be positive definite.
+            reg_scale (float): Positive scalar defining value variance estimates
+                are regularized towards.
+        """
+        self.reg_iter_offset = reg_iter_offset
+        self.reg_scale = reg_scale
+
+    def initialize(self, chain_state, transition):
+        return {
+            'iter': 0,
+            'mean': np.zeros_like(chain_state.pos),
+            'sum_diff_sq': np.zeros_like(chain_state.pos)
+        }
+
+    def update(self, adapt_state, chain_state, trans_stats, transition):
+        # Use Welford (1962) incremental algorithm to update statistics to
+        # calculate online variance estimate
+        # https://en.wikipedia.org/wiki/
+        #   Algorithms_for_calculating_variance#Welford's_online_algorithm
+        adapt_state['iter'] += 1
+        pos_minus_mean = chain_state.pos - adapt_state['mean']
+        adapt_state['mean'] += pos_minus_mean / adapt_state['iter']
+        adapt_state['sum_diff_sq'] += pos_minus_mean * (
+            chain_state.pos - adapt_state['mean'])
+
+    def _regularize_var_est(self, var_est, n_iter):
+        """Update variance estimates by regularizing towards common scalar.
+
+        Performed in place to prevent further array allocations.
+        """
+        if self.reg_iter_offset is not None and self.reg_iter_offset != 0:
+            var_est *= n_iter / (self.reg_iter_offset + n_iter)
+            var_est += self.reg_scale * (
+                self.reg_iter_offset / (self.reg_iter_offset + n_iter))
+
+    def finalize(self, adapt_state, transition):
+        if isinstance(adapt_state, dict):
+            n_iter = adapt_state['iter']
+            var_est = adapt_state.pop('sum_diff_sq')
+        else:
+            # Use Chan et al. (1979) parallel variance estimation algorithm
+            # to combine per-chain statistics
+            # https://en.wikipedia.org/wiki/
+            #    Algorithms_for_calculating_variance#Parallel_algorithm
+            for i, a in enumerate(adapt_state):
+                if i == 0:
+                    n_iter = a['iter']
+                    mean_est = a.pop('mean')
+                    var_est = a.pop('sum_diff_sq')
+                else:
+                    n_iter_prev = n_iter
+                    n_iter += a['iter']
+                    mean_diff = mean_est - a['mean']
+                    mean_est *= n_iter_prev
+                    mean_est += a['iter'] * a['mean']
+                    mean_est /= n_iter
+                    var_est += a['sum_diff_sq']
+                    var_est += mean_diff**2 * (a['iter'] * n_iter_prev) / n_iter
+        if n_iter < 2:
+            raise AdaptationError(
+                'At least two chain samples required to compute a variance '
+                'estimates.')
+        var_est /= (n_iter - 1)
+        self._regularize_var_est(var_est, n_iter)
+        transition.system.metric = PositiveDiagonalMatrix(var_est).inv
+
+
+class OnlineCovarianceMetricAdapter(Adapter):
+    """Dense metric adapter using online covariance estimates.
+
+    Uses Welford's algorithm [1] to stably compute an online estimate of the
+    sample covariane matrix of the chain state position components during
+    sampling. If online estimates are available from multiple independent
+    chains, the final covariance matrix estimate is calculated from the
+    per-chain statistics using a covariance variant due to Schubert and Gertz
+    [2] of the parallel / batched incremental variance algorithm described by
+    Chan et al. [3]. The covariance matrix estimates are optionally regularized
+    towards a scaled identity matrix, with increasing weight for small number of
+    samples, to decrease the effect of noisy estimates for small sample sizes,
+    following the approach in Stan [4]. The metric matrix representation is set
+    to a dense positive definite matrix corresponding to the inverse of the
+    (regularized) covariance matrix estimate.
+
+
+    References:
+
+      1. Welford, B. P., 1962. Note on a method for calculating corrected sums
+         of squares and products. Technometrics, 4(3), pp. 419–420.
+      2. Schubert, E. and Gertz, M., 2018. Numerically stable parallel
+         computation of (co-)variance. ACM. p. 10. doi:10.1145/3221269.3223036.
+      3. Chan, T. F., Golub, G. H., LeVeque, R. J., 1979. Updating formulae and
+         a pairwise algorithm for computing sample variances. Technical Report
+         STAN-CS-79-773, Department of Computer Science, Stanford University.
+      4. Carpenter, B., Gelman, A., Hoffman, M.D., Lee, D., Goodrich, B.,
+         Betancourt, M., Brubaker, M., Guo, J., Li, P. and Riddell, A., 2017.
+         Stan: A probabilistic programming language. Journal of Statistical
+         Software, 76(1).
+    """
+
+    def __init__(self, reg_iter_offset=5, reg_scale=1e-3):
+        """
+        Args:
+            reg_iter_offset (int): Iteration offset used for calculating
+                iteration dependent weighting between regularisation target and
+                current covariance estimate. Higher values cause stronger
+                regularisation during initial iterations.
+            reg_scale (float): Positive scalar defining value variance estimates
+                are regularized towards.
+        """
+        self.reg_iter_offset = reg_iter_offset
+        self.reg_scale = reg_scale
+
+    def initialize(self, chain_state, transition):
+        dim_pos = chain_state.pos.shape[0]
+        dtype = chain_state.pos.dtype
+        return {
+            'iter': 0,
+            'mean': np.zeros(shape=(dim_pos,), dtype=dtype),
+            'sum_diff_outer': np.zeros(shape=(dim_pos, dim_pos), dtype=dtype)
+        }
+
+    def update(self, adapt_state, chain_state, trans_stats, transition):
+        # Use Welford (1962) incremental algorithm to update statistics to
+        # calculate online covariance estimate
+        # https://en.wikipedia.org/wiki/
+        #  Algorithms_for_calculating_variance#Online
+        adapt_state['iter'] += 1
+        pos_minus_mean = chain_state.pos - adapt_state['mean']
+        adapt_state['mean'] += pos_minus_mean / adapt_state['iter']
+        adapt_state['sum_diff_outer'] += pos_minus_mean[None, :] * (
+            chain_state.pos - adapt_state['mean'])[:, None]
+
+    def _regularize_covar_est(self, covar_est, n_iter):
+        """Update covariance estimate by regularising towards identity.
+
+        Performed in place to prevent further array allocations.
+        """
+        covar_est *= (n_iter / (self.reg_iter_offset + n_iter))
+        covar_est_diagonal = np.einsum('ii->i', covar_est)
+        covar_est_diagonal += self.reg_scale * (
+            self.reg_iter_offset / (self.reg_iter_offset + n_iter))
+
+    def finalize(self, adapt_state, transition):
+        if isinstance(adapt_state, dict):
+            n_iter = adapt_state['iter']
+            covar_est = adapt_state.pop('sum_diff_outer')
+        else:
+            # Use Schubert and Gertz (2018) parallel covariance estimation
+            # algorithm to combine per-chain statistics
+            for i, a in enumerate(adapt_state):
+                if i == 0:
+                    n_iter = a['iter']
+                    mean_est = a.pop('mean')
+                    covar_est = a.pop('sum_diff_outer')
+                else:
+                    n_iter_prev = n_iter
+                    n_iter += a['iter']
+                    mean_diff = mean_est - a['mean']
+                    mean_est *= n_iter_prev
+                    mean_est += a['iter'] * a['mean']
+                    mean_est /= n_iter
+                    covar_est += a['sum_diff_outer']
+                    covar_est += np.outer(mean_diff, mean_diff) * (
+                        a['iter'] * n_iter_prev) / n_iter
+        if n_iter < 2:
+            raise AdaptationError(
+                'At least two chain samples required to compute a variance '
+                'estimates.')
+        covar_est /= (n_iter - 1)
+        self._regularize_covar_est(covar_est, n_iter)
+        transition.system.metric = DensePositiveDefiniteMatrix(covar_est).inv
+
+
+
+
+
+
+
+
+
+

Classes

+
+
+class Adapter +(*args, **kwargs) +
+
+

Abstract adapter for implementing schemes to adapt transition parameters.

+

Adaptation schemes are assumed to be based on updating a collection of +adaptation variables (collectively termed the adapter state here) after +each chain transition based on the sampled chain state and/or statistics of +the transition such as an acceptance probability statistic. After completing +a chain of one or more adaptive transitions, the final adapter state may be +used to perform a final update to the transition parameters.

+
+ +Expand source code +Browse git + +
class Adapter(ABC):
+    """Abstract adapter for implementing schemes to adapt transition parameters.
+
+    Adaptation schemes are assumed to be based on updating a collection of
+    adaptation variables (collectively termed the adapter state here) after
+    each chain transition based on the sampled chain state and/or statistics of
+    the transition such as an acceptance probability statistic. After completing
+    a chain of one or more adaptive transitions, the final adapter state may be
+    used to perform a final update to the transition parameters.
+    """
+
+    @abstractmethod
+    def initialize(self, chain_state, transition):
+        """Initialize adapter state prior to starting adaptive transitions.
+
+        Args:
+            chain_state (mici.states.ChainState): Initial chain state adaptive
+                transition will be started from. May be used to calculate
+                initial adapter state but should not be mutated by method.
+            transition (mici.transitions.Transition): Markov transition being
+                adapted. Attributes of the transition or child objects may be
+                updated in-place by the method.
+
+        Returns:
+            adapt_state (Dict[str, Any]): Initial adapter state.
+        """
+
+    @abstractmethod
+    def update(self, adapt_state, chain_state, trans_stats, transition):
+        """Update adapter state after sampling transition being adapted.
+
+        Args:
+            adapt_state (Dict[str, Any]): Current adapter state. Entries will
+                be updated in-place by the method.
+            chain_state (mici.states.ChainState): Current chain state following
+                sampling from transition being adapted. May be used to calculate
+                adapter state updates but should not be mutated by method.
+            trans_stats (Dict[str, numeric]): Dictionary of statistics
+                associated with transition being adapted. May be used to
+                calculate adapter state updates but should not be mutated by
+                method.
+            transition (mici.transitions.Transition): Markov transition being
+                adapted. Attributes of the transition or child objects may be
+                updated in-place by the method.
+        """
+
+    @abstractmethod
+    def finalize(self, adapt_state, transition):
+        """Update transition parameters based on final adapter state or states.
+
+        Optionally, if multiple adapter states are available, e.g. from a set of
+        independent adaptive chains, then these adaptation information from all
+        the chains may be combined to set the transition parameter(s).
+
+        Args:
+            adapt_state (Dict[str, Any] or List[Dict[str, Any]]): Final adapter
+                state or a list of adapter states. Arrays / buffers associated
+                with the adapter state entries may be recycled to reduce memory
+                usage - if so the corresponding entries will be removed from
+                the adapter state dictionary / dictionaries.
+            transition (mici.transitions.Transition): Markov transition being
+                adapted. Attributes of the transition or child objects will be
+                updated in-place by the method.
+        """
+
+

Ancestors

+
    +
  • abc.ABC
  • +
+

Subclasses

+ +

Methods

+
+
+def initialize(self, chain_state, transition) +
+
+

Initialize adapter state prior to starting adaptive transitions.

+

Args

+
+
chain_state : ChainState
+
Initial chain state adaptive +transition will be started from. May be used to calculate +initial adapter state but should not be mutated by method.
+
transition : Transition
+
Markov transition being +adapted. Attributes of the transition or child objects may be +updated in-place by the method.
+
+

Returns

+
+
adapt_state : Dict[str, Any]
+
Initial adapter state.
+
+
+ +Expand source code +Browse git + +
@abstractmethod
+def initialize(self, chain_state, transition):
+    """Initialize adapter state prior to starting adaptive transitions.
+
+    Args:
+        chain_state (mici.states.ChainState): Initial chain state adaptive
+            transition will be started from. May be used to calculate
+            initial adapter state but should not be mutated by method.
+        transition (mici.transitions.Transition): Markov transition being
+            adapted. Attributes of the transition or child objects may be
+            updated in-place by the method.
+
+    Returns:
+        adapt_state (Dict[str, Any]): Initial adapter state.
+    """
+
+
+
+def update(self, adapt_state, chain_state, trans_stats, transition) +
+
+

Update adapter state after sampling transition being adapted.

+

Args

+
+
adapt_state : Dict[str, Any]
+
Current adapter state. Entries will +be updated in-place by the method.
+
chain_state : ChainState
+
Current chain state following +sampling from transition being adapted. May be used to calculate +adapter state updates but should not be mutated by method.
+
trans_stats : Dict[str, numeric]
+
Dictionary of statistics +associated with transition being adapted. May be used to +calculate adapter state updates but should not be mutated by +method.
+
transition : Transition
+
Markov transition being +adapted. Attributes of the transition or child objects may be +updated in-place by the method.
+
+
+ +Expand source code +Browse git + +
@abstractmethod
+def update(self, adapt_state, chain_state, trans_stats, transition):
+    """Update adapter state after sampling transition being adapted.
+
+    Args:
+        adapt_state (Dict[str, Any]): Current adapter state. Entries will
+            be updated in-place by the method.
+        chain_state (mici.states.ChainState): Current chain state following
+            sampling from transition being adapted. May be used to calculate
+            adapter state updates but should not be mutated by method.
+        trans_stats (Dict[str, numeric]): Dictionary of statistics
+            associated with transition being adapted. May be used to
+            calculate adapter state updates but should not be mutated by
+            method.
+        transition (mici.transitions.Transition): Markov transition being
+            adapted. Attributes of the transition or child objects may be
+            updated in-place by the method.
+    """
+
+
+
+def finalize(self, adapt_state, transition) +
+
+

Update transition parameters based on final adapter state or states.

+

Optionally, if multiple adapter states are available, e.g. from a set of +independent adaptive chains, then these adaptation information from all +the chains may be combined to set the transition parameter(s).

+

Args

+
+
adapt_state : Dict[str, Any] or List[Dict[str, Any]]
+
Final adapter +state or a list of adapter states. Arrays / buffers associated +with the adapter state entries may be recycled to reduce memory +usage - if so the corresponding entries will be removed from +the adapter state dictionary / dictionaries.
+
transition : Transition
+
Markov transition being +adapted. Attributes of the transition or child objects will be +updated in-place by the method.
+
+
+ +Expand source code +Browse git + +
@abstractmethod
+def finalize(self, adapt_state, transition):
+    """Update transition parameters based on final adapter state or states.
+
+    Optionally, if multiple adapter states are available, e.g. from a set of
+    independent adaptive chains, then these adaptation information from all
+    the chains may be combined to set the transition parameter(s).
+
+    Args:
+        adapt_state (Dict[str, Any] or List[Dict[str, Any]]): Final adapter
+            state or a list of adapter states. Arrays / buffers associated
+            with the adapter state entries may be recycled to reduce memory
+            usage - if so the corresponding entries will be removed from
+            the adapter state dictionary / dictionaries.
+        transition (mici.transitions.Transition): Markov transition being
+            adapted. Attributes of the transition or child objects will be
+            updated in-place by the method.
+    """
+
+
+
+
+
+class DualAveragingStepSizeAdapter +(adapt_stat_target=0.8, adapt_stat_func=None, log_step_size_reg_target=None, log_step_size_reg_coefficient=0.05, iter_decay_coeff=0.75, iter_offset=10, max_init_step_size_iters=100) +
+
+

Dual averaging integrator step size adapter.

+

Implementation of the dual algorithm step size adaptation algorithm +described in [1], a modified version of the stochastic optimisation scheme +of [2]. By default the adaptation is performed to control the accept_prob +statistic of an integration transition to be close to a target value but +the statistic adapted on can be altered by changing the adapt_stat_func.

+

References

+
    +
  1. Hoffman, M.D. and Gelman, A., 2014. The No-U-turn sampler: +adaptively setting path lengths in Hamiltonian Monte Carlo. +Journal of Machine Learning Research, 15(1), pp.1593-1623.
  2. +
  3. Nesterov, Y., 2009. Primal-dual subgradient methods for convex +problems. Mathematical programming 120(1), pp.221-259.
  4. +
+

Args

+
+
adapt_stat_target : float
+
Target value for the transition statistic +being controlled during adaptation.
+
adapt_stat_func : Callable[[Dict[str, numeric]], numeric]
+
Function +which given a dictionary of transition statistics outputs the +value of the statistic to control during adaptation. By default +this is set to a function which simply selects the 'accept_stat' +value in the statistics dictionary.
+
log_step_size_reg_target : float or None
+
Value to regularize the +controlled output (logarithm of the integrator step size) +towards. If None set to log(10 * init_step_size) where +init_step_size is the initial 'reasonable' step size found by +a coarse search as recommended in Hoffman and Gelman (2014). +This has the effect of giving the dual averaging algorithm a +tendency towards testing step sizes larger than the initial +value, with typically integrating with a larger step size having +a lower computational cost.
+
log_step_size_reg_coefficient : float
+
Coefficient controlling +amount of regularisation of controlled output (logarithm of the +integrator step size) towards log_step_size_reg_target. +Defaults to 0.05 as recommended in Hoffman and Gelman (2014).
+
iter_decay_coeff : float
+
Coefficient controlling exponent of +decay in schedule weighting stochastic updates to smoothed log +step size estimate. Should be in the interval (0.5, 1] to ensure +asymptotic convergence of adaptation. A value of 1 gives equal +weight to the whole history of updates while setting to a +smaller value increasingly highly weights recent updates, giving +a tendency to 'forget' early updates. Defaults to 0.75 as +recommended in Hoffman and Gelman (2014).
+
iter_offset : int
+
Offset used for the iteration based weighting of +the adaptation statistic error estimate. Should be set to a +non-negative value. A value > 0 has the effect of stabilising +early iterations. Defaults to the value of 10 as recommended in +Hoffman and Gelman (2014).
+
max_init_step_size_iters : int
+
Maximum number of iterations to use +in initial search for a reasonable step size with an +AdaptationError exception raised if a suitable step size is +not found within this many iterations.
+
+
+ +Expand source code +Browse git + +
class DualAveragingStepSizeAdapter(Adapter):
+    """Dual averaging integrator step size adapter.
+
+    Implementation of the dual algorithm step size adaptation algorithm
+    described in [1], a modified version of the stochastic optimisation scheme
+    of [2]. By default the adaptation is performed to control the `accept_prob`
+    statistic of an integration transition to be close to a target value but
+    the statistic adapted on can be altered by changing the `adapt_stat_func`.
+
+
+    References:
+
+      1. Hoffman, M.D. and Gelman, A., 2014. The No-U-turn sampler:
+         adaptively setting path lengths in Hamiltonian Monte Carlo.
+         Journal of Machine Learning Research, 15(1), pp.1593-1623.
+      2. Nesterov, Y., 2009. Primal-dual subgradient methods for convex
+         problems. Mathematical programming 120(1), pp.221-259.
+    """
+
+    def __init__(self, adapt_stat_target=0.8, adapt_stat_func=None,
+                 log_step_size_reg_target=None,
+                 log_step_size_reg_coefficient=0.05, iter_decay_coeff=0.75,
+                 iter_offset=10, max_init_step_size_iters=100):
+        """
+        Args:
+            adapt_stat_target (float): Target value for the transition statistic
+                being controlled during adaptation.
+            adapt_stat_func (Callable[[Dict[str, numeric]], numeric]): Function
+                which given a dictionary of transition statistics outputs the
+                value of the statistic to control during adaptation. By default
+                this is set to a function which simply selects the 'accept_stat'
+                value in the statistics dictionary.
+            log_step_size_reg_target (float or None): Value to regularize the
+                controlled output (logarithm of the integrator step size)
+                towards. If `None` set to `log(10 * init_step_size)` where
+                `init_step_size` is the initial 'reasonable' step size found by
+                a coarse search as recommended in Hoffman and Gelman (2014).
+                This has the effect of giving the dual averaging algorithm a
+                tendency towards testing step sizes larger than the initial
+                value, with typically integrating with a larger step size having
+                a lower computational cost.
+            log_step_size_reg_coefficient (float): Coefficient controlling
+                amount of regularisation of controlled output (logarithm of the
+                integrator step size) towards `log_step_size_reg_target`.
+                Defaults to 0.05 as recommended in Hoffman and Gelman (2014).
+            iter_decay_coeff (float): Coefficient controlling exponent of
+                decay in schedule weighting stochastic updates to smoothed log
+                step size estimate. Should be in the interval (0.5, 1] to ensure
+                asymptotic convergence of adaptation. A value of 1 gives equal
+                weight to the whole history of updates while setting to a
+                smaller value increasingly highly weights recent updates, giving
+                a tendency to 'forget' early updates. Defaults to 0.75 as
+                recommended in Hoffman and Gelman (2014).
+            iter_offset (int): Offset used for the iteration based weighting of
+                the adaptation statistic error estimate. Should be set to a
+                non-negative value. A value > 0 has the effect of stabilising
+                early iterations. Defaults to the value of 10 as recommended in
+                Hoffman and Gelman (2014).
+            max_init_step_size_iters (int): Maximum number of iterations to use
+                in initial search for a reasonable step size with an
+                `AdaptationError` exception raised if a suitable step size is
+                not found within this many iterations.
+        """
+        self.adapt_stat_target = adapt_stat_target
+        if adapt_stat_func is None:
+            def adapt_stat_func(stats): return stats['accept_stat']
+        self.adapt_stat_func = adapt_stat_func
+        self.log_step_size_reg_target = log_step_size_reg_target
+        self.log_step_size_reg_coefficient = log_step_size_reg_coefficient
+        self.iter_decay_coeff = iter_decay_coeff
+        self.iter_offset = iter_offset
+        self.max_init_step_size_iters = max_init_step_size_iters
+
+    def initialize(self, chain_state, transition):
+        integrator = transition.integrator
+        system = transition.system
+        adapt_state = {
+            'iter': 0,
+            'smoothed_log_step_size': 0.,
+            'adapt_stat_error': 0.,
+        }
+        init_step_size = (self._find_and_set_init_step_size(
+            chain_state, system, integrator) if integrator.step_size is None
+            else integrator.step_size)
+        if self.log_step_size_reg_target is None:
+            adapt_state['log_step_size_reg_target'] = log(10 * init_step_size)
+        else:
+            adapt_state['log_step_size_reg_target'] = (
+                self.log_step_size_reg_target)
+        return adapt_state
+
+    def _find_and_set_init_step_size(self, state, system, integrator):
+        """Find initial step size by coarse search using single step statistics.
+
+        Adaptation of Algorithm 4 in Hoffman and Gelman (2014).
+
+        Compared to the Hoffman and Gelman algorithm, this version makes two
+        changes:
+
+          1. The absolute value of the change in Hamiltonian over a step being
+             larger or smaller than log(2) is used to determine whether the step
+             size is too big or small as opposed to the value of the equivalent
+             Metropolis accept probability being larger or smaller than 0.5.
+             Although a negative change in the Hamiltonian over a step of
+             magnitude more than log(2) will lead to an accept probability of 1
+             for the forward move, the corresponding reversed move will have an
+             accept probability less than 0.5, and so a change in the
+             Hamiltonian over a step of magnitude more than log(2) irrespective
+             of the sign of the change is indicative of the minimum acceptance
+             probability over both forward and reversed steps being less than
+             0.5.
+          2. To allow for integrators for which an integrator step may fail due
+             to e.g. a convergence error in an iterative solver, the step size
+             is also considered to be too big if any of the step sizes tried in
+             the search result in a failed integrator step, with in this case
+             the step size always being decreased on subsequent steps
+             irrespective of the initial Hamiltonian error, until a integrator
+             step successfully completes and the absolute value of the change in
+             Hamiltonian is below the threshold of log(2) (corresponding to a
+             minimum acceptance probability over forward and reversed steps of
+             0.5).
+        """
+        init_state = state.copy()
+        h_init = system.h(init_state)
+        integrator.step_size = 1
+        delta_h_threshold = log(2)
+        for s in range(self.max_init_step_size_iters):
+            try:
+                state = integrator.step(init_state)
+                delta_h = abs(h_init - system.h(state))
+                if s == 0:
+                    step_size_too_big = delta_h > delta_h_threshold
+                if (step_size_too_big and delta_h <= delta_h_threshold) or (
+                        not step_size_too_big and delta_h > delta_h_threshold):
+                    return integrator.step_size
+                elif step_size_too_big:
+                    integrator.step_size /= 2
+                else:
+                    integrator.step_size *= 2
+            except IntegratorError:
+                step_size_too_big = True
+                integrator.step_size /= 2
+        raise AdaptationError(
+            f'Could not find reasonable initial step size in '
+            f'{self.max_init_step_size_iters} iterations (final step size '
+            f'{integrator.step_size}). A very large final step size may '
+            f'indicate that the target distribution is improper such that the '
+            f'negative log density is flat in one or more directions while a '
+            f'very small final step size may indicate that the density function'
+            f' is insufficiently smooth at the point initialized at.')
+
+    def update(self, adapt_state, chain_state, trans_stats, transition):
+        adapt_state['iter'] += 1
+        error_weight = 1 / (self.iter_offset + adapt_state['iter'])
+        adapt_state['adapt_stat_error'] *= (1 - error_weight)
+        adapt_state['adapt_stat_error'] += error_weight * (
+            self.adapt_stat_target - self.adapt_stat_func(trans_stats))
+        smoothing_weight = (1 / adapt_state['iter'])**self.iter_decay_coeff
+        log_step_size = adapt_state['log_step_size_reg_target'] - (
+            adapt_state['adapt_stat_error'] * adapt_state['iter']**0.5 /
+            self.log_step_size_reg_coefficient)
+        adapt_state['smoothed_log_step_size'] *= (1 - smoothing_weight)
+        adapt_state['smoothed_log_step_size'] += (
+            smoothing_weight * log_step_size)
+        transition.integrator.step_size = exp(log_step_size)
+
+    def finalize(self, adapt_state, transition):
+        if isinstance(adapt_state, dict):
+            transition.integrator.step_size = exp(
+                adapt_state['smoothed_log_step_size'])
+        else:
+            transition.integrator.step_size = sum(
+                exp(a['smoothed_log_step_size'])
+                for a in adapt_state) / len(adapt_state)
+
+

Ancestors

+ +

Methods

+
+
+def initialize(self, chain_state, transition) +
+
+

Initialize adapter state prior to starting adaptive transitions.

+

Args

+
+
chain_state : ChainState
+
Initial chain state adaptive +transition will be started from. May be used to calculate +initial adapter state but should not be mutated by method.
+
transition : Transition
+
Markov transition being +adapted. Attributes of the transition or child objects may be +updated in-place by the method.
+
+

Returns

+
+
adapt_state : Dict[str, Any]
+
Initial adapter state.
+
+
+ +Expand source code +Browse git + +
def initialize(self, chain_state, transition):
+    integrator = transition.integrator
+    system = transition.system
+    adapt_state = {
+        'iter': 0,
+        'smoothed_log_step_size': 0.,
+        'adapt_stat_error': 0.,
+    }
+    init_step_size = (self._find_and_set_init_step_size(
+        chain_state, system, integrator) if integrator.step_size is None
+        else integrator.step_size)
+    if self.log_step_size_reg_target is None:
+        adapt_state['log_step_size_reg_target'] = log(10 * init_step_size)
+    else:
+        adapt_state['log_step_size_reg_target'] = (
+            self.log_step_size_reg_target)
+    return adapt_state
+
+
+
+def update(self, adapt_state, chain_state, trans_stats, transition) +
+
+

Update adapter state after sampling transition being adapted.

+

Args

+
+
adapt_state : Dict[str, Any]
+
Current adapter state. Entries will +be updated in-place by the method.
+
chain_state : ChainState
+
Current chain state following +sampling from transition being adapted. May be used to calculate +adapter state updates but should not be mutated by method.
+
trans_stats : Dict[str, numeric]
+
Dictionary of statistics +associated with transition being adapted. May be used to +calculate adapter state updates but should not be mutated by +method.
+
transition : Transition
+
Markov transition being +adapted. Attributes of the transition or child objects may be +updated in-place by the method.
+
+
+ +Expand source code +Browse git + +
def update(self, adapt_state, chain_state, trans_stats, transition):
+    adapt_state['iter'] += 1
+    error_weight = 1 / (self.iter_offset + adapt_state['iter'])
+    adapt_state['adapt_stat_error'] *= (1 - error_weight)
+    adapt_state['adapt_stat_error'] += error_weight * (
+        self.adapt_stat_target - self.adapt_stat_func(trans_stats))
+    smoothing_weight = (1 / adapt_state['iter'])**self.iter_decay_coeff
+    log_step_size = adapt_state['log_step_size_reg_target'] - (
+        adapt_state['adapt_stat_error'] * adapt_state['iter']**0.5 /
+        self.log_step_size_reg_coefficient)
+    adapt_state['smoothed_log_step_size'] *= (1 - smoothing_weight)
+    adapt_state['smoothed_log_step_size'] += (
+        smoothing_weight * log_step_size)
+    transition.integrator.step_size = exp(log_step_size)
+
+
+
+def finalize(self, adapt_state, transition) +
+
+

Update transition parameters based on final adapter state or states.

+

Optionally, if multiple adapter states are available, e.g. from a set of +independent adaptive chains, then these adaptation information from all +the chains may be combined to set the transition parameter(s).

+

Args

+
+
adapt_state : Dict[str, Any] or List[Dict[str, Any]]
+
Final adapter +state or a list of adapter states. Arrays / buffers associated +with the adapter state entries may be recycled to reduce memory +usage - if so the corresponding entries will be removed from +the adapter state dictionary / dictionaries.
+
transition : Transition
+
Markov transition being +adapted. Attributes of the transition or child objects will be +updated in-place by the method.
+
+
+ +Expand source code +Browse git + +
def finalize(self, adapt_state, transition):
+    if isinstance(adapt_state, dict):
+        transition.integrator.step_size = exp(
+            adapt_state['smoothed_log_step_size'])
+    else:
+        transition.integrator.step_size = sum(
+            exp(a['smoothed_log_step_size'])
+            for a in adapt_state) / len(adapt_state)
+
+
+
+
+
+class OnlineVarianceMetricAdapter +(reg_iter_offset=5, reg_scale=0.001) +
+
+

Diagonal metric adapter using online variance estimates.

+

Uses Welford's algorithm [1] to stably compute an online estimate of the +sample variances of the chain state position components during sampling. If +online estimates are available from multiple independent chains, the final +variance estimate is calculated from the per-chain statistics using the +parallel / batched incremental variance algorithm described by Chan et al. +[2]. The variance estimates are optionally regularized towards a common +scalar value, with increasing weight for small number of samples, to +decrease the effect of noisy estimates for small sample sizes, following the +approach in Stan [3]. The metric matrix representation is set to a diagonal +matrix with diagonal elements corresponding to the reciprocal of the +(regularized) variance estimates.

+

References

+
    +
  1. Welford, B. P., 1962. Note on a method for calculating corrected sums +of squares and products. Technometrics, 4(3), pp. 419–420.
  2. +
  3. Chan, T. F., Golub, G. H., LeVeque, R. J., 1979. Updating formulae and +a pairwise algorithm for computing sample variances. Technical Report +STAN-CS-79-773, Department of Computer Science, Stanford University.
  4. +
  5. Carpenter, B., Gelman, A., Hoffman, M.D., Lee, D., Goodrich, B., +Betancourt, M., Brubaker, M., Guo, J., Li, P. and Riddell, A., 2017. +Stan: A probabilistic programming language. Journal of Statistical +Software, 76(1).
  6. +
+

Args

+
+
reg_iter_offset : int
+
Iteration offset used for calculating +iteration dependent weighting between regularisation target and +current covariance estimate. Higher values cause stronger +regularisation during initial iterations. A value of zero +corresponds to no regularisation; this should only be used if +the sample covariance is guaranteed to be positive definite.
+
reg_scale : float
+
Positive scalar defining value variance estimates +are regularized towards.
+
+
+ +Expand source code +Browse git + +
class OnlineVarianceMetricAdapter(Adapter):
+    """Diagonal metric adapter using online variance estimates.
+
+    Uses Welford's algorithm [1] to stably compute an online estimate of the
+    sample variances of the chain state position components during sampling. If
+    online estimates are available from multiple independent chains, the final
+    variance estimate is calculated from the per-chain statistics using the
+    parallel / batched incremental variance algorithm described by Chan et al.
+    [2]. The variance estimates are optionally regularized towards a common
+    scalar value, with increasing weight for small number of samples, to
+    decrease the effect of noisy estimates for small sample sizes, following the
+    approach in Stan [3]. The metric matrix representation is set to a diagonal
+    matrix with diagonal elements corresponding to the reciprocal of the
+    (regularized) variance estimates.
+
+    References:
+
+      1. Welford, B. P., 1962. Note on a method for calculating corrected sums
+         of squares and products. Technometrics, 4(3), pp. 419–420.
+      2. Chan, T. F., Golub, G. H., LeVeque, R. J., 1979. Updating formulae and
+         a pairwise algorithm for computing sample variances. Technical Report
+         STAN-CS-79-773, Department of Computer Science, Stanford University.
+      3. Carpenter, B., Gelman, A., Hoffman, M.D., Lee, D., Goodrich, B.,
+         Betancourt, M., Brubaker, M., Guo, J., Li, P. and Riddell, A., 2017.
+         Stan: A probabilistic programming language. Journal of Statistical
+         Software, 76(1).
+    """
+
+    def __init__(self, reg_iter_offset=5, reg_scale=1e-3):
+        """
+        Args:
+            reg_iter_offset (int): Iteration offset used for calculating
+                iteration dependent weighting between regularisation target and
+                current covariance estimate. Higher values cause stronger
+                regularisation during initial iterations. A value of zero
+                corresponds to no regularisation; this should only be used if
+                the sample covariance is guaranteed to be positive definite.
+            reg_scale (float): Positive scalar defining value variance estimates
+                are regularized towards.
+        """
+        self.reg_iter_offset = reg_iter_offset
+        self.reg_scale = reg_scale
+
+    def initialize(self, chain_state, transition):
+        return {
+            'iter': 0,
+            'mean': np.zeros_like(chain_state.pos),
+            'sum_diff_sq': np.zeros_like(chain_state.pos)
+        }
+
+    def update(self, adapt_state, chain_state, trans_stats, transition):
+        # Use Welford (1962) incremental algorithm to update statistics to
+        # calculate online variance estimate
+        # https://en.wikipedia.org/wiki/
+        #   Algorithms_for_calculating_variance#Welford's_online_algorithm
+        adapt_state['iter'] += 1
+        pos_minus_mean = chain_state.pos - adapt_state['mean']
+        adapt_state['mean'] += pos_minus_mean / adapt_state['iter']
+        adapt_state['sum_diff_sq'] += pos_minus_mean * (
+            chain_state.pos - adapt_state['mean'])
+
+    def _regularize_var_est(self, var_est, n_iter):
+        """Update variance estimates by regularizing towards common scalar.
+
+        Performed in place to prevent further array allocations.
+        """
+        if self.reg_iter_offset is not None and self.reg_iter_offset != 0:
+            var_est *= n_iter / (self.reg_iter_offset + n_iter)
+            var_est += self.reg_scale * (
+                self.reg_iter_offset / (self.reg_iter_offset + n_iter))
+
+    def finalize(self, adapt_state, transition):
+        if isinstance(adapt_state, dict):
+            n_iter = adapt_state['iter']
+            var_est = adapt_state.pop('sum_diff_sq')
+        else:
+            # Use Chan et al. (1979) parallel variance estimation algorithm
+            # to combine per-chain statistics
+            # https://en.wikipedia.org/wiki/
+            #    Algorithms_for_calculating_variance#Parallel_algorithm
+            for i, a in enumerate(adapt_state):
+                if i == 0:
+                    n_iter = a['iter']
+                    mean_est = a.pop('mean')
+                    var_est = a.pop('sum_diff_sq')
+                else:
+                    n_iter_prev = n_iter
+                    n_iter += a['iter']
+                    mean_diff = mean_est - a['mean']
+                    mean_est *= n_iter_prev
+                    mean_est += a['iter'] * a['mean']
+                    mean_est /= n_iter
+                    var_est += a['sum_diff_sq']
+                    var_est += mean_diff**2 * (a['iter'] * n_iter_prev) / n_iter
+        if n_iter < 2:
+            raise AdaptationError(
+                'At least two chain samples required to compute a variance '
+                'estimates.')
+        var_est /= (n_iter - 1)
+        self._regularize_var_est(var_est, n_iter)
+        transition.system.metric = PositiveDiagonalMatrix(var_est).inv
+
+

Ancestors

+ +

Methods

+
+
+def initialize(self, chain_state, transition) +
+
+

Initialize adapter state prior to starting adaptive transitions.

+

Args

+
+
chain_state : ChainState
+
Initial chain state adaptive +transition will be started from. May be used to calculate +initial adapter state but should not be mutated by method.
+
transition : Transition
+
Markov transition being +adapted. Attributes of the transition or child objects may be +updated in-place by the method.
+
+

Returns

+
+
adapt_state : Dict[str, Any]
+
Initial adapter state.
+
+
+ +Expand source code +Browse git + +
def initialize(self, chain_state, transition):
+    return {
+        'iter': 0,
+        'mean': np.zeros_like(chain_state.pos),
+        'sum_diff_sq': np.zeros_like(chain_state.pos)
+    }
+
+
+
+def update(self, adapt_state, chain_state, trans_stats, transition) +
+
+

Update adapter state after sampling transition being adapted.

+

Args

+
+
adapt_state : Dict[str, Any]
+
Current adapter state. Entries will +be updated in-place by the method.
+
chain_state : ChainState
+
Current chain state following +sampling from transition being adapted. May be used to calculate +adapter state updates but should not be mutated by method.
+
trans_stats : Dict[str, numeric]
+
Dictionary of statistics +associated with transition being adapted. May be used to +calculate adapter state updates but should not be mutated by +method.
+
transition : Transition
+
Markov transition being +adapted. Attributes of the transition or child objects may be +updated in-place by the method.
+
+
+ +Expand source code +Browse git + +
def update(self, adapt_state, chain_state, trans_stats, transition):
+    # Use Welford (1962) incremental algorithm to update statistics to
+    # calculate online variance estimate
+    # https://en.wikipedia.org/wiki/
+    #   Algorithms_for_calculating_variance#Welford's_online_algorithm
+    adapt_state['iter'] += 1
+    pos_minus_mean = chain_state.pos - adapt_state['mean']
+    adapt_state['mean'] += pos_minus_mean / adapt_state['iter']
+    adapt_state['sum_diff_sq'] += pos_minus_mean * (
+        chain_state.pos - adapt_state['mean'])
+
+
+
+def finalize(self, adapt_state, transition) +
+
+

Update transition parameters based on final adapter state or states.

+

Optionally, if multiple adapter states are available, e.g. from a set of +independent adaptive chains, then these adaptation information from all +the chains may be combined to set the transition parameter(s).

+

Args

+
+
adapt_state : Dict[str, Any] or List[Dict[str, Any]]
+
Final adapter +state or a list of adapter states. Arrays / buffers associated +with the adapter state entries may be recycled to reduce memory +usage - if so the corresponding entries will be removed from +the adapter state dictionary / dictionaries.
+
transition : Transition
+
Markov transition being +adapted. Attributes of the transition or child objects will be +updated in-place by the method.
+
+
+ +Expand source code +Browse git + +
def finalize(self, adapt_state, transition):
+    if isinstance(adapt_state, dict):
+        n_iter = adapt_state['iter']
+        var_est = adapt_state.pop('sum_diff_sq')
+    else:
+        # Use Chan et al. (1979) parallel variance estimation algorithm
+        # to combine per-chain statistics
+        # https://en.wikipedia.org/wiki/
+        #    Algorithms_for_calculating_variance#Parallel_algorithm
+        for i, a in enumerate(adapt_state):
+            if i == 0:
+                n_iter = a['iter']
+                mean_est = a.pop('mean')
+                var_est = a.pop('sum_diff_sq')
+            else:
+                n_iter_prev = n_iter
+                n_iter += a['iter']
+                mean_diff = mean_est - a['mean']
+                mean_est *= n_iter_prev
+                mean_est += a['iter'] * a['mean']
+                mean_est /= n_iter
+                var_est += a['sum_diff_sq']
+                var_est += mean_diff**2 * (a['iter'] * n_iter_prev) / n_iter
+    if n_iter < 2:
+        raise AdaptationError(
+            'At least two chain samples required to compute a variance '
+            'estimates.')
+    var_est /= (n_iter - 1)
+    self._regularize_var_est(var_est, n_iter)
+    transition.system.metric = PositiveDiagonalMatrix(var_est).inv
+
+
+
+
+
+class OnlineCovarianceMetricAdapter +(reg_iter_offset=5, reg_scale=0.001) +
+
+

Dense metric adapter using online covariance estimates.

+

Uses Welford's algorithm [1] to stably compute an online estimate of the +sample covariane matrix of the chain state position components during +sampling. If online estimates are available from multiple independent +chains, the final covariance matrix estimate is calculated from the +per-chain statistics using a covariance variant due to Schubert and Gertz +[2] of the parallel / batched incremental variance algorithm described by +Chan et al. [3]. The covariance matrix estimates are optionally regularized +towards a scaled identity matrix, with increasing weight for small number of +samples, to decrease the effect of noisy estimates for small sample sizes, +following the approach in Stan [4]. The metric matrix representation is set +to a dense positive definite matrix corresponding to the inverse of the +(regularized) covariance matrix estimate.

+

References

+
    +
  1. Welford, B. P., 1962. Note on a method for calculating corrected sums +of squares and products. Technometrics, 4(3), pp. 419–420.
  2. +
  3. Schubert, E. and Gertz, M., 2018. Numerically stable parallel +computation of (co-)variance. ACM. p. 10. doi:10.1145/3221269.3223036.
  4. +
  5. Chan, T. F., Golub, G. H., LeVeque, R. J., 1979. Updating formulae and +a pairwise algorithm for computing sample variances. Technical Report +STAN-CS-79-773, Department of Computer Science, Stanford University.
  6. +
  7. Carpenter, B., Gelman, A., Hoffman, M.D., Lee, D., Goodrich, B., +Betancourt, M., Brubaker, M., Guo, J., Li, P. and Riddell, A., 2017. +Stan: A probabilistic programming language. Journal of Statistical +Software, 76(1).
  8. +
+

Args

+
+
reg_iter_offset : int
+
Iteration offset used for calculating +iteration dependent weighting between regularisation target and +current covariance estimate. Higher values cause stronger +regularisation during initial iterations.
+
reg_scale : float
+
Positive scalar defining value variance estimates +are regularized towards.
+
+
+ +Expand source code +Browse git + +
class OnlineCovarianceMetricAdapter(Adapter):
+    """Dense metric adapter using online covariance estimates.
+
+    Uses Welford's algorithm [1] to stably compute an online estimate of the
+    sample covariane matrix of the chain state position components during
+    sampling. If online estimates are available from multiple independent
+    chains, the final covariance matrix estimate is calculated from the
+    per-chain statistics using a covariance variant due to Schubert and Gertz
+    [2] of the parallel / batched incremental variance algorithm described by
+    Chan et al. [3]. The covariance matrix estimates are optionally regularized
+    towards a scaled identity matrix, with increasing weight for small number of
+    samples, to decrease the effect of noisy estimates for small sample sizes,
+    following the approach in Stan [4]. The metric matrix representation is set
+    to a dense positive definite matrix corresponding to the inverse of the
+    (regularized) covariance matrix estimate.
+
+
+    References:
+
+      1. Welford, B. P., 1962. Note on a method for calculating corrected sums
+         of squares and products. Technometrics, 4(3), pp. 419–420.
+      2. Schubert, E. and Gertz, M., 2018. Numerically stable parallel
+         computation of (co-)variance. ACM. p. 10. doi:10.1145/3221269.3223036.
+      3. Chan, T. F., Golub, G. H., LeVeque, R. J., 1979. Updating formulae and
+         a pairwise algorithm for computing sample variances. Technical Report
+         STAN-CS-79-773, Department of Computer Science, Stanford University.
+      4. Carpenter, B., Gelman, A., Hoffman, M.D., Lee, D., Goodrich, B.,
+         Betancourt, M., Brubaker, M., Guo, J., Li, P. and Riddell, A., 2017.
+         Stan: A probabilistic programming language. Journal of Statistical
+         Software, 76(1).
+    """
+
+    def __init__(self, reg_iter_offset=5, reg_scale=1e-3):
+        """
+        Args:
+            reg_iter_offset (int): Iteration offset used for calculating
+                iteration dependent weighting between regularisation target and
+                current covariance estimate. Higher values cause stronger
+                regularisation during initial iterations.
+            reg_scale (float): Positive scalar defining value variance estimates
+                are regularized towards.
+        """
+        self.reg_iter_offset = reg_iter_offset
+        self.reg_scale = reg_scale
+
+    def initialize(self, chain_state, transition):
+        dim_pos = chain_state.pos.shape[0]
+        dtype = chain_state.pos.dtype
+        return {
+            'iter': 0,
+            'mean': np.zeros(shape=(dim_pos,), dtype=dtype),
+            'sum_diff_outer': np.zeros(shape=(dim_pos, dim_pos), dtype=dtype)
+        }
+
+    def update(self, adapt_state, chain_state, trans_stats, transition):
+        # Use Welford (1962) incremental algorithm to update statistics to
+        # calculate online covariance estimate
+        # https://en.wikipedia.org/wiki/
+        #  Algorithms_for_calculating_variance#Online
+        adapt_state['iter'] += 1
+        pos_minus_mean = chain_state.pos - adapt_state['mean']
+        adapt_state['mean'] += pos_minus_mean / adapt_state['iter']
+        adapt_state['sum_diff_outer'] += pos_minus_mean[None, :] * (
+            chain_state.pos - adapt_state['mean'])[:, None]
+
+    def _regularize_covar_est(self, covar_est, n_iter):
+        """Update covariance estimate by regularising towards identity.
+
+        Performed in place to prevent further array allocations.
+        """
+        covar_est *= (n_iter / (self.reg_iter_offset + n_iter))
+        covar_est_diagonal = np.einsum('ii->i', covar_est)
+        covar_est_diagonal += self.reg_scale * (
+            self.reg_iter_offset / (self.reg_iter_offset + n_iter))
+
+    def finalize(self, adapt_state, transition):
+        if isinstance(adapt_state, dict):
+            n_iter = adapt_state['iter']
+            covar_est = adapt_state.pop('sum_diff_outer')
+        else:
+            # Use Schubert and Gertz (2018) parallel covariance estimation
+            # algorithm to combine per-chain statistics
+            for i, a in enumerate(adapt_state):
+                if i == 0:
+                    n_iter = a['iter']
+                    mean_est = a.pop('mean')
+                    covar_est = a.pop('sum_diff_outer')
+                else:
+                    n_iter_prev = n_iter
+                    n_iter += a['iter']
+                    mean_diff = mean_est - a['mean']
+                    mean_est *= n_iter_prev
+                    mean_est += a['iter'] * a['mean']
+                    mean_est /= n_iter
+                    covar_est += a['sum_diff_outer']
+                    covar_est += np.outer(mean_diff, mean_diff) * (
+                        a['iter'] * n_iter_prev) / n_iter
+        if n_iter < 2:
+            raise AdaptationError(
+                'At least two chain samples required to compute a variance '
+                'estimates.')
+        covar_est /= (n_iter - 1)
+        self._regularize_covar_est(covar_est, n_iter)
+        transition.system.metric = DensePositiveDefiniteMatrix(covar_est).inv
+
+

Ancestors

+ +

Methods

+
+
+def initialize(self, chain_state, transition) +
+
+

Initialize adapter state prior to starting adaptive transitions.

+

Args

+
+
chain_state : ChainState
+
Initial chain state adaptive +transition will be started from. May be used to calculate +initial adapter state but should not be mutated by method.
+
transition : Transition
+
Markov transition being +adapted. Attributes of the transition or child objects may be +updated in-place by the method.
+
+

Returns

+
+
adapt_state : Dict[str, Any]
+
Initial adapter state.
+
+
+ +Expand source code +Browse git + +
def initialize(self, chain_state, transition):
+    dim_pos = chain_state.pos.shape[0]
+    dtype = chain_state.pos.dtype
+    return {
+        'iter': 0,
+        'mean': np.zeros(shape=(dim_pos,), dtype=dtype),
+        'sum_diff_outer': np.zeros(shape=(dim_pos, dim_pos), dtype=dtype)
+    }
+
+
+
+def update(self, adapt_state, chain_state, trans_stats, transition) +
+
+

Update adapter state after sampling transition being adapted.

+

Args

+
+
adapt_state : Dict[str, Any]
+
Current adapter state. Entries will +be updated in-place by the method.
+
chain_state : ChainState
+
Current chain state following +sampling from transition being adapted. May be used to calculate +adapter state updates but should not be mutated by method.
+
trans_stats : Dict[str, numeric]
+
Dictionary of statistics +associated with transition being adapted. May be used to +calculate adapter state updates but should not be mutated by +method.
+
transition : Transition
+
Markov transition being +adapted. Attributes of the transition or child objects may be +updated in-place by the method.
+
+
+ +Expand source code +Browse git + +
def update(self, adapt_state, chain_state, trans_stats, transition):
+    # Use Welford (1962) incremental algorithm to update statistics to
+    # calculate online covariance estimate
+    # https://en.wikipedia.org/wiki/
+    #  Algorithms_for_calculating_variance#Online
+    adapt_state['iter'] += 1
+    pos_minus_mean = chain_state.pos - adapt_state['mean']
+    adapt_state['mean'] += pos_minus_mean / adapt_state['iter']
+    adapt_state['sum_diff_outer'] += pos_minus_mean[None, :] * (
+        chain_state.pos - adapt_state['mean'])[:, None]
+
+
+
+def finalize(self, adapt_state, transition) +
+
+

Update transition parameters based on final adapter state or states.

+

Optionally, if multiple adapter states are available, e.g. from a set of +independent adaptive chains, then these adaptation information from all +the chains may be combined to set the transition parameter(s).

+

Args

+
+
adapt_state : Dict[str, Any] or List[Dict[str, Any]]
+
Final adapter +state or a list of adapter states. Arrays / buffers associated +with the adapter state entries may be recycled to reduce memory +usage - if so the corresponding entries will be removed from +the adapter state dictionary / dictionaries.
+
transition : Transition
+
Markov transition being +adapted. Attributes of the transition or child objects will be +updated in-place by the method.
+
+
+ +Expand source code +Browse git + +
def finalize(self, adapt_state, transition):
+    if isinstance(adapt_state, dict):
+        n_iter = adapt_state['iter']
+        covar_est = adapt_state.pop('sum_diff_outer')
+    else:
+        # Use Schubert and Gertz (2018) parallel covariance estimation
+        # algorithm to combine per-chain statistics
+        for i, a in enumerate(adapt_state):
+            if i == 0:
+                n_iter = a['iter']
+                mean_est = a.pop('mean')
+                covar_est = a.pop('sum_diff_outer')
+            else:
+                n_iter_prev = n_iter
+                n_iter += a['iter']
+                mean_diff = mean_est - a['mean']
+                mean_est *= n_iter_prev
+                mean_est += a['iter'] * a['mean']
+                mean_est /= n_iter
+                covar_est += a['sum_diff_outer']
+                covar_est += np.outer(mean_diff, mean_diff) * (
+                    a['iter'] * n_iter_prev) / n_iter
+    if n_iter < 2:
+        raise AdaptationError(
+            'At least two chain samples required to compute a variance '
+            'estimates.')
+    covar_est /= (n_iter - 1)
+    self._regularize_covar_est(covar_est, n_iter)
+    transition.system.metric = DensePositiveDefiniteMatrix(covar_est).inv
+
+
+
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/docs/docs/autodiff.html b/docs/docs/autodiff.html index 42da10d..e122bde 100644 --- a/docs/docs/autodiff.html +++ b/docs/docs/autodiff.html @@ -3,14 +3,14 @@ - + mici.autodiff API documentation - + @@ -40,14 +40,14 @@
-

Package mici.autodiff

+

Module mici.autodiff

Automatic differentation fallback for constructing derivative functions.

Expand source code -Browse git +Browse git
"""Automatic differentation fallback for constructing derivative functions."""
 
@@ -148,7 +148,7 @@ 

Returns

Expand source code -Browse git +Browse git
def autodiff_fallback(diff_func, func, diff_op_name, name):
     """Generate derivative function automatically if not provided.
@@ -190,7 +190,7 @@ 

Returns

diff --git a/docs/docs/autograd_wrapper.html b/docs/docs/autograd_wrapper.html index a7e6d50..c0810ba 100644 --- a/docs/docs/autograd_wrapper.html +++ b/docs/docs/autograd_wrapper.html @@ -3,14 +3,14 @@ - + mici.autograd_wrapper API documentation - + @@ -44,14 +44,14 @@
-

Package mici.autograd_wrapper

+

Module mici.autograd_wrapper

Additional autograd differential operators.

Expand source code -Browse git +Browse git
"""Additional autograd differential operators."""
 
@@ -195,7 +195,7 @@ 

Functions

Expand source code -Browse git +Browse git
@_wrapped_unary_to_nary
 def grad_and_value(fun, x):
@@ -220,7 +220,7 @@ 

Functions

Expand source code -Browse git +Browse git
@_wrapped_unary_to_nary
 def jacobian_and_value(fun, x):
@@ -262,7 +262,7 @@ 

Functions

Expand source code -Browse git +Browse git
@_wrapped_unary_to_nary
 def mhp_jacobian_and_value(fun, x):
@@ -300,7 +300,7 @@ 

Functions

Expand source code -Browse git +Browse git
@_wrapped_unary_to_nary
 def hessian_grad_and_value(fun, x):
@@ -342,7 +342,7 @@ 

Functions

Expand source code -Browse git +Browse git
@_wrapped_unary_to_nary
 def mtp_hessian_grad_and_value(fun, x):
@@ -378,7 +378,7 @@ 

Functions

diff --git a/docs/docs/errors.html b/docs/docs/errors.html index 1a2df87..0d4488c 100644 --- a/docs/docs/errors.html +++ b/docs/docs/errors.html @@ -3,14 +3,14 @@ - + mici.errors API documentation - + @@ -34,22 +34,28 @@
  • Classes

  • @@ -57,14 +63,14 @@

    -

    Package mici.errors

    +

    Module mici.errors

    Exception types.

    Expand source code -Browse git +Browse git
    """Exception types."""
     
    @@ -89,8 +95,16 @@ 

    Package mici.errors

    """Error raised when a matrix operation raises a linear algebra error.""" -class HamiltonianDivergenceError(Error): - """Error raised when integration of Hamiltonian dynamics diverges."""
    +class HamiltonianDivergenceError(IntegratorError): + """Error raised when integration of Hamiltonian dynamics diverges.""" + + +class AdaptationError(Error): + """Error raised when adaptation of transition parameters fails.""" + + +class ReadOnlyStateError(Error): + """Error raised when writing to attributes of read-only chain state."""

    @@ -111,7 +125,7 @@

    Classes

    Expand source code -Browse git +Browse git
    class Error(RuntimeError):
         """Base class for errors."""
    @@ -126,7 +140,8 @@

    Subclasses

    @@ -138,7 +153,7 @@

    Subclasses

    Expand source code -Browse git +Browse git
    class IntegratorError(Error):
         """Error raised when integrator step fails."""
    @@ -154,6 +169,7 @@

    Subclasses

    @@ -165,7 +181,7 @@

    Subclasses

    Expand source code -Browse git +Browse git
    class NonReversibleStepError(IntegratorError):
         """Error raised when integrator step fails reversibility check."""
    @@ -188,7 +204,7 @@

    Ancestors

    Expand source code -Browse git +Browse git
    class ConvergenceError(IntegratorError):
         """Error raised when solver fails to converge within allowed iterations."""
    @@ -211,7 +227,7 @@

    Ancestors

    Expand source code -Browse git +Browse git
    class LinAlgError(Error):
         """Error raised when a matrix operation raises a linear algebra error."""
    @@ -233,13 +249,58 @@

    Ancestors

    Expand source code -Browse git +Browse git -
    class HamiltonianDivergenceError(Error):
    +
    class HamiltonianDivergenceError(IntegratorError):
         """Error raised when integration of Hamiltonian dynamics diverges."""

    Ancestors

    + +
    +class AdaptationError +(*args, **kwargs) +
    +
    +

    Error raised when adaptation of transition parameters fails.

    +
    + +Expand source code +Browse git + +
    class AdaptationError(Error):
    +    """Error raised when adaptation of transition parameters fails."""
    +
    +

    Ancestors

    +
      +
    • Error
    • +
    • builtins.RuntimeError
    • +
    • builtins.Exception
    • +
    • builtins.BaseException
    • +
    +
    +
    +class ReadOnlyStateError +(*args, **kwargs) +
    +
    +

    Error raised when writing to attributes of read-only chain state.

    +
    + +Expand source code +Browse git + +
    class ReadOnlyStateError(Error):
    +    """Error raised when writing to attributes of read-only chain state."""
    +
    +

    Ancestors

    +
    • Error
    • builtins.RuntimeError
    • builtins.Exception
    • @@ -252,7 +313,7 @@

      Ancestors

      diff --git a/docs/docs/index.html b/docs/docs/index.html index e15fa23..af46142 100644 --- a/docs/docs/index.html +++ b/docs/docs/index.html @@ -3,14 +3,14 @@ - + mici API documentation - + @@ -28,6 +28,7 @@
      • Modules

          +
        • mici.adapters
        • mici.autodiff
        • mici.autograd_wrapper
        • mici.errors
        • @@ -53,7 +54,7 @@

          Package mici

          Expand source code -Browse git +Browse git
          # -*- coding: utf-8 -*-
           """ MCMC samplers based on simulating Hamiltonian dynamics on a manifold. """
          @@ -61,6 +62,7 @@ 

          Package mici

          __authors__ = 'Matt Graham' __license__ = 'MIT' +import mici.adapters import mici.autodiff import mici.integrators import mici.matrices @@ -75,6 +77,10 @@

          Package mici

          Modules

          +
          mici.adapters
          +
          +

          Methods for adaptively setting algorithmic parameters of transitions.

          +
          mici.autodiff

          Automatic differentation fallback for constructing derivative functions.

          @@ -135,7 +141,7 @@

          Modules

          diff --git a/docs/docs/integrators.html b/docs/docs/integrators.html index 323c7c1..05817d3 100644 --- a/docs/docs/integrators.html +++ b/docs/docs/integrators.html @@ -3,14 +3,14 @@ - + mici.integrators API documentation - + @@ -34,25 +34,25 @@
        • Classes

          • -

            Integrator

            +Integrator
          • -

            ExplicitLeapfrogIntegrator

            +LeapfrogIntegrator
          • -

            ImplicitLeapfrogIntegrator

            +ImplicitLeapfrogIntegrator
          • -

            ConstrainedLeapfrogIntegrator

            +ConstrainedLeapfrogIntegrator @@ -63,39 +63,38 @@

            -

            Package mici.integrators

            +

            Module mici.integrators

            Symplectic integrators for simulation of Hamiltonian dynamics.

            Expand source code -Browse git +Browse git
            """Symplectic integrators for simulation of Hamiltonian dynamics."""
             
             from abc import ABC, abstractmethod
            -from mici.errors import NonReversibleStepError
            +from mici.errors import NonReversibleStepError, AdaptationError
             from mici.solvers import (maximum_norm, solve_fixed_point_direct,
                                       solve_projection_onto_manifold_quasi_newton)
             
            -__pdoc__ = {}
            -
             
             class Integrator(ABC):
                 """Base class for integrators."""
             
            -    def __init__(self, system, step_size):
            +    def __init__(self, system, step_size=None):
                     """
                     Args:
                         system (mici.systems.System): Hamiltonian system to integrate the
                             dynamics of.
            -            step_size (float): Integrator time step.
            +            step_size (float or None): Integrator time step. If set to `None`
            +                (the default) it is assumed that a step size adapter will be
            +                used to set the step size before calling the `step` method.
                     """
                     self.system = system
                     self.step_size = step_size
             
            -    @abstractmethod
                 def step(self, state):
                     """Perform a single integrator step from a supplied state.
             
            @@ -107,9 +106,28 @@ 

            Package mici.integrators

            new_state (mici.states.ChainState): New object corresponding to stepped state. """ + if self.step_size is None: + raise AdaptationError( + 'Integrator `step_size` is `None`. This value should only be ' + 'used if a step size adapter is being used to set the step ' + 'size.') + state = state.copy() + self._step(state, state.dir * self.step_size) + return state + + @abstractmethod + def _step(self, state, dt): + """Implementation of single integrator step. + + Args: + state (mici.states.ChainState): System state to perform integrator + step from. Updated in place. + dt (float): Integrator time step. May be positive or negative. + """ + -class ExplicitLeapfrogIntegrator(Integrator): +class LeapfrogIntegrator(Integrator): r""" Leapfrog integrator for Hamiltonian systems with tractable component flows. @@ -123,11 +141,9 @@

            Package mici.integrators

            where \(q\) and \(p\) are the position and momentum variables respectively, and \(h_1\) and \(h_2\) are Hamiltonian component functions for which the exact flows can be computed. - - `LeapfrogIntegrator` is an alias for `ExplicitLeapfrogIntegrator`. """ - def __init__(self, system, step_size): + def __init__(self, system, step_size=None): if not hasattr(system, 'h1_flow') or not hasattr(system, 'h2_flow'): raise ValueError( 'Explicit leapfrog integrator can only be used for systems ' @@ -136,17 +152,10 @@

            Package mici.integrators

            'the `ImplicitLeapfrogIntegrator` class may be used instead.') super().__init__(system, step_size) - def step(self, state): - dt = state.dir * self.step_size - state = state.copy() + def _step(self, state, dt): self.system.h1_flow(state, 0.5 * dt) self.system.h2_flow(state, dt) self.system.h1_flow(state, 0.5 * dt) - return state - - -LeapfrogIntegrator = ExplicitLeapfrogIntegrator -__pdoc__['LeapfrogIntegrator'] = False class ImplicitLeapfrogIntegrator(Integrator): @@ -167,7 +176,7 @@

            Package mici.integrators

            of equations. """ - def __init__(self, system, step_size, reverse_check_tol=1e-8, + def __init__(self, system, step_size=None, reverse_check_tol=1e-8, reverse_check_norm=maximum_norm, fixed_point_solver=solve_fixed_point_direct, fixed_point_solver_kwargs=None): @@ -175,7 +184,9 @@

            Package mici.integrators

            Args: system (mici.systems.System): Hamiltonian system to integrate the dynamics of. - step_size (float): Integrator time step. + step_size (float or None): Integrator time step. If set to `None` + (the default) it is assumed that a step size adapter will be + used to set the step size before calling the `step` method. reverse_check_tol (float): Tolerance for check of reversibility of implicit sub-steps which involve iterative solving of a non-linear system of equations. The step is assumed to be @@ -200,8 +211,7 @@

            Package mici.integrators

            fixed_point_solver_kwargs (None or Dict[str, object]): Dictionary of any keyword arguments to `fixed_point_solver`. """ - self.system = system - self.step_size = step_size + super().__init__(system, step_size) self.reverse_check_tol = reverse_check_tol self.reverse_check_norm = maximum_norm self.fixed_point_solver = fixed_point_solver @@ -252,16 +262,13 @@

            Package mici.integrators

            pos_init = state.pos state.pos = self._solve_fixed_point(fixed_point_func, pos_init) - def step(self, state): - dt = 0.5 * state.dir * self.step_size - state = state.copy() + def _step(self, state, dt): self._step_a(state, dt) self._step_b_fwd(state, dt) self._step_c_fwd(state, dt) self._step_c_adj(state, dt) self._step_b_adj(state, dt) self._step_a(state, dt) - return state class ConstrainedLeapfrogIntegrator(Integrator): @@ -307,7 +314,7 @@

            Package mici.integrators

            integrator will also be in the cotangent bundle. """ - def __init__(self, system, step_size, n_inner_step=1, + def __init__(self, system, step_size=None, n_inner_step=1, reverse_check_tol=2e-8, reverse_check_norm=maximum_norm, projection_solver=solve_projection_onto_manifold_quasi_newton, projection_solver_kwargs=None): @@ -315,7 +322,9 @@

            Package mici.integrators

            Args: system (mici.systems.System): Hamiltonian system to integrate the dynamics of. - step_size (float): Integrator time step. + step_size (float or None): Integrator time step. If set to `None` + (the default) it is assumed that a step size adapter will be + used to set the step size before calling the `step` method. n_inner_step (int): Positive integer specifying number of 'inner' constrained `system.h2_flow` steps to take within each overall step. As the derivative `system.dh1_dpos` is not evaluated @@ -366,8 +375,7 @@

            Package mici.integrators

            projection_solver_kwargs (None or Dict[str, object]): Dictionary of any keyword arguments to `projection_solver`. """ - self.system = system - self.step_size = step_size + super().__init__(system, step_size) self.n_inner_step = n_inner_step self.reverse_check_tol = reverse_check_tol self.reverse_check_norm = reverse_check_norm @@ -416,13 +424,10 @@

            Package mici.integrators

            f'Non-reversible step. Distance between initial and ' f'forward-backward integrated positions = {rev_diff:.1e}.') - def step(self, state): - dt = state.dir * self.step_size - state = state.copy() + def _step(self, state, dt): self._step_a(state, 0.5 * dt) self._step_b(state, dt) - self._step_a(state, 0.5 * dt) - return state
            + self._step_a(state, 0.5 * dt)

    @@ -436,7 +441,7 @@

    Classes

    class Integrator -(system, step_size) +(system, step_size=None)

    Base class for integrators.

    @@ -445,28 +450,31 @@

    Args

    system : System
    Hamiltonian system to integrate the dynamics of.
    -
    step_size : float
    -
    Integrator time step.
    +
    step_size : float or None
    +
    Integrator time step. If set to None +(the default) it is assumed that a step size adapter will be +used to set the step size before calling the step method.
    Expand source code -Browse git +Browse git
    class Integrator(ABC):
         """Base class for integrators."""
     
    -    def __init__(self, system, step_size):
    +    def __init__(self, system, step_size=None):
             """
             Args:
                 system (mici.systems.System): Hamiltonian system to integrate the
                     dynamics of.
    -            step_size (float): Integrator time step.
    +            step_size (float or None): Integrator time step. If set to `None`
    +                (the default) it is assumed that a step size adapter will be
    +                used to set the step size before calling the `step` method.
             """
             self.system = system
             self.step_size = step_size
     
    -    @abstractmethod
         def step(self, state):
             """Perform a single integrator step from a supplied state.
     
    @@ -477,6 +485,24 @@ 

    Args

    Returns: new_state (mici.states.ChainState): New object corresponding to stepped state. + """ + if self.step_size is None: + raise AdaptationError( + 'Integrator `step_size` is `None`. This value should only be ' + 'used if a step size adapter is being used to set the step ' + 'size.') + state = state.copy() + self._step(state, state.dir * self.step_size) + return state + + @abstractmethod + def _step(self, state, dt): + """Implementation of single integrator step. + + Args: + state (mici.states.ChainState): System state to perform integrator + step from. Updated in place. + dt (float): Integrator time step. May be positive or negative. """

    Ancestors

    @@ -485,7 +511,7 @@

    Ancestors

    Subclasses

    @@ -511,10 +537,9 @@

    Returns

    Expand source code -Browse git +Browse git -
    @abstractmethod
    -def step(self, state):
    +
    def step(self, state):
         """Perform a single integrator step from a supplied state.
     
         Args:
    @@ -524,14 +549,22 @@ 

    Returns

    Returns: new_state (mici.states.ChainState): New object corresponding to stepped state. - """
    + """ + if self.step_size is None: + raise AdaptationError( + 'Integrator `step_size` is `None`. This value should only be ' + 'used if a step size adapter is being used to set the step ' + 'size.') + state = state.copy() + self._step(state, state.dir * self.step_size) + return state
    -
    -class ExplicitLeapfrogIntegrator -(system, step_size) +
    +class LeapfrogIntegrator +(system, step_size=None)

    Leapfrog integrator for Hamiltonian systems with tractable component flows.

    @@ -543,21 +576,22 @@

    Returns

    where q and p are the position and momentum variables respectively, and h_1 and h_2 are Hamiltonian component functions for which the exact flows can be computed.

    -

    LeapfrogIntegrator is an alias for ExplicitLeapfrogIntegrator.

    Args

    system : System
    Hamiltonian system to integrate the dynamics of.
    -
    step_size : float
    -
    Integrator time step.
    +
    step_size : float or None
    +
    Integrator time step. If set to None +(the default) it is assumed that a step size adapter will be +used to set the step size before calling the step method.
    Expand source code -Browse git +Browse git -
    class ExplicitLeapfrogIntegrator(Integrator):
    +
    class LeapfrogIntegrator(Integrator):
         r"""
         Leapfrog integrator for Hamiltonian systems with tractable component flows.
     
    @@ -571,11 +605,9 @@ 

    Args

    where \(q\) and \(p\) are the position and momentum variables respectively, and \(h_1\) and \(h_2\) are Hamiltonian component functions for which the exact flows can be computed. - - `LeapfrogIntegrator` is an alias for `ExplicitLeapfrogIntegrator`. """ - def __init__(self, system, step_size): + def __init__(self, system, step_size=None): if not hasattr(system, 'h1_flow') or not hasattr(system, 'h2_flow'): raise ValueError( 'Explicit leapfrog integrator can only be used for systems ' @@ -584,13 +616,10 @@

    Args

    'the `ImplicitLeapfrogIntegrator` class may be used instead.') super().__init__(system, step_size) - def step(self, state): - dt = state.dir * self.step_size - state = state.copy() + def _step(self, state, dt): self.system.h1_flow(state, 0.5 * dt) self.system.h2_flow(state, dt) - self.system.h1_flow(state, 0.5 * dt) - return state
    + self.system.h1_flow(state, 0.5 * dt)

    Ancestors

      @@ -599,7 +628,7 @@

      Ancestors

    Methods

    -
    +
    def step(self, state)
    @@ -616,25 +645,12 @@

    Returns

    New object corresponding to stepped state.
    -
    - -Expand source code -Browse git - -
    def step(self, state):
    -    dt = state.dir * self.step_size
    -    state = state.copy()
    -    self.system.h1_flow(state, 0.5 * dt)
    -    self.system.h2_flow(state, dt)
    -    self.system.h1_flow(state, 0.5 * dt)
    -    return state
    -
    class ImplicitLeapfrogIntegrator -(system, step_size, reverse_check_tol=1e-08, reverse_check_norm=<function maximum_norm>, fixed_point_solver=<function solve_fixed_point_direct>, fixed_point_solver_kwargs=None) +(system, step_size=None, reverse_check_tol=1e-08, reverse_check_norm=<function maximum_norm>, fixed_point_solver=<function solve_fixed_point_direct>, fixed_point_solver_kwargs=None)

    Implicit leapfrog integrator for Hamiltonian with non-separable component.

    @@ -653,8 +669,10 @@

    Args

    system : System
    Hamiltonian system to integrate the dynamics of.
    -
    step_size : float
    -
    Integrator time step.
    +
    step_size : float or None
    +
    Integrator time step. If set to None +(the default) it is assumed that a step size adapter will be +used to set the step size before calling the step method.
    reverse_check_tol : float
    Tolerance for check of reversibility of implicit sub-steps which involve iterative solving of a @@ -687,7 +705,7 @@

    Args

    Expand source code -Browse git +Browse git
    class ImplicitLeapfrogIntegrator(Integrator):
         r"""
    @@ -707,7 +725,7 @@ 

    Args

    of equations. """ - def __init__(self, system, step_size, reverse_check_tol=1e-8, + def __init__(self, system, step_size=None, reverse_check_tol=1e-8, reverse_check_norm=maximum_norm, fixed_point_solver=solve_fixed_point_direct, fixed_point_solver_kwargs=None): @@ -715,7 +733,9 @@

    Args

    Args: system (mici.systems.System): Hamiltonian system to integrate the dynamics of. - step_size (float): Integrator time step. + step_size (float or None): Integrator time step. If set to `None` + (the default) it is assumed that a step size adapter will be + used to set the step size before calling the `step` method. reverse_check_tol (float): Tolerance for check of reversibility of implicit sub-steps which involve iterative solving of a non-linear system of equations. The step is assumed to be @@ -740,8 +760,7 @@

    Args

    fixed_point_solver_kwargs (None or Dict[str, object]): Dictionary of any keyword arguments to `fixed_point_solver`. """ - self.system = system - self.step_size = step_size + super().__init__(system, step_size) self.reverse_check_tol = reverse_check_tol self.reverse_check_norm = maximum_norm self.fixed_point_solver = fixed_point_solver @@ -792,16 +811,13 @@

    Args

    pos_init = state.pos state.pos = self._solve_fixed_point(fixed_point_func, pos_init) - def step(self, state): - dt = 0.5 * state.dir * self.step_size - state = state.copy() + def _step(self, state, dt): self._step_a(state, dt) self._step_b_fwd(state, dt) self._step_c_fwd(state, dt) self._step_c_adj(state, dt) self._step_b_adj(state, dt) - self._step_a(state, dt) - return state
    + self._step_a(state, dt)

    Ancestors

      @@ -827,28 +843,12 @@

      Returns

      New object corresponding to stepped state.
    -
    - -Expand source code -Browse git - -
    def step(self, state):
    -    dt = 0.5 * state.dir * self.step_size
    -    state = state.copy()
    -    self._step_a(state, dt)
    -    self._step_b_fwd(state, dt)
    -    self._step_c_fwd(state, dt)
    -    self._step_c_adj(state, dt)
    -    self._step_b_adj(state, dt)
    -    self._step_a(state, dt)
    -    return state
    -
    class ConstrainedLeapfrogIntegrator -(system, step_size, n_inner_step=1, reverse_check_tol=2e-08, reverse_check_norm=<function maximum_norm>, projection_solver=<function solve_projection_onto_manifold_quasi_newton>, projection_solver_kwargs=None) +(system, step_size=None, n_inner_step=1, reverse_check_tol=2e-08, reverse_check_norm=<function maximum_norm>, projection_solver=<function solve_projection_onto_manifold_quasi_newton>, projection_solver_kwargs=None)

    Leapfrog integrator for constrained Hamiltonian systems.

    @@ -886,8 +886,10 @@

    Args

    system : System
    Hamiltonian system to integrate the dynamics of.
    -
    step_size : float
    -
    Integrator time step.
    +
    step_size : float or None
    +
    Integrator time step. If set to None +(the default) it is assumed that a step size adapter will be +used to set the step size before calling the step method.
    n_inner_step : int
    Positive integer specifying number of 'inner' constrained system.h2_flow steps to take within each overall @@ -946,7 +948,7 @@

    Args

    Expand source code -Browse git +Browse git
    class ConstrainedLeapfrogIntegrator(Integrator):
         r"""
    @@ -991,7 +993,7 @@ 

    Args

    integrator will also be in the cotangent bundle. """ - def __init__(self, system, step_size, n_inner_step=1, + def __init__(self, system, step_size=None, n_inner_step=1, reverse_check_tol=2e-8, reverse_check_norm=maximum_norm, projection_solver=solve_projection_onto_manifold_quasi_newton, projection_solver_kwargs=None): @@ -999,7 +1001,9 @@

    Args

    Args: system (mici.systems.System): Hamiltonian system to integrate the dynamics of. - step_size (float): Integrator time step. + step_size (float or None): Integrator time step. If set to `None` + (the default) it is assumed that a step size adapter will be + used to set the step size before calling the `step` method. n_inner_step (int): Positive integer specifying number of 'inner' constrained `system.h2_flow` steps to take within each overall step. As the derivative `system.dh1_dpos` is not evaluated @@ -1050,8 +1054,7 @@

    Args

    projection_solver_kwargs (None or Dict[str, object]): Dictionary of any keyword arguments to `projection_solver`. """ - self.system = system - self.step_size = step_size + super().__init__(system, step_size) self.n_inner_step = n_inner_step self.reverse_check_tol = reverse_check_tol self.reverse_check_norm = reverse_check_norm @@ -1100,13 +1103,10 @@

    Args

    f'Non-reversible step. Distance between initial and ' f'forward-backward integrated positions = {rev_diff:.1e}.') - def step(self, state): - dt = state.dir * self.step_size - state = state.copy() + def _step(self, state, dt): self._step_a(state, 0.5 * dt) self._step_b(state, dt) - self._step_a(state, 0.5 * dt) - return state
    + self._step_a(state, 0.5 * dt)

    Ancestors

      @@ -1132,19 +1132,6 @@

      Returns

      New object corresponding to stepped state.
    -
    - -Expand source code -Browse git - -
    def step(self, state):
    -    dt = state.dir * self.step_size
    -    state = state.copy()
    -    self._step_a(state, 0.5 * dt)
    -    self._step_b(state, dt)
    -    self._step_a(state, 0.5 * dt)
    -    return state
    -
    @@ -1154,7 +1141,7 @@

    Returns

    diff --git a/docs/docs/matrices.html b/docs/docs/matrices.html index 0baf92a..009bb7a 100644 --- a/docs/docs/matrices.html +++ b/docs/docs/matrices.html @@ -3,14 +3,14 @@ - + mici.matrices API documentation - + @@ -34,126 +34,196 @@
  • Classes

    • -

      Matrix

      +Matrix +
      + +Expand members + +
    • -

      ExplicitArrayMatrix

      +ExplicitArrayMatrix +
      + +Expand members + +
    • -

      ImplicitArrayMatrix

      +ImplicitArrayMatrix +
      + +Expand members + +
    • -

      MatrixProduct

      -
        +MatrixProduct +
        + +Expand members + + +
      • -

        SquareMatrix

        -
          +SquareMatrix +
          + +Expand members + + +
        • -

          SquareMatrixProduct

          -
            +SquareMatrixProduct +
            + +Expand members + + +
          • -

            InvertibleMatrix

            +InvertibleMatrix +
            + +Expand members + +
          • -

            InvertibleMatrixProduct

            +InvertibleMatrixProduct +
            + +Expand members + +
          • -

            SymmetricMatrix

            +SymmetricMatrix +
            + +Expand members + +
          • -

            PositiveDefiniteMatrix

            +PositiveDefiniteMatrix +
            + +Expand members + +
          • -

            IdentityMatrix

            +IdentityMatrix +
            + +Expand members + +
          • -

            DifferentiableMatrix

            +DifferentiableMatrix +
            + +Expand members + +
          • -

            ScaledIdentityMatrix

            +ScaledIdentityMatrix +
            + +Expand members + +
          • -

            PositiveScaledIdentityMatrix

            +PositiveScaledIdentityMatrix +
            + +Expand members + +
          • -

            DiagonalMatrix

            +DiagonalMatrix +
            + +Expand members + +
          • -

            PositiveDiagonalMatrix

            +PositiveDiagonalMatrix +
            + +Expand members + +
          • -

            TriangularMatrix

            +TriangularMatrix +
            + +Expand members + +
          • -

            InverseTriangularMatrix

            +InverseTriangularMatrix +
            + +Expand members + +
          • -

            TriangularFactoredDefiniteMatrix

            +TriangularFactoredDefiniteMatrix +
            + +Expand members + +
          • -

            TriangularFactoredPositiveDefiniteMatrix

            +TriangularFactoredPositiveDefiniteMatrix +
            + +Expand members + +
          • -

            DenseDefiniteMatrix

            +DenseDefiniteMatrix +
            + +Expand members + +
          • -

            DensePositiveDefiniteMatrix

            +DensePositiveDefiniteMatrix +
            + +Expand members + +
          • -

            DensePositiveDefiniteProductMatrix

            +DensePositiveDefiniteProductMatrix +
            + +Expand members + +
          • -

            DenseSquareMatrix

            +DenseSquareMatrix +
            + +Expand members + +
          • -

            InverseLUFactoredSquareMatrix

            +InverseLUFactoredSquareMatrix +
            + +Expand members + +
          • -

            DenseSymmetricMatrix

            +DenseSymmetricMatrix +
            + +Expand members + +
          • -

            OrthogonalMatrix

            +OrthogonalMatrix +
            + +Expand members + +
          • -

            ScaledOrthogonalMatrix

            +ScaledOrthogonalMatrix +
            + +Expand members + +
          • -

            EigendecomposedSymmetricMatrix

            +EigendecomposedSymmetricMatrix +
            + +Expand members + +
          • -

            EigendecomposedPositiveDefiniteMatrix

            +EigendecomposedPositiveDefiniteMatrix +
            + +Expand members + +
          • -

            SoftAbsRegularisedPositiveDefiniteMatrix

            +SoftAbsRegularizedPositiveDefiniteMatrix +
            + +Expand members + +
          • -

            BlockMatrix

            -
              +BlockMatrix +
              + +Expand members + + +
            • -

              SquareBlockDiagonalMatrix

              +SquareBlockDiagonalMatrix +
              + +Expand members + +
            • -

              SymmetricBlockDiagonalMatrix

              +SymmetricBlockDiagonalMatrix +
              + +Expand members + +
            • -

              PositiveDefiniteBlockDiagonalMatrix

              +PositiveDefiniteBlockDiagonalMatrix +
              + +Expand members + +
            • -

              DenseRectangularMatrix

              +DenseRectangularMatrix +
              + +Expand members + +
            • -

              BlockRowMatrix

              -
                +BlockRowMatrix +
                + +Expand members + + +
              • -

                BlockColumnMatrix

                -
              • @@ -570,14 +814,14 @@

                -

                Package mici.matrices

                +

                Module mici.matrices

                Structured matrix classes implementing basic linear algebra operations.

                Expand source code -Browse git +Browse git
                """Structured matrix classes implementing basic linear algebra operations."""
                 
                @@ -624,6 +868,7 @@ 

                Package mici.matrices

                """ self._shape = shape self._hash = None + self._transpose = None for k, v in kwargs.items(): if isinstance(v, np.ndarray): v.flags.writeable = False @@ -725,9 +970,17 @@

                Package mici.matrices

                """ @property - @abc.abstractmethod - def T(self): + def transpose(self): """Transpose of matrix.""" + if self._transpose is None: + self._transpose = self._construct_transpose() + return self._transpose + + T = transpose + + @abc.abstractmethod + def _construct_transpose(self): + """Construct transpose of matrix.""" @property def diagonal(self): @@ -751,7 +1004,7 @@

                Package mici.matrices

                @classmethod def __subclasshook__(cls, C): - # Customise isinstance / issubclass behaviour to also return True for + # Customize isinstance / issubclass behaviour to also return True for # classes / objects with classes which have all required attributes # without being direct subclasses if hasattr(cls, '_get_required_subclass_attrs'): @@ -784,6 +1037,8 @@

                Package mici.matrices

                def __init__(self, shape, **kwargs): if '_array' not in kwargs: raise ValueError('_array must be specified in kwargs') + else: + kwargs['_array'] = np.asarray_chkfinite(kwargs['_array']) super().__init__(shape, **kwargs) @property @@ -879,8 +1134,7 @@

                Package mici.matrices

                other = other @ matrix return other - @property - def T(self): + def _construct_transpose(self): return type(self)( tuple(matrix.T for matrix in reversed(self.matrices))) @@ -947,8 +1201,11 @@

                Package mici.matrices

                _required_subclass_attrs = {'inv'} + def __init__(self, shape, **kwargs): + super().__init__(shape, **kwargs) + self._inv = None + @property - @abc.abstractmethod def inv(self): """Inverse of matrix as a `Matrix` object. @@ -957,6 +1214,19 @@

                Package mici.matrices

                the matrix multiplication operators by solving the linear system defined by the original matrix object. """ + if self._inv is None: + self._inv = self._construct_inv() + return self._inv + + @abc.abstractmethod + def _construct_inv(self): + """Construct inverse of matrix as a `Matrix` object. + + This will not necessarily form an explicit representation of the + inverse matrix but may instead return a `Matrix` object that implements + the matrix multiplication operators by solving the linear system + defined by the original matrix object. + """ class InvertibleMatrixProduct(SquareMatrixProduct, InvertibleMatrix): @@ -972,8 +1242,7 @@

                Package mici.matrices

                raise ValueError(f'matrix {matrix} is not invertible.') super().__init__(matrices, check_shapes) - @property - def inv(self): + def _construct_inv(self): return InvertibleMatrixProduct( tuple(matrix.inv for matrix in reversed(self.matrices))) @@ -1006,8 +1275,7 @@

                Package mici.matrices

                self._compute_eigendecomposition() return self._eigvec - @property - def T(self): + def _construct_transpose(self): return self @property @@ -1020,8 +1288,11 @@

                Package mici.matrices

                _required_subclass_attrs = {'sqrt'} + def __init__(self, shape, **kwargs): + self._sqrt = None + super().__init__(shape, **kwargs) + @property - @abc.abstractmethod def sqrt(self): """Square-root of matrix satisfying `matrix == sqrt @ sqrt.T`. @@ -1029,6 +1300,18 @@

                Package mici.matrices

                symmetric square root of a symmetric matrix but instead may return any matrix satisfying the above property. """ + if self._sqrt is None: + self._sqrt = self._construct_sqrt() + return self._sqrt + + @abc.abstractmethod + def _construct_sqrt(self): + """Construct qquare-root of matrix satisfying `matrix == sqrt @ sqrt.T`. + + This will in general not correspond to the unique, if defined, + symmetric square root of a symmetric matrix but instead may return any + matrix satisfying the above property. + """ class IdentityMatrix(PositiveDefiniteMatrix, ImplicitArrayMatrix): @@ -1065,16 +1348,14 @@

                Package mici.matrices

                def eigval(self): return self.diagonal - @property - def sqrt(self): + def _construct_sqrt(self): return self @property def eigvec(self): return self - @property - def inv(self): + def _construct_inv(self): return self @property @@ -1186,8 +1467,7 @@

                Package mici.matrices

                def eigvec(self): return IdentityMatrix(self.shape[0]) - @property - def inv(self): + def _construct_inv(self): return ScaledIdentityMatrix(1 / self._scalar, self.shape[0]) @property @@ -1245,12 +1525,10 @@

                Package mici.matrices

                else: return super()._scalar_multiply(scalar) - @property - def inv(self): + def _construct_inv(self): return PositiveScaledIdentityMatrix(1 / self._scalar, self.shape[0]) - @property - def sqrt(self): + def _construct_sqrt(self): return PositiveScaledIdentityMatrix(self._scalar**0.5, self.shape[0]) @@ -1295,8 +1573,7 @@

                Package mici.matrices

                def eigval(self): return self.diagonal - @property - def inv(self): + def _construct_inv(self): return DiagonalMatrix(1. / self.diagonal) def _construct_array(self): @@ -1333,12 +1610,10 @@

                Package mici.matrices

                else: return super()._scalar_multiply(scalar) - @property - def inv(self): + def _construct_inv(self): return PositiveDiagonalMatrix(1. / self.diagonal) - @property - def sqrt(self): + def _construct_sqrt(self): return PositiveDiagonalMatrix(self.diagonal**0.5) @@ -1350,7 +1625,7 @@

                Package mici.matrices

                class TriangularMatrix(InvertibleMatrix, ExplicitArrayMatrix): """Matrix with non-zero values only in lower or upper triangle elements.""" - def __init__(self, array, lower=True): + def __init__(self, array, lower=True, make_triangular=True): """ Args: array (array): 2D array containing lower / upper triangular element @@ -1359,25 +1634,30 @@

                Package mici.matrices

                `lower == True` (`lower == False`). lower (bool): Whether the matrix is lower-triangular (`True`) or upper-triangular (`False`). + make_triangular (bool): Whether to ensure `array` is triangular + by explicitly zeroing entries in upper triangle if + `lower == True` and in lower triangle if `lower == False`. """ - super().__init__( - array.shape, _array=_make_array_triangular(array, lower)) + array = ( + _make_array_triangular(array, lower) if make_triangular else array) + super().__init__(array.shape, _array=array) self._lower = lower def _scalar_multiply(self, scalar): - return TriangularMatrix(self.array * scalar, self.lower) + return TriangularMatrix( + self.array * scalar, self.lower, make_triangular=False) @property def lower(self): return self._lower - @property - def inv(self): - return InverseTriangularMatrix(self.array, lower=self.lower) + def _construct_inv(self): + return InverseTriangularMatrix( + self.array, lower=self.lower, make_triangular=False) - @property - def T(self): - return TriangularMatrix(self.array.T, lower=not self.lower) + def _construct_transpose(self): + return TriangularMatrix( + self.array.T, lower=not self.lower, make_triangular=False) @property def log_abs_det(self): @@ -1390,7 +1670,7 @@

                Package mici.matrices

                class InverseTriangularMatrix(InvertibleMatrix, ImplicitArrayMatrix): """Triangular matrix implicitly specified by its inverse.""" - def __init__(self, inverse_array, lower=True): + def __init__(self, inverse_array, lower=True, make_triangular=True): """ Args: inverse_array (array): 2D containing values of *inverse* of this @@ -1400,39 +1680,47 @@

                Package mici.matrices

                when `lower == True` (`lower == False`). lower (bool): Whether the matrix is lower-triangular (`True`) or upper-triangular (`False`). - """ - super().__init__( - inverse_array.shape, - _inverse_array=_make_array_triangular(inverse_array, lower)) + make_triangular (bool): Whether to ensure `inverse_array` is + triangular by explicitly zeroing entries in upper triangle if + `lower == True` and in lower triangle if `lower == False`. + """ + inverse_array = np.asarray_chkfinite(inverse_array) + inverse_array = ( + _make_array_triangular(inverse_array, lower) if make_triangular + else inverse_array) + super().__init__(inverse_array.shape, _inverse_array=inverse_array) self._lower = lower def _scalar_multiply(self, scalar): return InverseTriangularMatrix( - self._inverse_array / scalar, self.lower) + self._inverse_array / scalar, self.lower, make_triangular=False) def _left_matrix_multiply(self, other): return sla.solve_triangular( - self._inverse_array, other, lower=self.lower) + self._inverse_array, other, lower=self.lower, check_finite=False) def _right_matrix_multiply(self, other): return sla.solve_triangular( - self._inverse_array, other.T, lower=self.lower, trans=1).T + self._inverse_array, other.T, lower=self.lower, trans=1, + check_finite=False).T @property def lower(self): return self._lower - @property - def inv(self): - return TriangularMatrix(self._inverse_array, lower=self.lower) + def _construct_inv(self): + return TriangularMatrix( + self._inverse_array, lower=self.lower, make_triangular=False) - @property - def T(self): + def _construct_transpose(self): return InverseTriangularMatrix( - self._inverse_array.T, lower=not self.lower) + self._inverse_array.T, lower=not self.lower, make_triangular=False) def _construct_array(self): - return self @ np.identity(self.shape[0]) + #return self @ np.identity(self.shape[0]) + return sla.solve_triangular( + self._inverse_array, np.identity(self.shape[0]), lower=self.lower, + check_finite=False) @property def diagonal(self): @@ -1470,8 +1758,7 @@

                Package mici.matrices

                """Signed binary valueith `matrix = sign * factor @ factor.T`""" return self._sign - @property - def inv(self): + def _construct_inv(self): return TriangularFactoredDefiniteMatrix( factor=self.factor.inv.T, sign=self._sign) @@ -1559,7 +1846,7 @@

                Package mici.matrices

                class TriangularFactoredPositiveDefiniteMatrix( TriangularFactoredDefiniteMatrix, PositiveDefiniteMatrix): - """Positive definite matrix parameterised a triangular matrix product. + """Positive definite matrix parametrized a triangular matrix product. The matrix is assumed to have the parameterisation @@ -1594,13 +1881,11 @@

                Package mici.matrices

                else: return super()._scalar_multiply(scalar) - @property - def inv(self): + def _construct_inv(self): return TriangularFactoredPositiveDefiniteMatrix( factor=self.factor.inv.T) - @property - def sqrt(self): + def _construct_sqrt(self): return self.factor @@ -1625,7 +1910,7 @@

                Package mici.matrices

                initialisation, and so if `array` is positive (negative) definite and `is_posdef` is `False` (`True`) then a `LinAlgError` exception will be if a later attempt is made to - factorise the matrix. + factorize the matrix. """ super().__init__( array.shape[0], sign=1 if is_posdef else -1, _array=array) @@ -1648,7 +1933,8 @@

                Package mici.matrices

                if self._factor is None: try: self._factor = TriangularMatrix( - nla.cholesky(self._sign * self._array), lower=True) + nla.cholesky(self._sign * self._array), lower=True, + make_triangular=False) except nla.LinAlgError as e: raise LinAlgError('Cholesky factorisation failed.') from e return self._factor @@ -1661,6 +1947,11 @@

                Package mici.matrices

                inv_matrix_vector = self.inv @ vector return -np.outer(inv_matrix_vector, inv_matrix_vector) + def _construct_inv(self): + return DenseDefiniteMatrix( + super()._construct_inv().array, factor=self.factor.inv.T, + is_posdef=(self._sign == 1)) + class DensePositiveDefiniteMatrix(DenseDefiniteMatrix, PositiveDefiniteMatrix): """Positive-definite matrix specified by a dense 2D array.""" @@ -1678,13 +1969,11 @@

                Package mici.matrices

                """ super().__init__(array=array, factor=factor, is_posdef=True) - @property - def inv(self): - return TriangularFactoredPositiveDefiniteMatrix( - factor=self.factor.inv.T) + def _construct_inv(self): + return DensePositiveDefiniteMatrix( + super()._construct_inv(), factor=self.factor.inv.T) - @property - def sqrt(self): + def _construct_sqrt(self): return self.factor @@ -1771,7 +2060,7 @@

                Package mici.matrices

                def lu_and_piv(self): """Pivoted LU factorisation of matrix.""" if self._lu_and_piv is None: - self._lu_and_piv = sla.lu_factor(self._array) + self._lu_and_piv = sla.lu_factor(self._array, check_finite=False) self._lu_transposed = False return self._lu_and_piv @@ -1780,14 +2069,12 @@

                Package mici.matrices

                lu, piv = self.lu_and_piv return np.log(np.abs(lu.diagonal())).sum() - @property - def T(self): + def _construct_transpose(self): lu_and_piv = self.lu_and_piv return DenseSquareMatrix( self._array.T, lu_and_piv, not self._lu_transposed) - @property - def inv(self): + def _construct_inv(self): lu_and_piv = self.lu_and_piv return InverseLUFactoredSquareMatrix( self._array, lu_and_piv, self._lu_transposed) @@ -1825,11 +2112,13 @@

                Package mici.matrices

                def _left_matrix_multiply(self, other): return sla.lu_solve( - self._inv_lu_and_piv, other, self._inv_lu_transposed) + self._inv_lu_and_piv, other, self._inv_lu_transposed, + check_finite=False) def _right_matrix_multiply(self, other): return sla.lu_solve( - self._inv_lu_and_piv, other.T, not self._inv_lu_transposed).T + self._inv_lu_and_piv, other.T, not self._inv_lu_transposed, + check_finite=False).T @property def log_abs_det(self): @@ -1838,13 +2127,11 @@

                Package mici.matrices

                def _construct_array(self): return self @ np.identity(self.shape[0]) - @property - def inv(self): + def _construct_inv(self): return DenseSquareMatrix( self._inv_array, self._inv_lu_and_piv, self._inv_lu_transposed) - @property - def T(self): + def _construct_transpose(self): return InverseLUFactoredSquareMatrix( self._inv_array.T, self._inv_lu_and_piv, not self._inv_lu_transposed) @@ -1885,8 +2172,7 @@

                Package mici.matrices

                self.array * scalar, self._eigvec, None if self._eigval is None else self._eigval * scalar) - @property - def inv(self): + def _construct_inv(self): return EigendecomposedSymmetricMatrix(self.eigvec, 1 / self.eigval) @@ -1907,12 +2193,10 @@

                Package mici.matrices

                def log_abs_det(self): return 0 - @property - def T(self): + def _construct_transpose(self): return OrthogonalMatrix(self.array.T) - @property - def inv(self): + def _construct_inv(self): return self.T @@ -1956,12 +2240,10 @@

                Package mici.matrices

                def log_abs_det(self): return self.shape[0] * np.log(abs(self._scalar)) - @property - def T(self): + def _construct_transpose(self): return ScaledOrthogonalMatrix(self._scalar, self._orth_array.T) - @property - def inv(self): + def _construct_inv(self): return ScaledOrthogonalMatrix(1 / self._scalar, self._orth_array.T) def _compute_hash(self): @@ -1974,7 +2256,7 @@

                Package mici.matrices

                class EigendecomposedSymmetricMatrix( SymmetricMatrix, InvertibleMatrix, ImplicitArrayMatrix): - """Symmetric matrix parameterised by its eigendecomposition. + """Symmetric matrix parametrized by its eigendecomposition. The matrix is assumed to have the parameterisation @@ -2016,8 +2298,7 @@

                Package mici.matrices

                def _right_matrix_multiply(self, other): return ((other @ self.eigvec) @ self.diag_eigval) @ self.eigvec.T - @property - def inv(self): + def _construct_inv(self): return EigendecomposedSymmetricMatrix(self.eigvec, 1 / self.eigval) def _construct_array(self): @@ -2037,7 +2318,7 @@

                Package mici.matrices

                class EigendecomposedPositiveDefiniteMatrix( EigendecomposedSymmetricMatrix, PositiveDefiniteMatrix): - """Positive definite matrix parameterised by its eigendecomposition. + """Positive definite matrix parametrized by its eigendecomposition. The matrix is assumed to have the parameterisation @@ -2060,21 +2341,19 @@

                Package mici.matrices

                else: return super()._scalar_multiply(scalar) - @property - def inv(self): + def _construct_inv(self): return EigendecomposedPositiveDefiniteMatrix( self.eigvec, 1 / self.eigval) - @property - def sqrt(self): + def _construct_sqrt(self): return EigendecomposedSymmetricMatrix(self.eigvec, self.eigval**0.5) -class SoftAbsRegularisedPositiveDefiniteMatrix( +class SoftAbsRegularizedPositiveDefiniteMatrix( EigendecomposedPositiveDefiniteMatrix, DifferentiableMatrix): """Matrix transformed to be positive definite by regularising eigenvalues. - Matrix is parameterised by a symmetric array `symmetric_array`, of which an + Matrix is parametrized by a symmetric array `symmetric_array`, of which an eigendecomposition is formed `eigvec, eigval = eigh(symmetric_array)`, with the output matrix then `matrix = eigvec @ softabs(eigval) @ eigvec.T` where `softabs` is a smooth approximation to the absolute function. @@ -2086,7 +2365,7 @@

                Package mici.matrices

                symmetric_array (array): 2D square array with symmetric values, i.e. `symmetric_array[i, j] == symmetric_array[j, i]` for all indices `i` and `j` which represents symmetric matrix to - form eigenvalue-regularised transformation of. + form eigenvalue-regularized transformation of. softabs_coeff (float): Positive regularisation coefficient for smooth approximation to absolute value. As the value tends to infinity the approximation becomes increasingly close to the @@ -2189,22 +2468,19 @@

                Package mici.matrices

                def _construct_array(self): return sla.block_diag(*(block.array for block in self._blocks)) - @property - def T(self): + def _construct_transpose(self): return SquareBlockDiagonalMatrix( tuple(block.T for block in self._blocks)) - @property - def sqrt(self): + def _construct_sqrt(self): return SquareBlockDiagonalMatrix( tuple(block.sqrt for block in self._blocks)) @property - def diag(self): + def diagonal(self): return np.concatenate([block.diagonal() for block in self._blocks]) - @property - def inv(self): + def _construct_inv(self): return type(self)(tuple(block.inv for block in self._blocks)) @property @@ -2244,8 +2520,7 @@

                Package mici.matrices

                return SymmetricBlockDiagonalMatrix( tuple(scalar * block for block in self._blocks)) - @property - def T(self): + def _construct_transpose(self): return self @@ -2279,8 +2554,7 @@

                Package mici.matrices

                else: return super()._scalar_multiply(scalar) - @property - def sqrt(self): + def _construct_sqrt(self): return SquareBlockDiagonalMatrix( tuple(block.sqrt for block in self._blocks)) @@ -2315,8 +2589,7 @@

                Package mici.matrices

                def _scalar_multiply(self, scalar): return DenseRectangularMatrix(scalar * self.array) - @property - def T(self): + def _construct_transpose(self): return DenseRectangularMatrix(self.array.T) @@ -2361,10 +2634,8 @@

                Package mici.matrices

                def _construct_array(self): return np.concatenate([block.array for block in self._blocks], axis=1) - @property - def T(self): - return BlockColumnMatrix( - tuple(block.T for block in self._blocks)) + def _construct_transpose(self): + return BlockColumnMatrix(tuple(block.T for block in self._blocks)) class BlockColumnMatrix(BlockMatrix): @@ -2408,10 +2679,8 @@

                Package mici.matrices

                def _construct_array(self): return np.concatenate([block.array for block in self._blocks], axis=0) - @property - def T(self): - return BlockRowMatrix( - tuple(block.T for block in self._blocks)) + def _construct_transpose(self): + return BlockRowMatrix(tuple(block.T for block in self._blocks)) class SquareLowRankUpdateMatrix(InvertibleMatrix, ImplicitArrayMatrix): @@ -2473,6 +2742,10 @@

                Package mici.matrices

                f'{square_matrix.shape[0]}.') if square_matrix.shape[0] != square_matrix.shape[1]: raise ValueError('square_matrix argument must be square') + if not isinstance(left_factor_matrix, Matrix): + left_factor_matrix = DenseRectangularMatrix(left_factor_matrix) + if not isinstance(right_factor_matrix, Matrix): + right_factor_matrix = DenseRectangularMatrix(right_factor_matrix) if right_factor_matrix.shape != (dim_inner, dim_outer): raise ValueError(f'Inconsistent factor matrix shapes: ' f'{left_factor_matrix.shape} and ' @@ -2528,8 +2801,7 @@

                Package mici.matrices

                (self.left_factor_matrix.array @ self.inner_square_matrix) * self.right_factor_matrix.T.array).sum(1) - @property - def T(self): + def _construct_transpose(self): return type(self)( self.right_factor_matrix.T, self.left_factor_matrix.T, self.square_matrix.T, self.inner_square_matrix.T, @@ -2537,8 +2809,7 @@

                Package mici.matrices

                if self._capacitance_matrix is not None else None, self._sign) - @property - def inv(self): + def _construct_inv(self): return type(self)( self.square_matrix.inv @ self.left_factor_matrix, self.right_factor_matrix @ self.square_matrix.inv, @@ -2614,10 +2885,15 @@

                Package mici.matrices

                sign (int): One of {-1, +1}, determining whether a low-rank update (`sign = 1`) or 'downdate' (`sign = -1`) is peformed. """ + dim_inner = factor_matrix.shape[1] if symmetric_matrix.T is not symmetric_matrix: raise ValueError('symmetric_matrix must be symmetric') + if inner_symmetric_matrix is None: + inner_symmetric_matrix = IdentityMatrix(dim_inner) if inner_symmetric_matrix.T is not inner_symmetric_matrix: raise ValueError('inner_symmetric_matrix must be symmetric') + if not isinstance(factor_matrix, Matrix): + factor_matrix = DenseRectangularMatrix(factor_matrix) self.factor_matrix = factor_matrix self.symmetric_matrix = symmetric_matrix self.inner_symmetric_matrix = inner_symmetric_matrix @@ -2641,15 +2917,13 @@

                Package mici.matrices

                self.symmetric_matrix.inv @ self.factor_matrix.array)) return self._capacitance_matrix - @property - def inv(self): + def _construct_inv(self): return type(self)( self.symmetric_matrix.inv @ self.factor_matrix, self.symmetric_matrix.inv, self.capacitance_matrix.inv, self.inner_symmetric_matrix.inv, -self._sign) - @property - def T(self): + def _construct_transpose(self): return self def _compute_hash(self): @@ -2664,8 +2938,8 @@

                Package mici.matrices

                class PositiveDefiniteLowRankUpdateMatrix( - PositiveDefiniteMatrix, DifferentiableMatrix, - SymmetricLowRankUpdateMatrix): + SymmetricLowRankUpdateMatrix, PositiveDefiniteMatrix, + DifferentiableMatrix): """Positive-definite matrix equal to low-rank update to a square matrix. The matrix is assumed to have the parametrisation @@ -2716,8 +2990,13 @@

                Package mici.matrices

                sign (int): One of {-1, +1}, determining whether a low-rank update (`sign = 1`) or 'downdate' (`sign = -1`) is peformed. """ + dim_inner = factor_matrix.shape[1] + if not isinstance(factor_matrix, Matrix): + factor_matrix = DenseRectangularMatrix(factor_matrix) self.factor_matrix = factor_matrix self.pos_def_matrix = pos_def_matrix + if inner_pos_def_matrix is None: + inner_pos_def_matrix = IdentityMatrix(dim_inner) self.inner_pos_def_matrix = inner_pos_def_matrix super().__init__( factor_matrix, pos_def_matrix, inner_pos_def_matrix, @@ -2747,8 +3026,7 @@

                Package mici.matrices

                self.factor_matrix.array)) return self._capacitance_matrix - @property - def sqrt(self): + def _construct_sqrt(self): # Uses O(dim_inner**3 + dim_inner**2 * dim_outer) cost implementation # proposed in # Ambikasaran, O'Neill & Singh (2016). Fast symmetric factorization @@ -2757,7 +3035,8 @@

                Package mici.matrices

                W = self.pos_def_matrix.sqrt K = self.inner_pos_def_matrix U = W.inv @ self.factor_matrix - L = TriangularMatrix(nla.cholesky(U.T @ U.array)) + L = TriangularMatrix( + nla.cholesky(U.T @ U.array), lower=True, make_triangular=False) I_outer, I_inner = IdentityMatrix(U.shape[0]), np.identity(U.shape[1]) M = sla.sqrtm(I_inner + L.T @ (K @ L.array)) X = DenseSymmetricMatrix(L.inv.T @ ((M - I_inner) @ L.inv)) @@ -2802,7 +3081,7 @@

                Args

                Expand source code -Browse git +Browse git
                class Matrix(abc.ABC):
                     """Base class for matrix-like objects.
                @@ -2827,6 +3106,7 @@ 

                Args

                """ self._shape = shape self._hash = None + self._transpose = None for k, v in kwargs.items(): if isinstance(v, np.ndarray): v.flags.writeable = False @@ -2928,9 +3208,17 @@

                Args

                """ @property - @abc.abstractmethod - def T(self): + def transpose(self): """Transpose of matrix.""" + if self._transpose is None: + self._transpose = self._construct_transpose() + return self._transpose + + T = transpose + + @abc.abstractmethod + def _construct_transpose(self): + """Construct transpose of matrix.""" @property def diagonal(self): @@ -2954,7 +3242,7 @@

                Args

                @classmethod def __subclasshook__(cls, C): - # Customise isinstance / issubclass behaviour to also return True for + # Customize isinstance / issubclass behaviour to also return True for # classes / objects with classes which have all required attributes # without being direct subclasses if hasattr(cls, '_get_required_subclass_attrs'): @@ -2998,7 +3286,7 @@

                Instance variables

                Expand source code -Browse git +Browse git
                @property
                 def shape(self):
                @@ -3012,7 +3300,7 @@ 

                Instance variables

                Expand source code -Browse git +Browse git
                @property
                 @abc.abstractmethod
                @@ -3020,18 +3308,36 @@ 

                Instance variables

                """Full dense representation of matrix as a 2D array."""
                +
                var transpose
                +
                +

                Transpose of matrix.

                +
                + +Expand source code +Browse git + +
                @property
                +def transpose(self):
                +    """Transpose of matrix."""
                +    if self._transpose is None:
                +        self._transpose = self._construct_transpose()
                +    return self._transpose
                +
                +
                var T

                Transpose of matrix.

                Expand source code -Browse git +Browse git
                @property
                -@abc.abstractmethod
                -def T(self):
                -    """Transpose of matrix."""
                +def transpose(self): + """Transpose of matrix.""" + if self._transpose is None: + self._transpose = self._construct_transpose() + return self._transpose
                var diagonal
                @@ -3040,7 +3346,7 @@

                Instance variables

                Expand source code -Browse git +Browse git
                @property
                 def diagonal(self):
                @@ -3064,7 +3370,7 @@ 

                Args

                Expand source code -Browse git +Browse git
                class ExplicitArrayMatrix(Matrix):
                     """Matrix with an explicit array representation."""
                @@ -3072,6 +3378,8 @@ 

                Args

                def __init__(self, shape, **kwargs): if '_array' not in kwargs: raise ValueError('_array must be specified in kwargs') + else: + kwargs['_array'] = np.asarray_chkfinite(kwargs['_array']) super().__init__(shape, **kwargs) @property @@ -3112,7 +3420,7 @@

                Instance variables

                Expand source code -Browse git +Browse git
                @property
                 def array(self):
                @@ -3123,6 +3431,10 @@ 

                Instance variables

                Shape of matrix as a tuple (num_rows, num_columns).

                +
                var transpose
                +
                +

                Transpose of matrix.

                +
                var T

                Transpose of matrix.

                @@ -3147,7 +3459,7 @@

                Args

                Expand source code -Browse git +Browse git
                class ImplicitArrayMatrix(Matrix):
                     """Matrix with an implicit array representation."""
                @@ -3211,7 +3523,7 @@ 

                Instance variables

                Expand source code -Browse git +Browse git
                @property
                 def array(self):
                @@ -3230,6 +3542,10 @@ 

                Instance variables

                Shape of matrix as a tuple (num_rows, num_columns).

                +
                var transpose
                +
                +

                Transpose of matrix.

                +
                var T

                Transpose of matrix.

                @@ -3259,7 +3575,7 @@

                Args

                Expand source code -Browse git +Browse git
                class MatrixProduct(ImplicitArrayMatrix):
                     """Matrix implicitly defined as a product of a sequence of matrices.
                @@ -3304,8 +3620,7 @@ 

                Args

                other = other @ matrix return other - @property - def T(self): + def _construct_transpose(self): return type(self)( tuple(matrix.T for matrix in reversed(self.matrices))) @@ -3340,27 +3655,13 @@

                Instance variables

                Expand source code -Browse git +Browse git
                @property
                 def matrices(self):
                     return self._matrices
                -
                var T
                -
                -

                Transpose of matrix.

                -
                - -Expand source code -Browse git - -
                @property
                -def T(self):
                -    return type(self)(
                -        tuple(matrix.T for matrix in reversed(self.matrices)))
                -
                -
                var array

                Full dense representation of matrix as a 2D array.

                @@ -3372,6 +3673,14 @@

                Instance variables

                Shape of matrix as a tuple (num_rows, num_columns).

                +
                var transpose
                +
                +

                Transpose of matrix.

                +
                +
                var T
                +
                +

                Transpose of matrix.

                +
                var diagonal

                Diagonal of matrix as a 1D array.

                @@ -3392,7 +3701,7 @@

                Args

                Expand source code -Browse git +Browse git
                class SquareMatrix(Matrix):
                     """Base class for matrices with equal numbers of rows and columns."""
                @@ -3437,7 +3746,7 @@ 

                Instance variables

                Expand source code -Browse git +Browse git
                @property
                 @abc.abstractmethod
                @@ -3458,6 +3767,10 @@ 

                Instance variables

                Full dense representation of matrix as a 2D array.

                +
                var transpose
                +
                +

                Transpose of matrix.

                +
                var T

                Transpose of matrix.

                @@ -3487,7 +3800,7 @@

                Args

                Expand source code -Browse git +Browse git
                class SquareMatrixProduct(MatrixProduct, SquareMatrix):
                     """Matrix implicitly defined as a product of a sequence of square matrices.
                @@ -3533,17 +3846,13 @@ 

                Instance variables

                Expand source code -Browse git +Browse git
                @property
                 def log_abs_det(self):
                     return sum(matrix.log_abs_det for matrix in self.matrices)
                -
                var T
                -
                -

                Transpose of matrix.

                -
                var array

                Full dense representation of matrix as a 2D array.

                @@ -3555,6 +3864,14 @@

                Instance variables

                Shape of matrix as a tuple (num_rows, num_columns).

                +
                var transpose
                +
                +

                Transpose of matrix.

                +
                +
                var T
                +
                +

                Transpose of matrix.

                +
                var diagonal

                Diagonal of matrix as a 1D array.

                @@ -3575,15 +3892,18 @@

                Args

                Expand source code -Browse git +Browse git
                class InvertibleMatrix(SquareMatrix):
                     """Base class for non-singular square matrices."""
                 
                     _required_subclass_attrs = {'inv'}
                 
                +    def __init__(self, shape, **kwargs):
                +        super().__init__(shape, **kwargs)
                +        self._inv = None
                +
                     @property
                -    @abc.abstractmethod
                     def inv(self):
                         """Inverse of matrix as a `Matrix` object.
                 
                @@ -3591,7 +3911,20 @@ 

                Args

                inverse matrix but may instead return a `Matrix` object that implements the matrix multiplication operators by solving the linear system defined by the original matrix object. - """
                + """ + if self._inv is None: + self._inv = self._construct_inv() + return self._inv + + @abc.abstractmethod + def _construct_inv(self): + """Construct inverse of matrix as a `Matrix` object. + + This will not necessarily form an explicit representation of the + inverse matrix but may instead return a `Matrix` object that implements + the matrix multiplication operators by solving the linear system + defined by the original matrix object. + """

                Ancestors

                  @@ -3629,10 +3962,9 @@

                  Instance variables

                  Expand source code -Browse git +Browse git
                  @property
                  -@abc.abstractmethod
                   def inv(self):
                       """Inverse of matrix as a `Matrix` object.
                   
                  @@ -3640,7 +3972,10 @@ 

                  Instance variables

                  inverse matrix but may instead return a `Matrix` object that implements the matrix multiplication operators by solving the linear system defined by the original matrix object. - """
                  + """ + if self._inv is None: + self._inv = self._construct_inv() + return self._inv
                var log_abs_det
                @@ -3658,6 +3993,10 @@

                Instance variables

                Full dense representation of matrix as a 2D array.

                +
                var transpose
                +
                +

                Transpose of matrix.

                +
                var T

                Transpose of matrix.

                @@ -3687,7 +4026,7 @@

                Args

                Expand source code -Browse git +Browse git
                class InvertibleMatrixProduct(SquareMatrixProduct, InvertibleMatrix):
                     """Matrix defined as a product of a sequence of invertible matrices.
                @@ -3702,8 +4041,7 @@ 

                Args

                raise ValueError(f'matrix {matrix} is not invertible.') super().__init__(matrices, check_shapes) - @property - def inv(self): + def _construct_inv(self): return InvertibleMatrixProduct( tuple(matrix.inv for matrix in reversed(self.matrices)))
                @@ -3719,24 +4057,6 @@

                Ancestors

              Instance variables

              -
              var inv
              -
              -

              Inverse of matrix as a Matrix object.

              -

              This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

              -
              - -Expand source code -Browse git - -
              @property
              -def inv(self):
              -    return InvertibleMatrixProduct(
              -        tuple(matrix.inv for matrix in reversed(self.matrices)))
              -
              -
              var log_abs_det

              Logarithm of absolute value of determinant of matrix.

              @@ -3744,10 +4064,6 @@

              Instance variables

              logarithm of the density of then Riemannian measure associated with metric with respect to the Lebesgue measure.

              -
              var T
              -
              -

              Transpose of matrix.

              -
              var array

              Full dense representation of matrix as a 2D array.

              @@ -3759,10 +4075,26 @@

              Instance variables

              Shape of matrix as a tuple (num_rows, num_columns).

              +
              var transpose
              +
              +

              Transpose of matrix.

              +
              +
              var T
              +
              +

              Transpose of matrix.

              +
              var diagonal

              Diagonal of matrix as a 1D array.

              +
              var inv
              +
              +

              Inverse of matrix as a Matrix object.

              +

              This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

              +
              @@ -3779,7 +4111,7 @@

              Args

              Expand source code -Browse git +Browse git
              class SymmetricMatrix(SquareMatrix):
                   """Base class for square matrices which are equal to their transpose."""
              @@ -3809,8 +4141,7 @@ 

              Args

              self._compute_eigendecomposition() return self._eigvec - @property - def T(self): + def _construct_transpose(self): return self @property @@ -3841,7 +4172,7 @@

              Instance variables

              Expand source code -Browse git +Browse git
              @property
               def eigval(self):
              @@ -3857,7 +4188,7 @@ 

              Instance variables

              Expand source code -Browse git +Browse git
              @property
               def eigvec(self):
              @@ -3867,19 +4198,6 @@ 

              Instance variables

              return self._eigvec
              -
              var T
              -
              -

              Transpose of matrix.

              -
              - -Expand source code -Browse git - -
              @property
              -def T(self):
              -    return self
              -
              -
              var log_abs_det

              Logarithm of absolute value of determinant of matrix.

              @@ -3889,7 +4207,7 @@

              Instance variables

              Expand source code -Browse git +Browse git
              @property
               def log_abs_det(self):
              @@ -3902,7 +4220,15 @@ 

              Instance variables

              var array
              -

              Full dense representation of matrix as a 2D array.

              +

              Full dense representation of matrix as a 2D array.

              +
              +
              var transpose
              +
              +

              Transpose of matrix.

              +
              +
              var T
              +
              +

              Transpose of matrix.

              var diagonal
              @@ -3924,18 +4250,33 @@

              Args

              Expand source code -Browse git +Browse git
              class PositiveDefiniteMatrix(SymmetricMatrix, InvertibleMatrix):
                   """Base class for positive definite matrices."""
               
                   _required_subclass_attrs = {'sqrt'}
               
              +    def __init__(self, shape, **kwargs):
              +        self._sqrt = None
              +        super().__init__(shape, **kwargs)
              +
                   @property
              -    @abc.abstractmethod
                   def sqrt(self):
                       """Square-root of matrix satisfying `matrix == sqrt @ sqrt.T`.
               
              +        This will in general not correspond to the unique, if defined,
              +        symmetric square root of a symmetric matrix but instead may return any
              +        matrix satisfying the above property.
              +        """
              +        if self._sqrt is None:
              +            self._sqrt = self._construct_sqrt()
              +        return self._sqrt
              +
              +    @abc.abstractmethod
              +    def _construct_sqrt(self):
              +        """Construct qquare-root of matrix satisfying `matrix == sqrt @ sqrt.T`.
              +
                       This will in general not correspond to the unique, if defined,
                       symmetric square root of a symmetric matrix but instead may return any
                       matrix satisfying the above property.
              @@ -3971,17 +4312,19 @@ 

              Instance variables

              Expand source code -Browse git +Browse git
              @property
              -@abc.abstractmethod
               def sqrt(self):
                   """Square-root of matrix satisfying `matrix == sqrt @ sqrt.T`.
               
                   This will in general not correspond to the unique, if defined,
                   symmetric square root of a symmetric matrix but instead may return any
                   matrix satisfying the above property.
              -    """
              + """ + if self._sqrt is None: + self._sqrt = self._construct_sqrt() + return self._sqrt
              var eigval
              @@ -3992,10 +4335,6 @@

              Instance variables

              Eigenvectors of matrix stacked as columns of a Matrix object.

              -
              var T
              -
              -

              Transpose of matrix.

              -
              var log_abs_det

              Logarithm of absolute value of determinant of matrix.

              @@ -4011,6 +4350,14 @@

              Instance variables

              Full dense representation of matrix as a 2D array.

              +
              var transpose
              +
              +

              Transpose of matrix.

              +
              +
              var T
              +
              +

              Transpose of matrix.

              +
              var diagonal

              Diagonal of matrix as a 1D array.

              @@ -4044,7 +4391,7 @@

              Args

              Expand source code -Browse git +Browse git
              class IdentityMatrix(PositiveDefiniteMatrix, ImplicitArrayMatrix):
                   """Matrix representing identity operator on a vector space.
              @@ -4080,16 +4427,14 @@ 

              Args

              def eigval(self): return self.diagonal - @property - def sqrt(self): + def _construct_sqrt(self): return self @property def eigvec(self): return self - @property - def inv(self): + def _construct_inv(self): return self @property @@ -4131,66 +4476,33 @@

              Instance variables

              Expand source code -Browse git +Browse git
              @property
               def eigval(self):
                   return self.diagonal
              -
              var sqrt
              -
              -

              Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

              -

              This will in general not correspond to the unique, if defined, -symmetric square root of a symmetric matrix but instead may return any -matrix satisfying the above property.

              -
              - -Expand source code -Browse git - -
              @property
              -def sqrt(self):
              -    return self
              -
              -
              var eigvec

              Eigenvectors of matrix stacked as columns of a Matrix object.

              Expand source code -Browse git +Browse git
              @property
               def eigvec(self):
                   return self
              -
              var inv
              -
              -

              Inverse of matrix as a Matrix object.

              -

              This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

              -
              - -Expand source code -Browse git - -
              @property
              -def inv(self):
              -    return self
              -
              -
              var diagonal

              Diagonal of matrix as a 1D array.

              Expand source code -Browse git +Browse git
              @property
               def diagonal(self):
              @@ -4206,16 +4518,19 @@ 

              Instance variables

              Expand source code -Browse git +Browse git
              @property
               def log_abs_det(self):
                   return 0.
              -
              var T
              +
              var sqrt
              -

              Transpose of matrix.

              +

              Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

              +

              This will in general not correspond to the unique, if defined, +symmetric square root of a symmetric matrix but instead may return any +matrix satisfying the above property.

              var shape
              @@ -4225,6 +4540,22 @@

              Instance variables

              Full dense representation of matrix as a 2D array.

              +
              var transpose
              +
              +

              Transpose of matrix.

              +
              +
              var T
              +
              +

              Transpose of matrix.

              +
              +
              var inv
              +
              +

              Inverse of matrix as a Matrix object.

              +

              This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

              +
              @@ -4257,7 +4588,7 @@

              Args

              Expand source code -Browse git +Browse git
              class DifferentiableMatrix(InvertibleMatrix):
                   """Parameterically defined matrix defining gradient of scalar operations.
              @@ -4312,7 +4643,7 @@ 

              Subclasses

            • DiagonalMatrix
            • TriangularFactoredDefiniteMatrix
            • DenseDefiniteMatrix
            • -
            • SoftAbsRegularisedPositiveDefiniteMatrix
            • +
            • SoftAbsRegularizedPositiveDefiniteMatrix
            • PositiveDefiniteBlockDiagonalMatrix
            • PositiveDefiniteLowRankUpdateMatrix
            @@ -4324,7 +4655,7 @@

            Instance variables

            Expand source code -Browse git +Browse git
            @property
             @abc.abstractmethod
            @@ -4355,6 +4686,10 @@ 

            Instance variables

            Full dense representation of matrix as a 2D array.

            +
            var transpose
            +
            +

            Transpose of matrix.

            +
            var T

            Transpose of matrix.

            @@ -4380,7 +4715,7 @@

            Args

            Expand source code -Browse git +Browse git
            @abc.abstractmethod
             def grad_quadratic_form_inv(self, vector):
            @@ -4417,7 +4752,7 @@ 

            Args

            Expand source code -Browse git +Browse git
            class ScaledIdentityMatrix(
                     SymmetricMatrix, DifferentiableMatrix, ImplicitArrayMatrix):
            @@ -4465,8 +4800,7 @@ 

            Args

            def eigvec(self): return IdentityMatrix(self.shape[0]) - @property - def inv(self): + def _construct_inv(self): return ScaledIdentityMatrix(1 / self._scalar, self.shape[0]) @property @@ -4526,7 +4860,7 @@

            Instance variables

            Expand source code -Browse git +Browse git
            @property
             def scalar(self):
            @@ -4540,7 +4874,7 @@ 

            Instance variables

            Expand source code -Browse git +Browse git
            @property
             def eigval(self):
            @@ -4553,37 +4887,20 @@ 

            Instance variables

            Expand source code -Browse git +Browse git
            @property
             def eigvec(self):
                 return IdentityMatrix(self.shape[0])
            -
            var inv
            -
            -

            Inverse of matrix as a Matrix object.

            -

            This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

            -
            - -Expand source code -Browse git - -
            @property
            -def inv(self):
            -    return ScaledIdentityMatrix(1 / self._scalar, self.shape[0])
            -
            -
            var diagonal

            Diagonal of matrix as a 1D array.

            Expand source code -Browse git +Browse git
            @property
             def diagonal(self):
            @@ -4599,7 +4916,7 @@ 

            Instance variables

            Expand source code -Browse git +Browse git
            @property
             def log_abs_det(self):
            @@ -4616,17 +4933,13 @@ 

            Instance variables

            Expand source code -Browse git +Browse git
            @property
             def grad_log_abs_det(self):
                 return self.shape[0] / self._scalar
            -
            var T
            -
            -

            Transpose of matrix.

            -
            var shape

            Shape of matrix as a tuple (num_rows, num_columns).

            @@ -4635,6 +4948,22 @@

            Instance variables

            Full dense representation of matrix as a 2D array.

            +
            var transpose
            +
            +

            Transpose of matrix.

            +
            +
            var T
            +
            +

            Transpose of matrix.

            +
            +
            var inv
            +
            +

            Inverse of matrix as a Matrix object.

            +

            This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

            +

            Methods

            @@ -4652,7 +4981,7 @@

            Args

            Expand source code -Browse git +Browse git
            def grad_quadratic_form_inv(self, vector):
                 return -np.sum(vector**2) / self._scalar**2
            @@ -4680,7 +5009,7 @@

            Args

            Expand source code -Browse git +Browse git
            class PositiveScaledIdentityMatrix(
                     ScaledIdentityMatrix, PositiveDefiniteMatrix):
            @@ -4701,12 +5030,10 @@ 

            Args

            else: return super()._scalar_multiply(scalar) - @property - def inv(self): + def _construct_inv(self): return PositiveScaledIdentityMatrix(1 / self._scalar, self.shape[0]) - @property - def sqrt(self): + def _construct_sqrt(self): return PositiveScaledIdentityMatrix(self._scalar**0.5, self.shape[0])

            Ancestors

            @@ -4723,39 +5050,6 @@

            Ancestors

          Instance variables

          -
          var inv
          -
          -

          Inverse of matrix as a Matrix object.

          -

          This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

          -
          - -Expand source code -Browse git - -
          @property
          -def inv(self):
          -    return PositiveScaledIdentityMatrix(1 / self._scalar, self.shape[0])
          -
          -
          -
          var sqrt
          -
          -

          Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

          -

          This will in general not correspond to the unique, if defined, -symmetric square root of a symmetric matrix but instead may return any -matrix satisfying the above property.

          -
          - -Expand source code -Browse git - -
          @property
          -def sqrt(self):
          -    return PositiveScaledIdentityMatrix(self._scalar**0.5, self.shape[0])
          -
          -
          var scalar

          Scalar multiplier.

          @@ -4783,10 +5077,6 @@

          Instance variables

          Gradient of logarithm of absolute value of determinant of matrix.

          -
          var T
          -
          -

          Transpose of matrix.

          -
          var shape

          Shape of matrix as a tuple (num_rows, num_columns).

          @@ -4795,6 +5085,29 @@

          Instance variables

          Full dense representation of matrix as a 2D array.

          +
          var transpose
          +
          +

          Transpose of matrix.

          +
          +
          var T
          +
          +

          Transpose of matrix.

          +
          +
          var inv
          +
          +

          Inverse of matrix as a Matrix object.

          +

          This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

          +
          +
          var sqrt
          +
          +

          Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

          +

          This will in general not correspond to the unique, if defined, +symmetric square root of a symmetric matrix but instead may return any +matrix satisfying the above property.

          +

          Methods

          @@ -4826,7 +5139,7 @@

          Args

          Expand source code -Browse git +Browse git
          class DiagonalMatrix(
                   SymmetricMatrix, DifferentiableMatrix, ImplicitArrayMatrix):
          @@ -4869,8 +5182,7 @@ 

          Args

          def eigval(self): return self.diagonal - @property - def inv(self): + def _construct_inv(self): return DiagonalMatrix(1. / self.diagonal) def _construct_array(self): @@ -4911,7 +5223,7 @@

          Instance variables

          Expand source code -Browse git +Browse git
          @property
           def diagonal(self):
          @@ -4924,7 +5236,7 @@ 

          Instance variables

          Expand source code -Browse git +Browse git
          @property
           def eigvec(self):
          @@ -4937,47 +5249,26 @@ 

          Instance variables

          Expand source code -Browse git +Browse git
          @property
           def eigval(self):
               return self.diagonal
          -
          var inv
          -
          -

          Inverse of matrix as a Matrix object.

          -

          This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

          -
          - -Expand source code -Browse git - -
          @property
          -def inv(self):
          -    return DiagonalMatrix(1. / self.diagonal)
          -
          -
          var grad_log_abs_det

          Gradient of logarithm of absolute value of determinant of matrix.

          Expand source code -Browse git +Browse git
          @property
           def grad_log_abs_det(self):
               return 1. / self.diagonal
          -
          var T
          -
          -

          Transpose of matrix.

          -
          var log_abs_det

          Logarithm of absolute value of determinant of matrix.

          @@ -4993,6 +5284,22 @@

          Instance variables

          Full dense representation of matrix as a 2D array.

          +
          var transpose
          +
          +

          Transpose of matrix.

          +
          +
          var T
          +
          +

          Transpose of matrix.

          +
          +
          var inv
          +
          +

          Inverse of matrix as a Matrix object.

          +

          This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

          +

          Methods

          @@ -5010,7 +5317,7 @@

          Args

          Expand source code -Browse git +Browse git
          def grad_quadratic_form_inv(self, vector):
               return -(self.inv @ vector)**2
          @@ -5033,7 +5340,7 @@

          Args

          Expand source code -Browse git +Browse git
          class PositiveDiagonalMatrix(DiagonalMatrix, PositiveDefiniteMatrix):
               """Specialisation of `DiagonalMatrix` with positive diagonal parameter.
          @@ -5052,12 +5359,10 @@ 

          Args

          else: return super()._scalar_multiply(scalar) - @property - def inv(self): + def _construct_inv(self): return PositiveDiagonalMatrix(1. / self.diagonal) - @property - def sqrt(self): + def _construct_sqrt(self): return PositiveDiagonalMatrix(self.diagonal**0.5)

          Ancestors

          @@ -5069,44 +5374,11 @@

          Ancestors

        • InvertibleMatrix
        • SquareMatrix
        • ImplicitArrayMatrix
        • -
        • Matrix
        • -
        • abc.ABC
        • -
        -

        Instance variables

        -
        -
        var inv
        -
        -

        Inverse of matrix as a Matrix object.

        -

        This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

        -
        - -Expand source code -Browse git - -
        @property
        -def inv(self):
        -    return PositiveDiagonalMatrix(1. / self.diagonal)
        -
        -
        -
        var sqrt
        -
        -

        Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

        -

        This will in general not correspond to the unique, if defined, -symmetric square root of a symmetric matrix but instead may return any -matrix satisfying the above property.

        -
        - -Expand source code -Browse git - -
        @property
        -def sqrt(self):
        -    return PositiveDiagonalMatrix(self.diagonal**0.5)
        -
        -
        +
      • Matrix
      • +
      • abc.ABC
      • +
      +

      Instance variables

      +
      var diagonal

      Diagonal of matrix as a 1D array.

      @@ -5123,10 +5395,6 @@

      Instance variables

      Gradient of logarithm of absolute value of determinant of matrix.

      -
      var T
      -
      -

      Transpose of matrix.

      -
      var log_abs_det

      Logarithm of absolute value of determinant of matrix.

      @@ -5142,6 +5410,29 @@

      Instance variables

      Full dense representation of matrix as a 2D array.

      +
      var transpose
      +
      +

      Transpose of matrix.

      +
      +
      var T
      +
      +

      Transpose of matrix.

      +
      +
      var inv
      +
      +

      Inverse of matrix as a Matrix object.

      +

      This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

      +
      +
      var sqrt
      +
      +

      Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

      +

      This will in general not correspond to the unique, if defined, +symmetric square root of a symmetric matrix but instead may return any +matrix satisfying the above property.

      +

      Methods

      @@ -5161,7 +5452,7 @@

      Args

      class TriangularMatrix -(array, lower=True) +(array, lower=True, make_triangular=True)

      Matrix with non-zero values only in lower or upper triangle elements.

      @@ -5175,16 +5466,20 @@

      Args

      lower : bool
      Whether the matrix is lower-triangular (True) or upper-triangular (False).
      +
      make_triangular : bool
      +
      Whether to ensure array is triangular +by explicitly zeroing entries in upper triangle if +lower == True and in lower triangle if lower == False.
      Expand source code -Browse git +Browse git
      class TriangularMatrix(InvertibleMatrix, ExplicitArrayMatrix):
           """Matrix with non-zero values only in lower or upper triangle elements."""
       
      -    def __init__(self, array, lower=True):
      +    def __init__(self, array, lower=True, make_triangular=True):
               """
               Args:
                   array (array): 2D array containing lower / upper triangular element
      @@ -5193,25 +5488,30 @@ 

      Args

      `lower == True` (`lower == False`). lower (bool): Whether the matrix is lower-triangular (`True`) or upper-triangular (`False`). + make_triangular (bool): Whether to ensure `array` is triangular + by explicitly zeroing entries in upper triangle if + `lower == True` and in lower triangle if `lower == False`. """ - super().__init__( - array.shape, _array=_make_array_triangular(array, lower)) + array = ( + _make_array_triangular(array, lower) if make_triangular else array) + super().__init__(array.shape, _array=array) self._lower = lower def _scalar_multiply(self, scalar): - return TriangularMatrix(self.array * scalar, self.lower) + return TriangularMatrix( + self.array * scalar, self.lower, make_triangular=False) @property def lower(self): return self._lower - @property - def inv(self): - return InverseTriangularMatrix(self.array, lower=self.lower) + def _construct_inv(self): + return InverseTriangularMatrix( + self.array, lower=self.lower, make_triangular=False) - @property - def T(self): - return TriangularMatrix(self.array.T, lower=not self.lower) + def _construct_transpose(self): + return TriangularMatrix( + self.array.T, lower=not self.lower, make_triangular=False) @property def log_abs_det(self): @@ -5236,43 +5536,13 @@

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def lower(self):
           return self._lower
      -
      var inv
      -
      -

      Inverse of matrix as a Matrix object.

      -

      This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

      -
      - -Expand source code -Browse git - -
      @property
      -def inv(self):
      -    return InverseTriangularMatrix(self.array, lower=self.lower)
      -
      -
      -
      var T
      -
      -

      Transpose of matrix.

      -
      - -Expand source code -Browse git - -
      @property
      -def T(self):
      -    return TriangularMatrix(self.array.T, lower=not self.lower)
      -
      -
      var log_abs_det

      Logarithm of absolute value of determinant of matrix.

      @@ -5282,13 +5552,21 @@

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def log_abs_det(self):
           return np.log(np.abs(self.diagonal)).sum()
      +
      var inv
      +
      +

      Inverse of matrix as a Matrix object.

      +

      This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

      +
      var shape

      Shape of matrix as a tuple (num_rows, num_columns).

      @@ -5297,6 +5575,14 @@

      Instance variables

      Full dense representation of matrix as a 2D array.

      +
      var transpose
      +
      +

      Transpose of matrix.

      +
      +
      var T
      +
      +

      Transpose of matrix.

      +
      var diagonal

      Diagonal of matrix as a 1D array.

      @@ -5305,7 +5591,7 @@

      Instance variables

      class InverseTriangularMatrix -(inverse_array, lower=True) +(inverse_array, lower=True, make_triangular=True)

      Triangular matrix implicitly specified by its inverse.

      @@ -5320,16 +5606,20 @@

      Args

      lower : bool
      Whether the matrix is lower-triangular (True) or upper-triangular (False).
      +
      make_triangular : bool
      +
      Whether to ensure inverse_array is +triangular by explicitly zeroing entries in upper triangle if +lower == True and in lower triangle if lower == False.
      Expand source code -Browse git +Browse git
      class InverseTriangularMatrix(InvertibleMatrix, ImplicitArrayMatrix):
           """Triangular matrix implicitly specified by its inverse."""
       
      -    def __init__(self, inverse_array, lower=True):
      +    def __init__(self, inverse_array, lower=True, make_triangular=True):
               """
               Args:
                   inverse_array (array): 2D containing values of *inverse* of this
      @@ -5339,39 +5629,47 @@ 

      Args

      when `lower == True` (`lower == False`). lower (bool): Whether the matrix is lower-triangular (`True`) or upper-triangular (`False`). - """ - super().__init__( - inverse_array.shape, - _inverse_array=_make_array_triangular(inverse_array, lower)) + make_triangular (bool): Whether to ensure `inverse_array` is + triangular by explicitly zeroing entries in upper triangle if + `lower == True` and in lower triangle if `lower == False`. + """ + inverse_array = np.asarray_chkfinite(inverse_array) + inverse_array = ( + _make_array_triangular(inverse_array, lower) if make_triangular + else inverse_array) + super().__init__(inverse_array.shape, _inverse_array=inverse_array) self._lower = lower def _scalar_multiply(self, scalar): return InverseTriangularMatrix( - self._inverse_array / scalar, self.lower) + self._inverse_array / scalar, self.lower, make_triangular=False) def _left_matrix_multiply(self, other): return sla.solve_triangular( - self._inverse_array, other, lower=self.lower) + self._inverse_array, other, lower=self.lower, check_finite=False) def _right_matrix_multiply(self, other): return sla.solve_triangular( - self._inverse_array, other.T, lower=self.lower, trans=1).T + self._inverse_array, other.T, lower=self.lower, trans=1, + check_finite=False).T @property def lower(self): return self._lower - @property - def inv(self): - return TriangularMatrix(self._inverse_array, lower=self.lower) + def _construct_inv(self): + return TriangularMatrix( + self._inverse_array, lower=self.lower, make_triangular=False) - @property - def T(self): + def _construct_transpose(self): return InverseTriangularMatrix( - self._inverse_array.T, lower=not self.lower) + self._inverse_array.T, lower=not self.lower, make_triangular=False) def _construct_array(self): - return self @ np.identity(self.shape[0]) + #return self @ np.identity(self.shape[0]) + return sla.solve_triangular( + self._inverse_array, np.identity(self.shape[0]), lower=self.lower, + check_finite=False) @property def diagonal(self): @@ -5406,51 +5704,20 @@

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def lower(self):
           return self._lower
      -
      var inv
      -
      -

      Inverse of matrix as a Matrix object.

      -

      This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

      -
      - -Expand source code -Browse git - -
      @property
      -def inv(self):
      -    return TriangularMatrix(self._inverse_array, lower=self.lower)
      -
      -
      -
      var T
      -
      -

      Transpose of matrix.

      -
      - -Expand source code -Browse git - -
      @property
      -def T(self):
      -    return InverseTriangularMatrix(
      -        self._inverse_array.T, lower=not self.lower)
      -
      -
      var diagonal

      Diagonal of matrix as a 1D array.

      Expand source code -Browse git +Browse git
      @property
       def diagonal(self):
      @@ -5466,13 +5733,21 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def log_abs_det(self):
           return -self.inv.log_abs_det
      +
      var inv
      +
      +

      Inverse of matrix as a Matrix object.

      +

      This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

      +
      var shape

      Shape of matrix as a tuple (num_rows, num_columns).

      @@ -5481,6 +5756,14 @@

      Instance variables

      Full dense representation of matrix as a 2D array.

      +
      var transpose
      +
      +

      Transpose of matrix.

      +
      +
      var T
      +
      +

      Transpose of matrix.

      +
      @@ -5519,7 +5802,7 @@

      Args

      Expand source code -Browse git +Browse git
      class TriangularFactoredDefiniteMatrix(
               _BaseTriangularFactoredDefiniteMatrix, DifferentiableMatrix,
      @@ -5617,7 +5900,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def grad_log_abs_det(self):
      @@ -5632,10 +5915,6 @@ 

      Instance variables

      Eigenvectors of matrix stacked as columns of a Matrix object.

      -
      var T
      -
      -

      Transpose of matrix.

      -
      var log_abs_det

      Logarithm of absolute value of determinant of matrix.

      @@ -5651,6 +5930,14 @@

      Instance variables

      Full dense representation of matrix as a 2D array.

      +
      var transpose
      +
      +

      Transpose of matrix.

      +
      +
      var T
      +
      +

      Transpose of matrix.

      +
      var diagonal

      Diagonal of matrix as a 1D array.

      @@ -5680,7 +5967,7 @@

      Args

      Expand source code -Browse git +Browse git
      def grad_quadratic_form_inv(self, vector):
           inv_factor_vector = self.factor.inv @ vector
      @@ -5697,7 +5984,7 @@ 

      Args

      (factor, factor_is_lower=True)
      -

      Positive definite matrix parameterised a triangular matrix product.

      +

      Positive definite matrix parametrized a triangular matrix product.

      The matrix is assumed to have the parameterisation

      matrix = factor @ factor.T
       
      @@ -5723,11 +6010,11 @@

      Args

      Expand source code -Browse git +Browse git
      class TriangularFactoredPositiveDefiniteMatrix(
               TriangularFactoredDefiniteMatrix, PositiveDefiniteMatrix):
      -    """Positive definite matrix parameterised a triangular matrix product.
      +    """Positive definite matrix parametrized a triangular matrix product.
       
           The matrix is assumed to have the parameterisation
       
      @@ -5762,13 +6049,11 @@ 

      Args

      else: return super()._scalar_multiply(scalar) - @property - def inv(self): + def _construct_inv(self): return TriangularFactoredPositiveDefiniteMatrix( factor=self.factor.inv.T) - @property - def sqrt(self): + def _construct_sqrt(self): return self.factor

      Ancestors

      @@ -5786,40 +6071,6 @@

      Ancestors

    Instance variables

    -
    var inv
    -
    -

    Inverse of matrix as a Matrix object.

    -

    This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

    -
    - -Expand source code -Browse git - -
    @property
    -def inv(self):
    -    return TriangularFactoredPositiveDefiniteMatrix(
    -        factor=self.factor.inv.T)
    -
    -
    -
    var sqrt
    -
    -

    Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

    -

    This will in general not correspond to the unique, if defined, -symmetric square root of a symmetric matrix but instead may return any -matrix satisfying the above property.

    -
    - -Expand source code -Browse git - -
    @property
    -def sqrt(self):
    -    return self.factor
    -
    -
    var grad_log_abs_det

    Gradient of logarithm of absolute value of determinant of matrix.

    @@ -5832,10 +6083,6 @@

    Instance variables

    Eigenvectors of matrix stacked as columns of a Matrix object.

    -
    var T
    -
    -

    Transpose of matrix.

    -
    var log_abs_det

    Logarithm of absolute value of determinant of matrix.

    @@ -5851,10 +6098,33 @@

    Instance variables

    Full dense representation of matrix as a 2D array.

    +
    var transpose
    +
    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    +
    var diagonal

    Diagonal of matrix as a 1D array.

    +
    var inv
    +
    +

    Inverse of matrix as a Matrix object.

    +

    This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

    +
    +
    var sqrt
    +
    +

    Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

    +

    This will in general not correspond to the unique, if defined, +symmetric square root of a symmetric matrix but instead may return any +matrix satisfying the above property.

    +

    Methods

    @@ -5898,12 +6168,12 @@

    Args

    initialisation, and so if array is positive (negative) definite and is_posdef is False (True) then a LinAlgError exception will be if a later attempt is made to -factorise the matrix. +factorize the matrix.
    Expand source code -Browse git +Browse git
    class DenseDefiniteMatrix(_BaseTriangularFactoredDefiniteMatrix,
                               DifferentiableMatrix, ExplicitArrayMatrix):
    @@ -5926,7 +6196,7 @@ 

    Args

    initialisation, and so if `array` is positive (negative) definite and `is_posdef` is `False` (`True`) then a `LinAlgError` exception will be if a later attempt is made to - factorise the matrix. + factorize the matrix. """ super().__init__( array.shape[0], sign=1 if is_posdef else -1, _array=array) @@ -5949,7 +6219,8 @@

    Args

    if self._factor is None: try: self._factor = TriangularMatrix( - nla.cholesky(self._sign * self._array), lower=True) + nla.cholesky(self._sign * self._array), lower=True, + make_triangular=False) except nla.LinAlgError as e: raise LinAlgError('Cholesky factorisation failed.') from e return self._factor @@ -5960,7 +6231,12 @@

    Args

    def grad_quadratic_form_inv(self, vector): inv_matrix_vector = self.inv @ vector - return -np.outer(inv_matrix_vector, inv_matrix_vector)
    + return -np.outer(inv_matrix_vector, inv_matrix_vector) + + def _construct_inv(self): + return DenseDefiniteMatrix( + super()._construct_inv().array, factor=self.factor.inv.T, + is_posdef=(self._sign == 1))

    Ancestors

      @@ -5985,14 +6261,15 @@

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def factor(self):
           if self._factor is None:
               try:
                   self._factor = TriangularMatrix(
      -                nla.cholesky(self._sign * self._array), lower=True)
      +                nla.cholesky(self._sign * self._array), lower=True, 
      +                make_triangular=False)
               except nla.LinAlgError as e:
                   raise LinAlgError('Cholesky factorisation failed.') from e
           return self._factor
      @@ -6004,7 +6281,7 @@

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def grad_log_abs_det(self):
      @@ -6019,10 +6296,6 @@ 

      Instance variables

      Eigenvectors of matrix stacked as columns of a Matrix object.

      -
      var T
      -
      -

      Transpose of matrix.

      -
      var log_abs_det

      Logarithm of absolute value of determinant of matrix.

      @@ -6038,6 +6311,14 @@

      Instance variables

      Full dense representation of matrix as a 2D array.

      +
      var transpose
      +
      +

      Transpose of matrix.

      +
      +
      var T
      +
      +

      Transpose of matrix.

      +
      var diagonal

      Diagonal of matrix as a 1D array.

      @@ -6067,7 +6348,7 @@

      Args

      Expand source code -Browse git +Browse git
      def grad_quadratic_form_inv(self, vector):
           inv_matrix_vector = self.inv @ vector
      @@ -6098,7 +6379,7 @@ 

      Args

      Expand source code -Browse git +Browse git
      class DensePositiveDefiniteMatrix(DenseDefiniteMatrix, PositiveDefiniteMatrix):
           """Positive-definite matrix specified by a dense 2D array."""
      @@ -6116,13 +6397,11 @@ 

      Args

      """ super().__init__(array=array, factor=factor, is_posdef=True) - @property - def inv(self): - return TriangularFactoredPositiveDefiniteMatrix( - factor=self.factor.inv.T) + def _construct_inv(self): + return DensePositiveDefiniteMatrix( + super()._construct_inv(), factor=self.factor.inv.T) - @property - def sqrt(self): + def _construct_sqrt(self): return self.factor

      Ancestors

      @@ -6130,54 +6409,20 @@

      Ancestors

    • DenseDefiniteMatrix
    • mici.matrices._BaseTriangularFactoredDefiniteMatrix
    • PositiveDefiniteMatrix
    • -
    • SymmetricMatrix
    • -
    • DifferentiableMatrix
    • -
    • InvertibleMatrix
    • -
    • SquareMatrix
    • -
    • ExplicitArrayMatrix
    • -
    • Matrix
    • -
    • abc.ABC
    • -
    -

    Subclasses

    - -

    Instance variables

    -
    -
    var inv
    -
    -

    Inverse of matrix as a Matrix object.

    -

    This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

    -
    - -Expand source code -Browse git - -
    @property
    -def inv(self):
    -    return TriangularFactoredPositiveDefiniteMatrix(
    -        factor=self.factor.inv.T)
    -
    -
    -
    var sqrt
    -
    -

    Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

    -

    This will in general not correspond to the unique, if defined, -symmetric square root of a symmetric matrix but instead may return any -matrix satisfying the above property.

    -
    - -Expand source code -Browse git - -
    @property
    -def sqrt(self):
    -    return self.factor
    -
    -
    +
  • SymmetricMatrix
  • +
  • DifferentiableMatrix
  • +
  • InvertibleMatrix
  • +
  • SquareMatrix
  • +
  • ExplicitArrayMatrix
  • +
  • Matrix
  • +
  • abc.ABC
  • + +

    Subclasses

    + +

    Instance variables

    +
    var factor

    Triangular matrix with matrix = sign * factor @ factor.T

    @@ -6194,10 +6439,6 @@

    Instance variables

    Eigenvectors of matrix stacked as columns of a Matrix object.

    -
    var T
    -
    -

    Transpose of matrix.

    -
    var log_abs_det

    Logarithm of absolute value of determinant of matrix.

    @@ -6213,10 +6454,33 @@

    Instance variables

    Full dense representation of matrix as a 2D array.

    +
    var transpose
    +
    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    +
    var diagonal

    Diagonal of matrix as a 1D array.

    +
    var inv
    +
    +

    Inverse of matrix as a Matrix object.

    +

    This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

    +
    +
    var sqrt
    +
    +

    Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

    +

    This will in general not correspond to the unique, if defined, +symmetric square root of a symmetric matrix but instead may return any +matrix satisfying the above property.

    +

    Methods

    @@ -6263,7 +6527,7 @@

    Args

    Expand source code -Browse git +Browse git
    class DensePositiveDefiniteProductMatrix(DensePositiveDefiniteMatrix):
         """Positive-definite matrix specified as a signed symmetric product.
    @@ -6334,7 +6598,7 @@ 

    Instance variables

    Expand source code -Browse git +Browse git
    @property
     def grad_log_abs_det(self):
    @@ -6342,21 +6606,6 @@ 

    Instance variables

    self._rect_matrix.array @ self._pos_def_matrix))
    -
    var inv
    -
    -

    Inverse of matrix as a Matrix object.

    -

    This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

    -
    -
    var sqrt
    -
    -

    Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

    -

    This will in general not correspond to the unique, if defined, -symmetric square root of a symmetric matrix but instead may return any -matrix satisfying the above property.

    -
    var factor

    Triangular matrix with matrix = sign * factor @ factor.T

    @@ -6369,10 +6618,6 @@

    Instance variables

    Eigenvectors of matrix stacked as columns of a Matrix object.

    -
    var T
    -
    -

    Transpose of matrix.

    -
    var log_abs_det

    Logarithm of absolute value of determinant of matrix.

    @@ -6388,10 +6633,33 @@

    Instance variables

    Full dense representation of matrix as a 2D array.

    +
    var transpose
    +
    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    +
    var diagonal

    Diagonal of matrix as a 1D array.

    +
    var inv
    +
    +

    Inverse of matrix as a Matrix object.

    +

    This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

    +
    +
    var sqrt
    +
    +

    Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

    +

    This will in general not correspond to the unique, if defined, +symmetric square root of a symmetric matrix but instead may return any +matrix satisfying the above property.

    +

    Methods

    @@ -6409,7 +6677,7 @@

    Args

    Expand source code -Browse git +Browse git
    def grad_quadratic_form_inv(self, vector):
         inv_matrix_vector = self.inv @ vector
    @@ -6445,7 +6713,7 @@ 

    Args

    Expand source code -Browse git +Browse git
    class DenseSquareMatrix(InvertibleMatrix, ExplicitArrayMatrix):
         """Dense non-singular square matrix."""
    @@ -6482,7 +6750,7 @@ 

    Args

    def lu_and_piv(self): """Pivoted LU factorisation of matrix.""" if self._lu_and_piv is None: - self._lu_and_piv = sla.lu_factor(self._array) + self._lu_and_piv = sla.lu_factor(self._array, check_finite=False) self._lu_transposed = False return self._lu_and_piv @@ -6491,14 +6759,12 @@

    Args

    lu, piv = self.lu_and_piv return np.log(np.abs(lu.diagonal())).sum() - @property - def T(self): + def _construct_transpose(self): lu_and_piv = self.lu_and_piv return DenseSquareMatrix( self._array.T, lu_and_piv, not self._lu_transposed) - @property - def inv(self): + def _construct_inv(self): lu_and_piv = self.lu_and_piv return InverseLUFactoredSquareMatrix( self._array, lu_and_piv, self._lu_transposed)
    @@ -6519,13 +6785,13 @@

    Instance variables

    Expand source code -Browse git +Browse git
    @property
     def lu_and_piv(self):
         """Pivoted LU factorisation of matrix."""
         if self._lu_and_piv is None:
    -        self._lu_and_piv = sla.lu_factor(self._array)
    +        self._lu_and_piv = sla.lu_factor(self._array, check_finite=False)
             self._lu_transposed = False
         return self._lu_and_piv
    @@ -6539,7 +6805,7 @@

    Instance variables

    Expand source code -Browse git +Browse git
    @property
     def log_abs_det(self):
    @@ -6547,21 +6813,6 @@ 

    Instance variables

    return np.log(np.abs(lu.diagonal())).sum()
    -
    var T
    -
    -

    Transpose of matrix.

    -
    - -Expand source code -Browse git - -
    @property
    -def T(self):
    -    lu_and_piv = self.lu_and_piv
    -    return DenseSquareMatrix(
    -        self._array.T, lu_and_piv, not self._lu_transposed)
    -
    -
    var inv

    Inverse of matrix as a Matrix object.

    @@ -6569,17 +6820,6 @@

    Instance variables

    inverse matrix but may instead return a Matrix object that implements the matrix multiplication operators by solving the linear system defined by the original matrix object.

    -
    - -Expand source code -Browse git - -
    @property
    -def inv(self):
    -    lu_and_piv = self.lu_and_piv
    -    return InverseLUFactoredSquareMatrix(
    -        self._array, lu_and_piv, self._lu_transposed)
    -
    var shape
    @@ -6589,6 +6829,14 @@

    Instance variables

    Full dense representation of matrix as a 2D array.

    +
    var transpose
    +
    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    +
    var diagonal

    Diagonal of matrix as a 1D array.

    @@ -6620,7 +6868,7 @@

    Args

    Expand source code -Browse git +Browse git
    class InverseLUFactoredSquareMatrix(InvertibleMatrix, ImplicitArrayMatrix):
         """Square matrix implicitly defined by LU factorisation of inverse."""
    @@ -6654,11 +6902,13 @@ 

    Args

    def _left_matrix_multiply(self, other): return sla.lu_solve( - self._inv_lu_and_piv, other, self._inv_lu_transposed) + self._inv_lu_and_piv, other, self._inv_lu_transposed, + check_finite=False) def _right_matrix_multiply(self, other): return sla.lu_solve( - self._inv_lu_and_piv, other.T, not self._inv_lu_transposed).T + self._inv_lu_and_piv, other.T, not self._inv_lu_transposed, + check_finite=False).T @property def log_abs_det(self): @@ -6667,13 +6917,11 @@

    Args

    def _construct_array(self): return self @ np.identity(self.shape[0]) - @property - def inv(self): + def _construct_inv(self): return DenseSquareMatrix( self._inv_array, self._inv_lu_and_piv, self._inv_lu_transposed) - @property - def T(self): + def _construct_transpose(self): return InverseLUFactoredSquareMatrix( self._inv_array.T, self._inv_lu_and_piv, not self._inv_lu_transposed) @@ -6703,7 +6951,7 @@

    Instance variables

    Expand source code -Browse git +Browse git
    @property
     def log_abs_det(self):
    @@ -6717,31 +6965,6 @@ 

    Instance variables

    inverse matrix but may instead return a Matrix object that implements the matrix multiplication operators by solving the linear system defined by the original matrix object.

    -
    - -Expand source code -Browse git - -
    @property
    -def inv(self):
    -    return DenseSquareMatrix(
    -        self._inv_array, self._inv_lu_and_piv, self._inv_lu_transposed)
    -
    -
    -
    var T
    -
    -

    Transpose of matrix.

    -
    - -Expand source code -Browse git - -
    @property
    -def T(self):
    -    return InverseLUFactoredSquareMatrix(
    -        self._inv_array.T, self._inv_lu_and_piv,
    -        not self._inv_lu_transposed)
    -
    var shape
    @@ -6751,6 +6974,14 @@

    Instance variables

    Full dense representation of matrix as a 2D array.

    +
    var transpose
    +
    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    +
    var diagonal

    Diagonal of matrix as a 1D array.

    @@ -6782,7 +7013,7 @@

    Args

    Expand source code -Browse git +Browse git
    class DenseSymmetricMatrix(
             SymmetricMatrix, InvertibleMatrix, ExplicitArrayMatrix):
    @@ -6813,8 +7044,7 @@ 

    Args

    self.array * scalar, self._eigvec, None if self._eigval is None else self._eigval * scalar) - @property - def inv(self): + def _construct_inv(self): return EigendecomposedSymmetricMatrix(self.eigvec, 1 / self.eigval)

    Ancestors

    @@ -6828,23 +7058,6 @@

    Ancestors

    Instance variables

    -
    var inv
    -
    -

    Inverse of matrix as a Matrix object.

    -

    This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

    -
    - -Expand source code -Browse git - -
    @property
    -def inv(self):
    -    return EigendecomposedSymmetricMatrix(self.eigvec, 1 / self.eigval)
    -
    -
    var eigval

    Eigenvalues of matrix as a 1D array.

    @@ -6853,10 +7066,6 @@

    Instance variables

    Eigenvectors of matrix stacked as columns of a Matrix object.

    -
    var T
    -
    -

    Transpose of matrix.

    -
    var log_abs_det

    Logarithm of absolute value of determinant of matrix.

    @@ -6872,10 +7081,26 @@

    Instance variables

    Full dense representation of matrix as a 2D array.

    +
    var transpose
    +
    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    +
    var diagonal

    Diagonal of matrix as a 1D array.

    +
    var inv
    +
    +

    Inverse of matrix as a Matrix object.

    +

    This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

    +
    @@ -6892,7 +7117,7 @@

    Args

    Expand source code -Browse git +Browse git
    class OrthogonalMatrix(InvertibleMatrix, ExplicitArrayMatrix):
         """Square matrix with columns and rows that are orthogonal unit vectors."""
    @@ -6911,12 +7136,10 @@ 

    Args

    def log_abs_det(self): return 0 - @property - def T(self): + def _construct_transpose(self): return OrthogonalMatrix(self.array.T) - @property - def inv(self): + def _construct_inv(self): return self.T

    Ancestors

    @@ -6938,26 +7161,13 @@

    Instance variables

    Expand source code -Browse git +Browse git
    @property
     def log_abs_det(self):
         return 0
    -
    var T
    -
    -

    Transpose of matrix.

    -
    - -Expand source code -Browse git - -
    @property
    -def T(self):
    -    return OrthogonalMatrix(self.array.T)
    -
    -
    var inv

    Inverse of matrix as a Matrix object.

    @@ -6965,15 +7175,6 @@

    Instance variables

    inverse matrix but may instead return a Matrix object that implements the matrix multiplication operators by solving the linear system defined by the original matrix object.

    -
    - -Expand source code -Browse git - -
    @property
    -def inv(self):
    -    return self.T
    -
    var shape
    @@ -6983,6 +7184,14 @@

    Instance variables

    Full dense representation of matrix as a 2D array.

    +
    var transpose
    +
    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    +
    var diagonal

    Diagonal of matrix as a 1D array.

    @@ -7010,7 +7219,7 @@

    Args

    Expand source code -Browse git +Browse git
    class ScaledOrthogonalMatrix(InvertibleMatrix, ImplicitArrayMatrix):
         """Matrix corresponding to orthogonal matrix multiplied by a scalar.
    @@ -7052,12 +7261,10 @@ 

    Args

    def log_abs_det(self): return self.shape[0] * np.log(abs(self._scalar)) - @property - def T(self): + def _construct_transpose(self): return ScaledOrthogonalMatrix(self._scalar, self._orth_array.T) - @property - def inv(self): + def _construct_inv(self): return ScaledOrthogonalMatrix(1 / self._scalar, self._orth_array.T) def _compute_hash(self): @@ -7083,7 +7290,7 @@

    Instance variables

    Expand source code -Browse git +Browse git
    @property
     def diagonal(self):
    @@ -7099,26 +7306,13 @@ 

    Instance variables

    Expand source code -Browse git +Browse git
    @property
     def log_abs_det(self):
         return self.shape[0] * np.log(abs(self._scalar))
    -
    var T
    -
    -

    Transpose of matrix.

    -
    - -Expand source code -Browse git - -
    @property
    -def T(self):
    -    return ScaledOrthogonalMatrix(self._scalar, self._orth_array.T)
    -
    -
    var inv

    Inverse of matrix as a Matrix object.

    @@ -7126,15 +7320,6 @@

    Instance variables

    inverse matrix but may instead return a Matrix object that implements the matrix multiplication operators by solving the linear system defined by the original matrix object.

    -
    - -Expand source code -Browse git - -
    @property
    -def inv(self):
    -    return ScaledOrthogonalMatrix(1 / self._scalar, self._orth_array.T)
    -
    var shape
    @@ -7144,6 +7329,14 @@

    Instance variables

    Full dense representation of matrix as a 2D array.

    +
    var transpose
    +
    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    +
    @@ -7151,7 +7344,7 @@

    Instance variables

    (eigvec, eigval)
    -

    Symmetric matrix parameterised by its eigendecomposition.

    +

    Symmetric matrix parametrized by its eigendecomposition.

    The matrix is assumed to have the parameterisation

    matrix = eigvec @ diag(eigval) @ eigvec.T
     
    @@ -7173,11 +7366,11 @@

    Args

    Expand source code -Browse git +Browse git
    class EigendecomposedSymmetricMatrix(
             SymmetricMatrix, InvertibleMatrix, ImplicitArrayMatrix):
    -    """Symmetric matrix parameterised by its eigendecomposition.
    +    """Symmetric matrix parametrized by its eigendecomposition.
     
         The matrix is assumed to have the parameterisation
     
    @@ -7219,8 +7412,7 @@ 

    Args

    def _right_matrix_multiply(self, other): return ((other @ self.eigvec) @ self.diag_eigval) @ self.eigvec.T - @property - def inv(self): + def _construct_inv(self): return EigendecomposedSymmetricMatrix(self.eigvec, 1 / self.eigval) def _construct_array(self): @@ -7238,37 +7430,20 @@

    Args

    self.eigvec == other.eigvec)

    Ancestors

    - -

    Subclasses

    - -

    Instance variables

    -
    -
    var inv
    -
    -

    Inverse of matrix as a Matrix object.

    -

    This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

    -
    - -Expand source code -Browse git - -
    @property
    -def inv(self):
    -    return EigendecomposedSymmetricMatrix(self.eigvec, 1 / self.eigval)
    -
    -
    + +

    Subclasses

    + +

    Instance variables

    +
    var eigval

    Eigenvalues of matrix as a 1D array.

    @@ -7277,10 +7452,6 @@

    Instance variables

    Eigenvectors of matrix stacked as columns of a Matrix object.

    -
    var T
    -
    -

    Transpose of matrix.

    -
    var log_abs_det

    Logarithm of absolute value of determinant of matrix.

    @@ -7296,10 +7467,26 @@

    Instance variables

    Full dense representation of matrix as a 2D array.

    +
    var transpose
    +
    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    +
    var diagonal

    Diagonal of matrix as a 1D array.

    +
    var inv
    +
    +

    Inverse of matrix as a Matrix object.

    +

    This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

    +
    @@ -7307,7 +7494,7 @@

    Instance variables

    (eigvec, eigval)
    -

    Positive definite matrix parameterised by its eigendecomposition.

    +

    Positive definite matrix parametrized by its eigendecomposition.

    The matrix is assumed to have the parameterisation

    matrix = eigvec @ diag(eigval) @ eigvec.T
     
    @@ -7329,11 +7516,11 @@

    Args

    Expand source code -Browse git +Browse git
    class EigendecomposedPositiveDefiniteMatrix(
             EigendecomposedSymmetricMatrix, PositiveDefiniteMatrix):
    -    """Positive definite matrix parameterised by its eigendecomposition.
    +    """Positive definite matrix parametrized by its eigendecomposition.
     
         The matrix is assumed to have the parameterisation
     
    @@ -7356,13 +7543,11 @@ 

    Args

    else: return super()._scalar_multiply(scalar) - @property - def inv(self): + def _construct_inv(self): return EigendecomposedPositiveDefiniteMatrix( self.eigvec, 1 / self.eigval) - @property - def sqrt(self): + def _construct_sqrt(self): return EigendecomposedSymmetricMatrix(self.eigvec, self.eigval**0.5)

    Ancestors

    @@ -7378,44 +7563,10 @@

    Ancestors

    Subclasses

    Instance variables

    -
    var inv
    -
    -

    Inverse of matrix as a Matrix object.

    -

    This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

    -
    - -Expand source code -Browse git - -
    @property
    -def inv(self):
    -    return EigendecomposedPositiveDefiniteMatrix(
    -        self.eigvec, 1 / self.eigval)
    -
    -
    -
    var sqrt
    -
    -

    Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

    -

    This will in general not correspond to the unique, if defined, -symmetric square root of a symmetric matrix but instead may return any -matrix satisfying the above property.

    -
    - -Expand source code -Browse git - -
    @property
    -def sqrt(self):
    -    return EigendecomposedSymmetricMatrix(self.eigvec, self.eigval**0.5)
    -
    -
    var eigval

    Eigenvalues of matrix as a 1D array.

    @@ -7424,10 +7575,6 @@

    Instance variables

    Eigenvectors of matrix stacked as columns of a Matrix object.

    -
    var T
    -
    -

    Transpose of matrix.

    -
    var log_abs_det

    Logarithm of absolute value of determinant of matrix.

    @@ -7443,19 +7590,42 @@

    Instance variables

    Full dense representation of matrix as a 2D array.

    +
    var transpose
    +
    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    +
    var diagonal

    Diagonal of matrix as a 1D array.

    +
    var inv
    +
    +

    Inverse of matrix as a Matrix object.

    +

    This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

    +
    +
    var sqrt
    +
    +

    Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

    +

    This will in general not correspond to the unique, if defined, +symmetric square root of a symmetric matrix but instead may return any +matrix satisfying the above property.

    +
    -
    -class SoftAbsRegularisedPositiveDefiniteMatrix +
    +class SoftAbsRegularizedPositiveDefiniteMatrix (symmetric_array, softabs_coeff)

    Matrix transformed to be positive definite by regularising eigenvalues.

    -

    Matrix is parameterised by a symmetric array symmetric_array, of which an +

    Matrix is parametrized by a symmetric array symmetric_array, of which an eigendecomposition is formed eigvec, eigval = eigh(symmetric_array), with the output matrix then matrix = eigvec @ softabs(eigval) @ eigvec.T where softabs is a smooth approximation to the absolute function.

    @@ -7465,7 +7635,7 @@

    Args

    2D square array with symmetric values, i.e. symmetric_array[i, j] == symmetric_array[j, i] for all indices i and j which represents symmetric matrix to -form eigenvalue-regularised transformation of.
    +form eigenvalue-regularized transformation of.
    softabs_coeff : float
    Positive regularisation coefficient for smooth approximation to absolute value. As the value tends to @@ -7475,13 +7645,13 @@

    Args

    Expand source code -Browse git +Browse git -
    class SoftAbsRegularisedPositiveDefiniteMatrix(
    +
    class SoftAbsRegularizedPositiveDefiniteMatrix(
             EigendecomposedPositiveDefiniteMatrix, DifferentiableMatrix):
         """Matrix transformed to be positive definite by regularising eigenvalues.
     
    -    Matrix is parameterised by a symmetric array `symmetric_array`, of which an
    +    Matrix is parametrized by a symmetric array `symmetric_array`, of which an
         eigendecomposition is formed `eigvec, eigval = eigh(symmetric_array)`, with
         the output matrix then `matrix = eigvec @ softabs(eigval) @ eigvec.T`
         where `softabs` is a smooth approximation to the absolute function.
    @@ -7493,7 +7663,7 @@ 

    Args

    symmetric_array (array): 2D square array with symmetric values, i.e. `symmetric_array[i, j] == symmetric_array[j, i]` for all indices `i` and `j` which represents symmetric matrix to - form eigenvalue-regularised transformation of. + form eigenvalue-regularized transformation of. softabs_coeff (float): Positive regularisation coefficient for smooth approximation to absolute value. As the value tends to infinity the approximation becomes increasingly close to the @@ -7546,13 +7716,13 @@

    Ancestors

    Instance variables

    -
    var grad_log_abs_det
    +
    var grad_log_abs_det

    Gradient of logarithm of absolute value of determinant of matrix.

    Expand source code -Browse git +Browse git
    @property
     def grad_log_abs_det(self):
    @@ -7560,56 +7730,60 @@ 

    Instance variables

    return EigendecomposedSymmetricMatrix(self.eigvec, grad_eigval).array
    -
    var inv
    -
    -

    Inverse of matrix as a Matrix object.

    -

    This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

    -
    -
    var sqrt
    -
    -

    Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

    -

    This will in general not correspond to the unique, if defined, -symmetric square root of a symmetric matrix but instead may return any -matrix satisfying the above property.

    -
    -
    var eigval
    +
    var eigval

    Eigenvalues of matrix as a 1D array.

    -
    var eigvec
    +
    var eigvec

    Eigenvectors of matrix stacked as columns of a Matrix object.

    -
    var T
    -
    -

    Transpose of matrix.

    -
    -
    var log_abs_det
    +
    var log_abs_det

    Logarithm of absolute value of determinant of matrix.

    For matrix representations of metrics it is proportional to the logarithm of the density of then Riemannian measure associated with metric with respect to the Lebesgue measure.

    -
    var shape
    +
    var shape

    Shape of matrix as a tuple (num_rows, num_columns).

    -
    var array
    +
    var array

    Full dense representation of matrix as a 2D array.

    -
    var diagonal
    +
    var transpose
    +
    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    +
    +
    var diagonal

    Diagonal of matrix as a 1D array.

    +
    var inv
    +
    +

    Inverse of matrix as a Matrix object.

    +

    This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

    +
    +
    var sqrt
    +
    +

    Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

    +

    This will in general not correspond to the unique, if defined, +symmetric square root of a symmetric matrix but instead may return any +matrix satisfying the above property.

    +

    Methods

    -
    +
    def softabs(self, x)
    @@ -7617,14 +7791,14 @@

    Methods

    Expand source code -Browse git +Browse git
    def softabs(self, x):
         """Smooth approximation to absolute function."""
         return x / np.tanh(x * self._softabs_coeff)
    -
    +
    def grad_softabs(self, x)
    @@ -7632,7 +7806,7 @@

    Methods

    Expand source code -Browse git +Browse git
    def grad_softabs(self, x):
         """Derivative of smooth approximation to absolute function."""
    @@ -7641,7 +7815,7 @@ 

    Methods

    self._softabs_coeff * x / np.sinh(self._softabs_coeff * x)**2)
    -
    +
    def grad_quadratic_form_inv(self, vector)
    @@ -7655,7 +7829,7 @@

    Args

    Expand source code -Browse git +Browse git
    def grad_quadratic_form_inv(self, vector):
         num_j_mtx = self.eigval[:, None] - self.eigval[None, :]
    @@ -7684,7 +7858,7 @@ 

    Args

    Expand source code -Browse git +Browse git
    class BlockMatrix(ImplicitArrayMatrix):
         """Matrix with non-zero entries defined by a series of submatrix blocks."""
    @@ -7724,7 +7898,7 @@ 

    Instance variables

    Expand source code -Browse git +Browse git
    @property
     @abc.abstractmethod
    @@ -7743,6 +7917,10 @@ 

    Instance variables

    Shape of matrix as a tuple (num_rows, num_columns).

    +
    var transpose
    +
    +

    Transpose of matrix.

    +
    var T

    Transpose of matrix.

    @@ -7769,7 +7947,7 @@

    Args

    Expand source code -Browse git +Browse git
    class SquareBlockDiagonalMatrix(InvertibleMatrix, BlockMatrix):
         """Square matrix with non-zero values only in blocks along diagonal."""
    @@ -7816,22 +7994,19 @@ 

    Args

    def _construct_array(self): return sla.block_diag(*(block.array for block in self._blocks)) - @property - def T(self): + def _construct_transpose(self): return SquareBlockDiagonalMatrix( tuple(block.T for block in self._blocks)) - @property - def sqrt(self): + def _construct_sqrt(self): return SquareBlockDiagonalMatrix( tuple(block.sqrt for block in self._blocks)) @property - def diag(self): + def diagonal(self): return np.concatenate([block.diagonal() for block in self._blocks]) - @property - def inv(self): + def _construct_inv(self): return type(self)(tuple(block.inv for block in self._blocks)) @property @@ -7868,7 +8043,7 @@

    Instance variables

    Expand source code -Browse git +Browse git
    @property
     def blocks(self):
    @@ -7876,71 +8051,26 @@ 

    Instance variables

    return self._blocks
    -
    var T
    -
    -

    Transpose of matrix.

    -
    - -Expand source code -Browse git - -
    @property
    -def T(self):
    -    return SquareBlockDiagonalMatrix(
    -        tuple(block.T for block in self._blocks))
    -
    -
    -
    var sqrt
    -
    -
    -
    - -Expand source code -Browse git - -
    @property
    -def sqrt(self):
    -    return SquareBlockDiagonalMatrix(
    -        tuple(block.sqrt for block in self._blocks))
    -
    -
    -
    var diag
    +
    var diagonal
    -
    +

    Diagonal of matrix as a 1D array.

    Expand source code -Browse git +Browse git
    @property
    -def diag(self):
    +def diagonal(self):
         return np.concatenate([block.diagonal() for block in self._blocks])
    -
    var inv
    -
    -

    Inverse of matrix as a Matrix object.

    -

    This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

    -
    - -Expand source code -Browse git - -
    @property
    -def inv(self):
    -    return type(self)(tuple(block.inv for block in self._blocks))
    -
    -
    var eigval
    Expand source code -Browse git +Browse git
    @property
     def eigval(self):
    @@ -7953,7 +8083,7 @@ 

    Instance variables

    Expand source code -Browse git +Browse git
    @property
     def eigvec(self):
    @@ -7970,13 +8100,21 @@ 

    Instance variables

    Expand source code -Browse git +Browse git
    @property
     def log_abs_det(self):
         return sum(block.log_abs_det for block in self._blocks)
    +
    var inv
    +
    +

    Inverse of matrix as a Matrix object.

    +

    This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

    +
    var shape

    Shape of matrix as a tuple (num_rows, num_columns).

    @@ -7985,9 +8123,13 @@

    Instance variables

    Full dense representation of matrix as a 2D array.

    -
    var diagonal
    +
    var transpose
    -

    Diagonal of matrix as a 1D array.

    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    @@ -8009,7 +8151,7 @@

    Args

    Expand source code -Browse git +Browse git
    class SymmetricBlockDiagonalMatrix(SquareBlockDiagonalMatrix):
         """Symmetric specialisation of `SquareBlockDiagonalMatrix`.
    @@ -8034,8 +8176,7 @@ 

    Args

    return SymmetricBlockDiagonalMatrix( tuple(scalar * block for block in self._blocks)) - @property - def T(self): + def _construct_transpose(self): return self

    Ancestors

    @@ -8054,30 +8195,13 @@

    Subclasses

    Instance variables

    -
    var T
    -
    -

    Transpose of matrix.

    -
    - -Expand source code -Browse git - -
    @property
    -def T(self):
    -    return self
    -
    -
    var blocks

    Blocks containing non-zero values left-to-right along diagonal.

    -
    var inv
    +
    var diagonal
    -

    Inverse of matrix as a Matrix object.

    -

    This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

    +

    Diagonal of matrix as a 1D array.

    var log_abs_det
    @@ -8086,6 +8210,14 @@

    Instance variables

    logarithm of the density of then Riemannian measure associated with metric with respect to the Lebesgue measure.

    +
    var inv
    +
    +

    Inverse of matrix as a Matrix object.

    +

    This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

    +
    var shape

    Shape of matrix as a tuple (num_rows, num_columns).

    @@ -8094,9 +8226,13 @@

    Instance variables

    Full dense representation of matrix as a 2D array.

    -
    var diagonal
    +
    var transpose
    -

    Diagonal of matrix as a 1D array.

    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    @@ -8117,7 +8253,7 @@

    Args

    Expand source code -Browse git +Browse git
    class PositiveDefiniteBlockDiagonalMatrix(
             SymmetricBlockDiagonalMatrix, PositiveDefiniteMatrix,
    @@ -8149,8 +8285,7 @@ 

    Args

    else: return super()._scalar_multiply(scalar) - @property - def sqrt(self): + def _construct_sqrt(self): return SquareBlockDiagonalMatrix( tuple(block.sqrt for block in self._blocks)) @@ -8175,42 +8310,25 @@

    Ancestors

    -

    Instance variables

    -
    -
    var sqrt
    -
    -

    Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

    -

    This will in general not correspond to the unique, if defined, -symmetric square root of a symmetric matrix but instead may return any -matrix satisfying the above property.

    -
    - -Expand source code -Browse git - -
    @property
    -def sqrt(self):
    -    return SquareBlockDiagonalMatrix(
    -        tuple(block.sqrt for block in self._blocks))
    -
    -
    +
  • PositiveDefiniteMatrix
  • +
  • SymmetricMatrix
  • +
  • DifferentiableMatrix
  • +
  • InvertibleMatrix
  • +
  • SquareMatrix
  • +
  • BlockMatrix
  • +
  • ImplicitArrayMatrix
  • +
  • Matrix
  • +
  • abc.ABC
  • + +

    Instance variables

    +
    var grad_log_abs_det

    Gradient of logarithm of absolute value of determinant of matrix.

    Expand source code -Browse git +Browse git
    @property
     def grad_log_abs_det(self):
    @@ -8221,21 +8339,13 @@ 

    Instance variables

    raise RuntimeError('Not all blocks are differentiable')
    -
    var T
    -
    -

    Transpose of matrix.

    -
    var blocks

    Blocks containing non-zero values left-to-right along diagonal.

    -
    var inv
    +
    var diagonal
    -

    Inverse of matrix as a Matrix object.

    -

    This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

    +

    Diagonal of matrix as a 1D array.

    var log_abs_det
    @@ -8244,6 +8354,14 @@

    Instance variables

    logarithm of the density of then Riemannian measure associated with metric with respect to the Lebesgue measure.

    +
    var inv
    +
    +

    Inverse of matrix as a Matrix object.

    +

    This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

    +
    var shape

    Shape of matrix as a tuple (num_rows, num_columns).

    @@ -8252,9 +8370,20 @@

    Instance variables

    Full dense representation of matrix as a 2D array.

    -
    var diagonal
    +
    var transpose
    -

    Diagonal of matrix as a 1D array.

    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    +
    +
    var sqrt
    +
    +

    Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

    +

    This will in general not correspond to the unique, if defined, +symmetric square root of a symmetric matrix but instead may return any +matrix satisfying the above property.

    var eigval
    @@ -8281,7 +8410,7 @@

    Args

    Expand source code -Browse git +Browse git
    def grad_quadratic_form_inv(self, vector):
         if self.is_differentiable:
    @@ -8309,7 +8438,7 @@ 

    Args

    Expand source code -Browse git +Browse git
    class DenseRectangularMatrix(ExplicitArrayMatrix):
         """Dense rectangular matrix."""
    @@ -8324,8 +8453,7 @@ 

    Args

    def _scalar_multiply(self, scalar): return DenseRectangularMatrix(scalar * self.array) - @property - def T(self): + def _construct_transpose(self): return DenseRectangularMatrix(self.array.T)

    Ancestors

    @@ -8336,19 +8464,6 @@

    Ancestors

    Instance variables

    -
    var T
    -
    -

    Transpose of matrix.

    -
    - -Expand source code -Browse git - -
    @property
    -def T(self):
    -    return DenseRectangularMatrix(self.array.T)
    -
    -
    var array

    Full dense representation of matrix as a 2D array.

    @@ -8357,6 +8472,14 @@

    Instance variables

    Shape of matrix as a tuple (num_rows, num_columns).

    +
    var transpose
    +
    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    +
    var diagonal

    Diagonal of matrix as a 1D array.

    @@ -8379,7 +8502,7 @@

    Args

    Expand source code -Browse git +Browse git
    class BlockRowMatrix(BlockMatrix):
         """Matrix composed of horizontal concatenation of a series of blocks."""
    @@ -8422,10 +8545,8 @@ 

    Args

    def _construct_array(self): return np.concatenate([block.array for block in self._blocks], axis=1) - @property - def T(self): - return BlockColumnMatrix( - tuple(block.T for block in self._blocks))
    + def _construct_transpose(self): + return BlockColumnMatrix(tuple(block.T for block in self._blocks))

    Ancestors

      @@ -8442,7 +8563,7 @@

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def blocks(self):
      @@ -8450,20 +8571,6 @@ 

      Instance variables

      return self._blocks
    -
    var T
    -
    -

    Transpose of matrix.

    -
    - -Expand source code -Browse git - -
    @property
    -def T(self):
    -    return BlockColumnMatrix(
    -        tuple(block.T for block in self._blocks))
    -
    -
    var array

    Full dense representation of matrix as a 2D array.

    @@ -8475,6 +8582,14 @@

    Instance variables

    Shape of matrix as a tuple (num_rows, num_columns).

    +
    var transpose
    +
    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    +
    var diagonal

    Diagonal of matrix as a 1D array.

    @@ -8497,7 +8612,7 @@

    Args

    Expand source code -Browse git +Browse git
    class BlockColumnMatrix(BlockMatrix):
         """Matrix composed of vertical concatenation of a series of blocks."""
    @@ -8540,10 +8655,8 @@ 

    Args

    def _construct_array(self): return np.concatenate([block.array for block in self._blocks], axis=0) - @property - def T(self): - return BlockRowMatrix( - tuple(block.T for block in self._blocks))
    + def _construct_transpose(self): + return BlockRowMatrix(tuple(block.T for block in self._blocks))

    Ancestors

      @@ -8560,7 +8673,7 @@

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def blocks(self):
      @@ -8568,20 +8681,6 @@ 

      Instance variables

      return self._blocks
      -
      var T
      -
      -

      Transpose of matrix.

      -
      - -Expand source code -Browse git - -
      @property
      -def T(self):
      -    return BlockRowMatrix(
      -        tuple(block.T for block in self._blocks))
      -
      -
      var array

      Full dense representation of matrix as a 2D array.

      @@ -8593,6 +8692,14 @@

      Instance variables

      Shape of matrix as a tuple (num_rows, num_columns).

      +
      var transpose
      +
      +

      Transpose of matrix.

      +
      +
      var T
      +
      +

      Transpose of matrix.

      +
      var diagonal

      Diagonal of matrix as a 1D array.

      @@ -8657,7 +8764,7 @@

      Args

      Expand source code -Browse git +Browse git
      class SquareLowRankUpdateMatrix(InvertibleMatrix, ImplicitArrayMatrix):
           """Square matrix equal to a low-rank update to a square matrix.
      @@ -8718,6 +8825,10 @@ 

      Args

      f'{square_matrix.shape[0]}.') if square_matrix.shape[0] != square_matrix.shape[1]: raise ValueError('square_matrix argument must be square') + if not isinstance(left_factor_matrix, Matrix): + left_factor_matrix = DenseRectangularMatrix(left_factor_matrix) + if not isinstance(right_factor_matrix, Matrix): + right_factor_matrix = DenseRectangularMatrix(right_factor_matrix) if right_factor_matrix.shape != (dim_inner, dim_outer): raise ValueError(f'Inconsistent factor matrix shapes: ' f'{left_factor_matrix.shape} and ' @@ -8773,8 +8884,7 @@

      Args

      (self.left_factor_matrix.array @ self.inner_square_matrix) * self.right_factor_matrix.T.array).sum(1) - @property - def T(self): + def _construct_transpose(self): return type(self)( self.right_factor_matrix.T, self.left_factor_matrix.T, self.square_matrix.T, self.inner_square_matrix.T, @@ -8782,8 +8892,7 @@

      Args

      if self._capacitance_matrix is not None else None, self._sign) - @property - def inv(self): + def _construct_inv(self): return type(self)( self.square_matrix.inv @ self.left_factor_matrix, self.right_factor_matrix @ self.square_matrix.inv, @@ -8828,7 +8937,7 @@

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def capacitance_matrix(self):
      @@ -8846,7 +8955,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def diagonal(self):
      @@ -8855,45 +8964,6 @@ 

      Instance variables

      self.right_factor_matrix.T.array).sum(1)
      -
      var T
      -
      -

      Transpose of matrix.

      -
      - -Expand source code -Browse git - -
      @property
      -def T(self):
      -    return type(self)(
      -        self.right_factor_matrix.T, self.left_factor_matrix.T,
      -        self.square_matrix.T, self.inner_square_matrix.T,
      -        self._capacitance_matrix.T
      -        if self._capacitance_matrix is not None else None,
      -        self._sign)
      -
      -
      -
      var inv
      -
      -

      Inverse of matrix as a Matrix object.

      -

      This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

      -
      - -Expand source code -Browse git - -
      @property
      -def inv(self):
      -    return type(self)(
      -        self.square_matrix.inv @ self.left_factor_matrix,
      -        self.right_factor_matrix @ self.square_matrix.inv,
      -        self.square_matrix.inv, self.capacitance_matrix.inv,
      -        self.inner_square_matrix.inv, -self._sign)
      -
      -
      var log_abs_det

      Logarithm of absolute value of determinant of matrix.

      @@ -8903,7 +8973,7 @@

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def log_abs_det(self):
      @@ -8913,6 +8983,14 @@ 

      Instance variables

      self.capacitance_matrix.log_abs_det)
      +
      var inv
      +
      +

      Inverse of matrix as a Matrix object.

      +

      This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

      +
      var shape

      Shape of matrix as a tuple (num_rows, num_columns).

      @@ -8921,6 +8999,14 @@

      Instance variables

      Full dense representation of matrix as a 2D array.

      +
      var transpose
      +
      +

      Transpose of matrix.

      +
      +
      var T
      +
      +

      Transpose of matrix.

      +
    @@ -8977,7 +9063,7 @@

    Args

    Expand source code -Browse git +Browse git
    class SymmetricLowRankUpdateMatrix(
             SquareLowRankUpdateMatrix, SymmetricMatrix, InvertibleMatrix):
    @@ -9029,10 +9115,15 @@ 

    Args

    sign (int): One of {-1, +1}, determining whether a low-rank update (`sign = 1`) or 'downdate' (`sign = -1`) is peformed. """ + dim_inner = factor_matrix.shape[1] if symmetric_matrix.T is not symmetric_matrix: raise ValueError('symmetric_matrix must be symmetric') + if inner_symmetric_matrix is None: + inner_symmetric_matrix = IdentityMatrix(dim_inner) if inner_symmetric_matrix.T is not inner_symmetric_matrix: raise ValueError('inner_symmetric_matrix must be symmetric') + if not isinstance(factor_matrix, Matrix): + factor_matrix = DenseRectangularMatrix(factor_matrix) self.factor_matrix = factor_matrix self.symmetric_matrix = symmetric_matrix self.inner_symmetric_matrix = inner_symmetric_matrix @@ -9056,15 +9147,13 @@

    Args

    self.symmetric_matrix.inv @ self.factor_matrix.array)) return self._capacitance_matrix - @property - def inv(self): + def _construct_inv(self): return type(self)( self.symmetric_matrix.inv @ self.factor_matrix, self.symmetric_matrix.inv, self.capacitance_matrix.inv, self.inner_symmetric_matrix.inv, -self._sign) - @property - def T(self): + def _construct_transpose(self): return self def _compute_hash(self): @@ -9099,7 +9188,7 @@

    Instance variables

    Expand source code -Browse git +Browse git
    @property
     def capacitance_matrix(self):
    @@ -9111,39 +9200,6 @@ 

    Instance variables

    return self._capacitance_matrix
    -
    var inv
    -
    -

    Inverse of matrix as a Matrix object.

    -

    This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

    -
    - -Expand source code -Browse git - -
    @property
    -def inv(self):
    -    return type(self)(
    -        self.symmetric_matrix.inv @ self.factor_matrix,
    -        self.symmetric_matrix.inv, self.capacitance_matrix.inv,
    -        self.inner_symmetric_matrix.inv, -self._sign)
    -
    -
    -
    var T
    -
    -

    Transpose of matrix.

    -
    - -Expand source code -Browse git - -
    @property
    -def T(self):
    -    return self
    -
    -
    var diagonal

    Diagonal of matrix as a 1D array.

    @@ -9155,6 +9211,14 @@

    Instance variables

    logarithm of the density of then Riemannian measure associated with metric with respect to the Lebesgue measure.

    +
    var inv
    +
    +

    Inverse of matrix as a Matrix object.

    +

    This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

    +
    var shape

    Shape of matrix as a tuple (num_rows, num_columns).

    @@ -9163,6 +9227,14 @@

    Instance variables

    Full dense representation of matrix as a 2D array.

    +
    var transpose
    +
    +

    Transpose of matrix.

    +
    +
    var T
    +
    +

    Transpose of matrix.

    +
    var eigval

    Eigenvalues of matrix as a 1D array.

    @@ -9229,11 +9301,11 @@

    Args

    Expand source code -Browse git +Browse git
    class PositiveDefiniteLowRankUpdateMatrix(
    -        PositiveDefiniteMatrix, DifferentiableMatrix,
    -        SymmetricLowRankUpdateMatrix):
    +        SymmetricLowRankUpdateMatrix, PositiveDefiniteMatrix, 
    +        DifferentiableMatrix):
         """Positive-definite matrix equal to low-rank update to a square matrix.
     
         The matrix is assumed to have the parametrisation
    @@ -9284,8 +9356,13 @@ 

    Args

    sign (int): One of {-1, +1}, determining whether a low-rank update (`sign = 1`) or 'downdate' (`sign = -1`) is peformed. """ + dim_inner = factor_matrix.shape[1] + if not isinstance(factor_matrix, Matrix): + factor_matrix = DenseRectangularMatrix(factor_matrix) self.factor_matrix = factor_matrix self.pos_def_matrix = pos_def_matrix + if inner_pos_def_matrix is None: + inner_pos_def_matrix = IdentityMatrix(dim_inner) self.inner_pos_def_matrix = inner_pos_def_matrix super().__init__( factor_matrix, pos_def_matrix, inner_pos_def_matrix, @@ -9315,8 +9392,7 @@

    Args

    self.factor_matrix.array)) return self._capacitance_matrix - @property - def sqrt(self): + def _construct_sqrt(self): # Uses O(dim_inner**3 + dim_inner**2 * dim_outer) cost implementation # proposed in # Ambikasaran, O'Neill & Singh (2016). Fast symmetric factorization @@ -9325,7 +9401,8 @@

    Args

    W = self.pos_def_matrix.sqrt K = self.inner_pos_def_matrix U = W.inv @ self.factor_matrix - L = TriangularMatrix(nla.cholesky(U.T @ U.array)) + L = TriangularMatrix( + nla.cholesky(U.T @ U.array), lower=True, make_triangular=False) I_outer, I_inner = IdentityMatrix(U.shape[0]), np.identity(U.shape[1]) M = sla.sqrtm(I_inner + L.T @ (K @ L.array)) X = DenseSymmetricMatrix(L.inv.T @ ((M - I_inner) @ L.inv)) @@ -9345,11 +9422,11 @@

    Args

    Ancestors

    -
    var sqrt
    -
    -

    Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

    -

    This will in general not correspond to the unique, if defined, -symmetric square root of a symmetric matrix but instead may return any -matrix satisfying the above property.

    -
    - -Expand source code -Browse git - -
    @property
    -def sqrt(self):
    -    # Uses O(dim_inner**3 + dim_inner**2 * dim_outer) cost implementation
    -    # proposed in
    -    #   Ambikasaran, O'Neill & Singh (2016). Fast symmetric factorization
    -    #   of hierarchical matrices with applications. arxiv:1405.0223.
    -    # Variable naming below follows notation in Algorithm 1 in paper
    -    W = self.pos_def_matrix.sqrt
    -    K = self.inner_pos_def_matrix
    -    U = W.inv @ self.factor_matrix
    -    L = TriangularMatrix(nla.cholesky(U.T @ U.array))
    -    I_outer, I_inner = IdentityMatrix(U.shape[0]), np.identity(U.shape[1])
    -    M = sla.sqrtm(I_inner + L.T @ (K @ L.array))
    -    X = DenseSymmetricMatrix(L.inv.T @ ((M - I_inner) @ L.inv))
    -    return W @ SymmetricLowRankUpdateMatrix(U, I_outer, X)
    -
    -
    var grad_log_abs_det

    Gradient of logarithm of absolute value of determinant of matrix.

    Expand source code -Browse git +Browse git
    @property
     def grad_log_abs_det(self):
    @@ -9419,17 +9468,9 @@ 

    Instance variables

    self.factor_matrix.array @ self.inner_pos_def_matrix))
    -
    var eigval
    -
    -

    Eigenvalues of matrix as a 1D array.

    -
    -
    var eigvec
    -
    -

    Eigenvectors of matrix stacked as columns of a Matrix object.

    -
    -
    var T
    +
    var diagonal
    -

    Transpose of matrix.

    +

    Diagonal of matrix as a 1D array.

    var log_abs_det
    @@ -9438,6 +9479,14 @@

    Instance variables

    logarithm of the density of then Riemannian measure associated with metric with respect to the Lebesgue measure.

    +
    var inv
    +
    +

    Inverse of matrix as a Matrix object.

    +

    This will not necessarily form an explicit representation of the +inverse matrix but may instead return a Matrix object that implements +the matrix multiplication operators by solving the linear system +defined by the original matrix object.

    +
    var shape

    Shape of matrix as a tuple (num_rows, num_columns).

    @@ -9446,17 +9495,28 @@

    Instance variables

    Full dense representation of matrix as a 2D array.

    -
    var diagonal
    +
    var transpose
    -

    Diagonal of matrix as a 1D array.

    +

    Transpose of matrix.

    -
    var inv
    +
    var T
    -

    Inverse of matrix as a Matrix object.

    -

    This will not necessarily form an explicit representation of the -inverse matrix but may instead return a Matrix object that implements -the matrix multiplication operators by solving the linear system -defined by the original matrix object.

    +

    Transpose of matrix.

    +
    +
    var eigval
    +
    +

    Eigenvalues of matrix as a 1D array.

    +
    +
    var eigvec
    +
    +

    Eigenvectors of matrix stacked as columns of a Matrix object.

    +
    +
    var sqrt
    +
    +

    Square-root of matrix satisfying matrix == sqrt @ sqrt.T.

    +

    This will in general not correspond to the unique, if defined, +symmetric square root of a symmetric matrix but instead may return any +matrix satisfying the above property.

    Methods

    @@ -9475,7 +9535,7 @@

    Args

    Expand source code -Browse git +Browse git
    def grad_quadratic_form_inv(self, vector):
         inv_matrix_vector = self.inv @ vector
    @@ -9493,7 +9553,7 @@ 

    Args

    diff --git a/docs/docs/progressbars.html b/docs/docs/progressbars.html index 9cb6448..98896d1 100644 --- a/docs/docs/progressbars.html +++ b/docs/docs/progressbars.html @@ -3,14 +3,14 @@ - + mici.progressbars API documentation - + @@ -34,24 +34,30 @@
  • Classes

    • -

      BaseProgressBar

      +BaseProgressBar
    • -

      DummyProgressBar

      +DummyProgressBar
    • -

      ProgressBar

      +ProgressBar +
      + +Expand members + +
    • -

      FileDisplay

      - @@ -93,14 +117,14 @@

      -

      Package mici.progressbars

      +

      Module mici.progressbars

      Progress bar classes for tracking progress of chains.

      Expand source code -Browse git +Browse git
      """Progress bar classes for tracking progress of chains."""
       
      @@ -120,12 +144,19 @@ 

      Package mici.progressbars

      TQDM_AVAILABLE = True except ImportError: TQDM_AVAILABLE = False +try: + import google.colab + ON_COLAB = True +except ImportError: + ON_COLAB = False def _in_zmq_interactive_shell(): """Check if in interactive ZMQ shell which supports updateable displays""" if not IPYTHON_AVAILABLE: return False + elif ON_COLAB: + return True else: try: shell = get_ipython().__class__.__name__ @@ -139,6 +170,25 @@

      Package mici.progressbars

      return False +def _create_display(obj, position): + """Create an updateable display object. + + Args: + obj (object): Initial object to display. + position (Tuple[int, int]): Tuple specifying position of display within + a sequence of displays with first entry corresponding to the + zero-indexed position and the second entry the total number of + displays. + + Returns: + Object with `update` method to update displayed content. + """ + if _in_zmq_interactive_shell(): + return ipython_display(obj, display_id=True) + else: + return FileDisplay(position) + + def _format_time(total_seconds): """Format a time interval in seconds as a colon-delimited string [h:]m:s""" total_mins, seconds = divmod(int(total_seconds), 60) @@ -161,10 +211,11 @@

      Package mici.progressbars

      class BaseProgressBar(abc.ABC): """Base class defining expected interface for progress bars.""" - def __init__(self, n_iter, description, position): + def __init__(self, sequence, description, position): """ Args: - n_iter (int): Number of iterations to iterate over. + sequence (Sequence): Sequence to iterate over. Must be iterable AND + have a defined length such that `len(sequence)` is valid. description (None or str): Description of task to prefix progress bar with. position (Tuple[int, int]): Tuple specifying position of progress @@ -172,27 +223,44 @@

      Package mici.progressbars

      zero-indexed position and the second entry the total number of progress bars. """ - assert isinstance(n_iter, int) and n_iter > 0, ( - 'n_iter must be a positive integer') - self._n_iter = n_iter + self._sequence = sequence self._description = description self._position = position + self._active = False + self._n_iter = len(sequence) + + @property + def sequence(self): + """Sequence iterated over.""" + return self._sequence + + @sequence.setter + def sequence(self, value): + if self._active: + raise RuntimeError('Cannot set sequence of active progress bar.') + else: + self._sequence = value + self._n_iter = len(value) + + @property + def n_iter(self): + return self._n_iter def __iter__(self): - for iter in range(self._n_iter): + for i, val in enumerate(self.sequence): iter_dict = {} - yield iter, iter_dict - self.update(iter + 1, iter_dict, refresh=True) + yield val, iter_dict + self.update(i + 1, iter_dict, refresh=True) def __len__(self): return self._n_iter @abc.abstractmethod - def update(self, iter, iter_dict, refresh=True): + def update(self, iter_count, iter_dict, refresh=True): """Update progress bar state. Args: - iter (int): New value for iteration counter. + iter_count (int): New value for iteration counter. iter_dict (None or Dict[str, float]): Dictionary of iteration statistics key-value pairs to use to update postfix stats. refresh (bool): Whether to refresh display(s). @@ -201,24 +269,22 @@

      Package mici.progressbars

      @abc.abstractmethod def __enter__(self): """Set up progress bar and any associated resource.""" + self._active = True + return self @abc.abstractmethod def __exit__(self, *args): """Close down progress bar and any associated resources.""" + self._active = False + return False class DummyProgressBar(BaseProgressBar): """Placeholder progress bar which does not display progress updates.""" - def update(self, iter, iter_dict, refresh=True): + def update(self, iter_count, iter_dict, refresh=True): pass - def __enter__(self): - return self - - def __exit__(self, *args): - return False - class ProgressBar(BaseProgressBar): """Iterable object for tracking progress of an iterative task. @@ -231,11 +297,12 @@

      Package mici.progressbars

      GLYPHS = ' ▏▎▍▌▋▊▉█' """Characters used to create string representation of progress bar.""" - def __init__(self, n_iter, description=None, position=(0, 1), + def __init__(self, sequence, description=None, position=(0, 1), displays=None, n_col=10, unit='it', min_refresh_time=0.25): """ Args: - n_iter (int): Number of iterations to iterate over. + sequence (Sequence): Sequence to iterate over. Must be iterable AND + have a defined length such that `len(sequence)` is valid. description (None or str): Description of task to prefix progress bar with. position (Tuple[int, int]): Tuple specifying position of progress @@ -252,22 +319,16 @@

      Package mici.progressbars

      min_referesh_time (float): Minimum time in seconds between each refresh of progress bar visual representation. """ - super().__init__(n_iter, description, position) + super().__init__(sequence, description, position) self._n_col = n_col self._unit = unit self._counter = 0 - self._active = False self._start_time = None self._elapsed_time = 0 self._stats_dict = {} self._displays = displays self._min_refresh_time = min_refresh_time - @property - def n_iter(self): - """Total number of iterations to complete.""" - return self._n_iter - @property def description(self): """"Description of task being tracked.""" @@ -362,11 +423,11 @@

      Package mici.progressbars

      def bar_color(self): """CSS color property for HTML progress bar.""" if self.counter == self.n_iter: - return 'var(--jp-success-color1)' + return 'var(--jp-success-color1, #4caf50)' elif self._active: - return 'var(--jp-brand-color1)' + return 'var(--jp-brand-color1, #2196f3)' else: - return 'var(--jp-error-color1)' + return 'var(--jp-error-color1, #f44336)' @property def stats(self): @@ -392,29 +453,28 @@

      Package mici.progressbars

      def reset(self): """Reset progress bar state.""" self._counter = 0 - self._active = True self._start_time = timer() self._last_refresh_time = -float('inf') self._stats_dict = {} - def update(self, iter, iter_dict=None, refresh=True): + def update(self, iter_count, iter_dict=None, refresh=True): """Update progress bar state Args: - iter (int): New value for iteration counter. + iter_count (int): New value for iteration counter. iter_dict (None or Dict[str, float]): Dictionary of iteration statistics key-value pairs to use to update postfix stats. refresh (bool): Whether to refresh display(s). """ - if iter == 0: + if iter_count == 0: self.reset() else: - self.counter = iter + self.counter = iter_count if iter_dict is not None: - _update_stats_running_means(iter, self._stats_dict, iter_dict) - prev_elased_time = self._elapsed_time + _update_stats_running_means( + iter_count, self._stats_dict, iter_dict) self._elapsed_time = timer() - self._start_time - if refresh and iter == self.n_iter or ( + if refresh and iter_count == self.n_iter or ( timer() - self._last_refresh_time > self._min_refresh_time): self.refresh() self._last_refresh_time = timer() @@ -436,8 +496,8 @@

      Package mici.progressbars

      flex-flow: row wrap; align-items: center; position: relative; margin: 2px;"> <label style="margin-right: 8px; flex-shrink: 0; - font-size: var(--jp-code-font-size); - font-family: var(--jp-code-font-family);"> + font-size: var(--jp-code-font-size, 13px); + font-family: var(--jp-code-font-family, monospace);"> {html.escape(self.prefix).replace(' ', '&nbsp;')} </label> <div role="progressbar" aria-valuenow="{self.prop_complete}" @@ -450,27 +510,161 @@

      Package mici.progressbars

      height: 100%;"></div> </div> <div style="margin-left: 8px; flex-shrink: 0; - font-family: var(--jp-code-font-family); - font-size: var(--jp-code-font-size);"> + font-family: var(--jp-code-font-family, monospace); + font-size: var(--jp-code-font-size, 13px);"> {html.escape(self.postfix)} </div> </div> ''' def __enter__(self): + super().__enter__() self.reset() if self._displays is None: - self._displays = [ - ipython_display(self, display_id=True) - if _in_zmq_interactive_shell() - else FileDisplay(self._position)] + self._displays = [_create_display(self, self._position)] return self def __exit__(self, *args): - self._active = False + ret_val = super().__exit__() if self.counter != self.n_iter: self.refresh() - return False + return ret_val + + +class LabelledSequenceProgressBar(BaseProgressBar): + """Iterable object for tracking progress of a sequence of labelled tasks.""" + + def __init__(self, labelled_sequence, description=None, position=(0, 1), + displays=None): + """ + Args: + labelled_sequence (OrderedDict[str, Any]): Ordered dictionary with + string keys corresponding to labels for stages represented by + sequence and values the entries in the sequence being iterated + over. + description (None or str): Description of task to prefix progress + bar with. + position (Tuple[int, int]): Tuple specifying position of progress + bar within a sequence with first entry corresponding to + zero-indexed position and the second entry the total number of + progress bars. + displays (None or List[object]): List of objects to use to display + visual representation(s) of progress bar. Each object much have + an `update` method which will be passed a single argument + corresponding to the current progress bar. + """ + super().__init__( + list(labelled_sequence.values()), description, position) + self._labels = list(labelled_sequence.keys()) + self._description = description + self._position = position + self._counter = 0 + self._prev_time = None + self._iter_times = [None] * self.n_iter + self._stats_dict = {} + self._displays = displays + + @property + def counter(self): + """Progress iteration count.""" + return self._counter + + @counter.setter + def counter(self, value): + self._counter = max(0, min(value, self.n_iter)) + + @property + def description(self): + """Description of task being tracked.""" + return self._description + + @property + def stats(self): + """Comma-delimited string list of statistic key=value pairs.""" + return ', '.join(f'{k}={v:#.3g}' for k, v in self._stats_dict.items()) + + @property + def prefix(self): + """Text to prefix progress bar with.""" + return f'{self.description + ": " if self.description else ""}' + + @property + def postfix(self): + """Text to postfix progress bar with.""" + return f' [{self.stats}]' if self._stats_dict else '' + + @property + def completed_labels(self): + """Labels corresponding to completed iterations.""" + return [ + f'{label} [{_format_time(time)}]' for label, time in + zip(self._labels[:self._counter], self._iter_times[:self._counter])] + + @property + def current_label(self): + """Label corresponding to current iteration.""" + return self._labels[self._counter] if self.counter < self.n_iter else '' + + @property + def progress_bar(self): + """Progress bar string.""" + labels = self.completed_labels + if self.counter < self.n_iter: + labels.append(self.current_label) + return ' > '.join(labels) + + def reset(self): + """Reset progress bar state.""" + self._counter = 0 + self._prev_time = timer() + self._iter_times = [None] * self.n_iter + self._stats_dict = {} + + def update(self, iter_count, iter_dict=None, refresh=True): + """Update progress bar state + + Args: + status (string): New value for status string. + iter_dict (None or Dict[str, float]): Dictionary of iteration + statistics key-value pairs to use to update postfix stats. + refresh (bool): Whether to refresh display(s). + """ + if iter_count == 0: + self.reset() + else: + self.counter = iter_count + if iter_dict is not None: + _update_stats_running_means(iter, self._stats_dict, iter_dict) + curr_time = timer() + self._iter_times[iter_count - 1] = curr_time - self._prev_time + self._prev_time = curr_time + if refresh: + self.refresh() + + def refresh(self): + """Refresh visual display(s) of status bar.""" + for display in self._displays: + display.update(self) + + def __str__(self): + return f'{self.prefix}{self.progress_bar}{self.postfix}' + + def __repr__(self): + return self.__str__() + + def __enter__(self): + super().__enter__() + self.reset() + if self._displays is None: + self._displays = [_create_display(self, self._position)] + self.refresh() + return self + + def __exit__(self, *args): + ret_val = super().__exit__() + if self.counter != self.n_iter: + self.refresh() + return ret_val class FileDisplay: @@ -497,7 +691,8 @@

      Package mici.progressbars

      self._position = position self._file = file if file is not None else sys.stdout self._last_string_length = 0 - self._file.write('\n') + if self._position[0] == 0: + self._file.write('\n' * self._position[1]) self._file.flush() def _move_line(self, offset): @@ -520,16 +715,18 @@

      Package mici.progressbars

      when distributing tasks across multiple processes. """ - def __init__(self, n_iter, job_id, iter_queue): + def __init__(self, sequence, job_id, iter_queue): """ Args: - n_iter (int): Number of iterations to iterate over. + sequence (Sequence): Sequence to iterate over. Must be iterable AND + have a defined length such that `len(sequence)` is valid. job_id (int): Unique integer identifier for progress bar amongst other progress bars sharing same `iter_queue` object. iter_queue (Queue): Shared queue object that progress updates are pushed to. """ - self._n_iter = n_iter + self._sequence = sequence + self._n_iter = len(sequence) self._job_id = job_id self._iter_queue = iter_queue @@ -544,10 +741,10 @@

      Package mici.progressbars

      return False def __iter__(self): - for iter in range(self._n_iter): + for i, val in enumerate(self._sequence): iter_dict = {} - yield iter, iter_dict - self._iter_queue.put((self._job_id, iter + 1, iter_dict)) + yield val, iter_dict + self._iter_queue.put((self._job_id, i + 1, iter_dict)) if TQDM_AVAILABLE: @@ -555,31 +752,32 @@

      Package mici.progressbars

      class TqdmProgressBar(BaseProgressBar): """Wrapper of `tqdm` with same interface as `ProgressBar`.""" - def __init__(self, n_iter, description=None, position=(0, 1)): - super().__init__(n_iter, description, position) + def __init__(self, sequence, description=None, position=(0, 1)): + super().__init__(sequence, description, position) self._stats_dict = {} self._tqdm_obj = None - def update(self, iter, iter_dict=None, refresh=True): + def update(self, iter_count, iter_dict=None, refresh=True): if self._tqdm_obj is None: raise RuntimeError( 'Must enter object first in context manager.') - if iter == 0: + if iter_count == 0: self._tqdm_obj.reset() elif not self._tqdm_obj.disable: - self._tqdm_obj.update(iter - self._tqdm_obj.n) + self._tqdm_obj.update(iter_count - self._tqdm_obj.n) if iter_dict is not None: _update_stats_running_means( - iter, self._stats_dict, iter_dict) + iter_count, self._stats_dict, iter_dict) self._tqdm_obj.set_postfix(self._stats_dict) - if iter == self._n_iter: + if iter_count == self._n_iter: self._tqdm_obj.close() if refresh: self._tqdm_obj.refresh() def __enter__(self): - self._tqdm_obj = tqdm.trange( - self._n_iter, desc=self._description, + super.__enter__() + self._tqdm_obj = tqdm.tqdm( + self._sequence, desc=self._description, position=self._position[0]).__enter__() return self @@ -598,14 +796,15 @@

      Classes

      class BaseProgressBar -(n_iter, description, position) +(sequence, description, position)

      Base class defining expected interface for progress bars.

      Args

      -
      n_iter : int
      -
      Number of iterations to iterate over.
      +
      sequence : Sequence
      +
      Sequence to iterate over. Must be iterable AND +have a defined length such that len(sequence) is valid.
      description : None or str
      Description of task to prefix progress bar with.
      @@ -618,15 +817,16 @@

      Args

      Expand source code -Browse git +Browse git
      class BaseProgressBar(abc.ABC):
           """Base class defining expected interface for progress bars."""
       
      -    def __init__(self, n_iter, description, position):
      +    def __init__(self, sequence, description, position):
               """
               Args:
      -            n_iter (int): Number of iterations to iterate over.
      +            sequence (Sequence): Sequence to iterate over. Must be iterable AND
      +                have a defined length such that `len(sequence)` is valid.
                   description (None or str): Description of task to prefix progress
                       bar with.
                   position (Tuple[int, int]): Tuple specifying position of progress
      @@ -634,27 +834,44 @@ 

      Args

      zero-indexed position and the second entry the total number of progress bars. """ - assert isinstance(n_iter, int) and n_iter > 0, ( - 'n_iter must be a positive integer') - self._n_iter = n_iter + self._sequence = sequence self._description = description self._position = position + self._active = False + self._n_iter = len(sequence) + + @property + def sequence(self): + """Sequence iterated over.""" + return self._sequence + + @sequence.setter + def sequence(self, value): + if self._active: + raise RuntimeError('Cannot set sequence of active progress bar.') + else: + self._sequence = value + self._n_iter = len(value) + + @property + def n_iter(self): + return self._n_iter def __iter__(self): - for iter in range(self._n_iter): + for i, val in enumerate(self.sequence): iter_dict = {} - yield iter, iter_dict - self.update(iter + 1, iter_dict, refresh=True) + yield val, iter_dict + self.update(i + 1, iter_dict, refresh=True) def __len__(self): return self._n_iter @abc.abstractmethod - def update(self, iter, iter_dict, refresh=True): + def update(self, iter_count, iter_dict, refresh=True): """Update progress bar state. Args: - iter (int): New value for iteration counter. + iter_count (int): New value for iteration counter. iter_dict (None or Dict[str, float]): Dictionary of iteration statistics key-value pairs to use to update postfix stats. refresh (bool): Whether to refresh display(s). @@ -663,10 +880,14 @@

      Args

      @abc.abstractmethod def __enter__(self): """Set up progress bar and any associated resource.""" + self._active = True + return self @abc.abstractmethod def __exit__(self, *args): - """Close down progress bar and any associated resources."""
      + """Close down progress bar and any associated resources.""" + self._active = False + return False

      Ancestors

        @@ -676,18 +897,48 @@

        Subclasses

        +

        Instance variables

        +
        +
        var sequence
        +
        +

        Sequence iterated over.

        +
        + +Expand source code +Browse git + +
        @property
        +def sequence(self):
        +    """Sequence iterated over."""
        +    return self._sequence
        +
        +
        +
        var n_iter
        +
        +
        +
        + +Expand source code +Browse git + +
        @property
        +def n_iter(self):
        +    return self._n_iter
        +
        +
        +

        Methods

        -def update(self, iter, iter_dict, refresh=True) +def update(self, iter_count, iter_dict, refresh=True)

        Update progress bar state.

        Args

        -
        iter : int
        +
        iter_count : int
        New value for iteration counter.
        iter_dict : None or Dict[str, float]
        Dictionary of iteration @@ -698,14 +949,14 @@

        Args

        Expand source code -Browse git +Browse git
        @abc.abstractmethod
        -def update(self, iter, iter_dict, refresh=True):
        +def update(self, iter_count, iter_dict, refresh=True):
             """Update progress bar state.
         
             Args:
        -        iter (int): New value for iteration counter.
        +        iter_count (int): New value for iteration counter.
                 iter_dict (None or Dict[str, float]): Dictionary of iteration
                     statistics key-value pairs to use to update postfix stats.
                 refresh (bool): Whether to refresh display(s).
        @@ -716,14 +967,15 @@ 

        Args

        class DummyProgressBar -(n_iter, description, position) +(sequence, description, position)

        Placeholder progress bar which does not display progress updates.

        Args

        -
        n_iter : int
        -
        Number of iterations to iterate over.
        +
        sequence : Sequence
        +
        Sequence to iterate over. Must be iterable AND +have a defined length such that len(sequence) is valid.
        description : None or str
        Description of task to prefix progress bar with.
        @@ -736,35 +988,36 @@

        Args

        Expand source code -Browse git +Browse git
        class DummyProgressBar(BaseProgressBar):
             """Placeholder progress bar which does not display progress updates."""
         
        -    def update(self, iter, iter_dict, refresh=True):
        -        pass
        -
        -    def __enter__(self):
        -        return self
        -
        -    def __exit__(self, *args):
        -        return False
        + def update(self, iter_count, iter_dict, refresh=True): + pass

  • Ancestors

    +

    Instance variables

    +
    +
    var sequence
    +
    +

    Sequence iterated over.

    +
    +

    Methods

    -def update(self, iter, iter_dict, refresh=True) +def update(self, iter_count, iter_dict, refresh=True)

    Update progress bar state.

    Args

    -
    iter : int
    +
    iter_count : int
    New value for iteration counter.
    iter_dict : None or Dict[str, float]
    Dictionary of iteration @@ -775,9 +1028,9 @@

    Args

    Expand source code -Browse git +Browse git -
    def update(self, iter, iter_dict, refresh=True):
    +
    def update(self, iter_count, iter_dict, refresh=True):
         pass
    @@ -785,7 +1038,7 @@

    Args

    class ProgressBar -(n_iter, description=None, position=(0, 1), displays=None, n_col=10, unit='it', min_refresh_time=0.25) +(sequence, description=None, position=(0, 1), displays=None, n_col=10, unit='it', min_refresh_time=0.25)

    Iterable object for tracking progress of an iterative task.

    @@ -794,8 +1047,9 @@

    Args

    notebooks or interactive terminals.

    Args

    -
    n_iter : int
    -
    Number of iterations to iterate over.
    +
    sequence : Sequence
    +
    Sequence to iterate over. Must be iterable AND +have a defined length such that len(sequence) is valid.
    description : None or str
    Description of task to prefix progress bar with.
    @@ -821,7 +1075,7 @@

    Args

    Expand source code -Browse git +Browse git
    class ProgressBar(BaseProgressBar):
         """Iterable object for tracking progress of an iterative task.
    @@ -834,11 +1088,12 @@ 

    Args

    GLYPHS = ' ▏▎▍▌▋▊▉█' """Characters used to create string representation of progress bar.""" - def __init__(self, n_iter, description=None, position=(0, 1), + def __init__(self, sequence, description=None, position=(0, 1), displays=None, n_col=10, unit='it', min_refresh_time=0.25): """ Args: - n_iter (int): Number of iterations to iterate over. + sequence (Sequence): Sequence to iterate over. Must be iterable AND + have a defined length such that `len(sequence)` is valid. description (None or str): Description of task to prefix progress bar with. position (Tuple[int, int]): Tuple specifying position of progress @@ -855,22 +1110,16 @@

    Args

    min_referesh_time (float): Minimum time in seconds between each refresh of progress bar visual representation. """ - super().__init__(n_iter, description, position) + super().__init__(sequence, description, position) self._n_col = n_col self._unit = unit self._counter = 0 - self._active = False self._start_time = None self._elapsed_time = 0 self._stats_dict = {} self._displays = displays self._min_refresh_time = min_refresh_time - @property - def n_iter(self): - """Total number of iterations to complete.""" - return self._n_iter - @property def description(self): """"Description of task being tracked.""" @@ -965,11 +1214,11 @@

    Args

    def bar_color(self): """CSS color property for HTML progress bar.""" if self.counter == self.n_iter: - return 'var(--jp-success-color1)' + return 'var(--jp-success-color1, #4caf50)' elif self._active: - return 'var(--jp-brand-color1)' + return 'var(--jp-brand-color1, #2196f3)' else: - return 'var(--jp-error-color1)' + return 'var(--jp-error-color1, #f44336)' @property def stats(self): @@ -995,29 +1244,28 @@

    Args

    def reset(self): """Reset progress bar state.""" self._counter = 0 - self._active = True self._start_time = timer() self._last_refresh_time = -float('inf') self._stats_dict = {} - def update(self, iter, iter_dict=None, refresh=True): + def update(self, iter_count, iter_dict=None, refresh=True): """Update progress bar state Args: - iter (int): New value for iteration counter. + iter_count (int): New value for iteration counter. iter_dict (None or Dict[str, float]): Dictionary of iteration statistics key-value pairs to use to update postfix stats. refresh (bool): Whether to refresh display(s). """ - if iter == 0: + if iter_count == 0: self.reset() else: - self.counter = iter + self.counter = iter_count if iter_dict is not None: - _update_stats_running_means(iter, self._stats_dict, iter_dict) - prev_elased_time = self._elapsed_time + _update_stats_running_means( + iter_count, self._stats_dict, iter_dict) self._elapsed_time = timer() - self._start_time - if refresh and iter == self.n_iter or ( + if refresh and iter_count == self.n_iter or ( timer() - self._last_refresh_time > self._min_refresh_time): self.refresh() self._last_refresh_time = timer() @@ -1039,8 +1287,8 @@

    Args

    flex-flow: row wrap; align-items: center; position: relative; margin: 2px;"> <label style="margin-right: 8px; flex-shrink: 0; - font-size: var(--jp-code-font-size); - font-family: var(--jp-code-font-family);"> + font-size: var(--jp-code-font-size, 13px); + font-family: var(--jp-code-font-family, monospace);"> {html.escape(self.prefix).replace(' ', '&nbsp;')} </label> <div role="progressbar" aria-valuenow="{self.prop_complete}" @@ -1053,27 +1301,25 @@

    Args

    height: 100%;"></div> </div> <div style="margin-left: 8px; flex-shrink: 0; - font-family: var(--jp-code-font-family); - font-size: var(--jp-code-font-size);"> + font-family: var(--jp-code-font-family, monospace); + font-size: var(--jp-code-font-size, 13px);"> {html.escape(self.postfix)} </div> </div> ''' def __enter__(self): + super().__enter__() self.reset() if self._displays is None: - self._displays = [ - ipython_display(self, display_id=True) - if _in_zmq_interactive_shell() - else FileDisplay(self._position)] + self._displays = [_create_display(self, self._position)] return self def __exit__(self, *args): - self._active = False + ret_val = super().__exit__() if self.counter != self.n_iter: self.refresh() - return False
    + return ret_val

    Ancestors

      @@ -1089,27 +1335,13 @@

      Class variables

      Instance variables

      -
      var n_iter
      -
      -

      Total number of iterations to complete.

      -
      - -Expand source code -Browse git - -
      @property
      -def n_iter(self):
      -    """Total number of iterations to complete."""
      -    return self._n_iter
      -
      -
      var description

      "Description of task being tracked.

      Expand source code -Browse git +Browse git
      @property
       def description(self):
      @@ -1123,7 +1355,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def counter(self):
      @@ -1137,7 +1369,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def prop_complete(self):
      @@ -1151,7 +1383,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def perc_complete(self):
      @@ -1165,7 +1397,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def elapsed_time(self):
      @@ -1179,7 +1411,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def iter_rate(self):
      @@ -1199,7 +1431,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def est_remaining_time(self):
      @@ -1217,7 +1449,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def n_block_filled(self):
      @@ -1231,7 +1463,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def n_block_empty(self):
      @@ -1245,7 +1477,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def prop_partial_block(self):
      @@ -1259,7 +1491,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def filled_blocks(self):
      @@ -1273,7 +1505,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def empty_blocks(self):
      @@ -1290,7 +1522,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def partial_block(self):
      @@ -1307,7 +1539,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def progress_bar(self):
      @@ -1321,17 +1553,17 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def bar_color(self):
           """CSS color property for HTML progress bar."""
           if self.counter == self.n_iter:
      -        return 'var(--jp-success-color1)'
      +        return 'var(--jp-success-color1, #4caf50)'
           elif self._active:
      -        return 'var(--jp-brand-color1)'
      +        return 'var(--jp-brand-color1, #2196f3)'
           else:
      -        return 'var(--jp-error-color1)'
      + return 'var(--jp-error-color1, #f44336)'
      var stats
      @@ -1340,7 +1572,7 @@

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def stats(self):
      @@ -1354,7 +1586,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def prefix(self):
      @@ -1370,7 +1602,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def postfix(self):
      @@ -1382,6 +1614,10 @@ 

      Instance variables

      f'{", " + self.stats if self._stats_dict else ""}]')
      +
      var sequence
      +
      +

      Sequence iterated over.

      +

      Methods

      @@ -1393,25 +1629,24 @@

      Methods

      Expand source code -Browse git +Browse git
      def reset(self):
           """Reset progress bar state."""
           self._counter = 0
      -    self._active = True
           self._start_time = timer()
           self._last_refresh_time = -float('inf')
           self._stats_dict = {}
      -def update(self, iter, iter_dict=None, refresh=True) +def update(self, iter_count, iter_dict=None, refresh=True)

      Update progress bar state

      Args

      -
      iter : int
      +
      iter_count : int
      New value for iteration counter.
      iter_dict : None or Dict[str, float]
      Dictionary of iteration @@ -1422,26 +1657,26 @@

      Args

      Expand source code -Browse git +Browse git -
      def update(self, iter, iter_dict=None, refresh=True):
      +
      def update(self, iter_count, iter_dict=None, refresh=True):
           """Update progress bar state
       
           Args:
      -        iter (int): New value for iteration counter.
      +        iter_count (int): New value for iteration counter.
               iter_dict (None or Dict[str, float]): Dictionary of iteration
                   statistics key-value pairs to use to update postfix stats.
               refresh (bool): Whether to refresh display(s).
           """
      -    if iter == 0:
      +    if iter_count == 0:
               self.reset()
           else:
      -        self.counter = iter
      +        self.counter = iter_count
               if iter_dict is not None:
      -            _update_stats_running_means(iter, self._stats_dict, iter_dict)
      -        prev_elased_time = self._elapsed_time
      +            _update_stats_running_means(
      +                iter_count, self._stats_dict, iter_dict)
               self._elapsed_time = timer() - self._start_time
      -    if refresh and iter == self.n_iter or (
      +    if refresh and iter_count == self.n_iter or (
                   timer() - self._last_refresh_time > self._min_refresh_time):
               self.refresh()
               self._last_refresh_time = timer()
      @@ -1455,7 +1690,7 @@

      Args

      Expand source code -Browse git +Browse git
      def refresh(self):
           """Refresh visual display(s) of progress bar."""
      @@ -1465,47 +1700,423 @@ 

      Args

      -
      -class FileDisplay -(position=(0, 1), file=None) +
      +class LabelledSequenceProgressBar +(labelled_sequence, description=None, position=(0, 1), displays=None)
      -

      Use file which supports ANSI escape sequences as an updatable display

      +

      Iterable object for tracking progress of a sequence of labelled tasks.

      Args

      +
      labelled_sequence : OrderedDict[str, Any]
      +
      Ordered dictionary with +string keys corresponding to labels for stages represented by +sequence and values the entries in the sequence being iterated +over.
      +
      description : None or str
      +
      Description of task to prefix progress +bar with.
      position : Tuple[int, int]
      -
      Tuple specifying position of -display line within a sequence lines with first entry -corresponding to zero-indexed line and the second entry -the total number of lines.
      -
      file : None or File
      -
      File object to write updates to. Must support -ANSI escape sequences \x1b[A} (cursor up) and \x1b[B -(cursor down) for manipulating write position. Defaults to -sys.stdout if None.
      +
      Tuple specifying position of progress +bar within a sequence with first entry corresponding to +zero-indexed position and the second entry the total number of +progress bars.
      +
      displays : None or List[object]
      +
      List of objects to use to display +visual representation(s) of progress bar. Each object much have +an update method which will be passed a single argument +corresponding to the current progress bar.
      Expand source code -Browse git +Browse git -
      class FileDisplay:
      -    """Use file which supports ANSI escape sequences as an updatable display"""
      -
      -    CURSOR_UP = '\x1b[A'
      -    """ANSI escape sequence to move cursor up one line."""
      -
      -    CURSOR_DOWN = '\x1b[B'
      -    """ANSI escape sequence to move cursor down one line."""
      +
      class LabelledSequenceProgressBar(BaseProgressBar):
      +    """Iterable object for tracking progress of a sequence of labelled tasks."""
       
      -    def __init__(self, position=(0, 1), file=None):
      +    def __init__(self, labelled_sequence, description=None, position=(0, 1),
      +                 displays=None):
               """
               Args:
      -            position (Tuple[int, int]): Tuple specifying position of
      -                display line within a sequence lines with first entry
      -                corresponding to zero-indexed line and the second entry
      -                the total number of lines.
      -            file (None or File): File object to write updates to. Must support
      +            labelled_sequence (OrderedDict[str, Any]): Ordered dictionary with
      +                string keys corresponding to labels for stages represented by
      +                sequence and values the entries in the sequence being iterated
      +                over.
      +            description (None or str): Description of task to prefix progress
      +                bar with.
      +            position (Tuple[int, int]): Tuple specifying position of progress
      +                bar within a sequence with first entry corresponding to
      +                zero-indexed position and the second entry the total number of
      +                progress bars.
      +            displays (None or List[object]): List of objects to use to display
      +                visual representation(s) of progress bar. Each object much have
      +                an `update` method which will be passed a single argument
      +                corresponding to the current progress bar.
      +        """
      +        super().__init__(
      +            list(labelled_sequence.values()), description, position)
      +        self._labels = list(labelled_sequence.keys())
      +        self._description = description
      +        self._position = position
      +        self._counter = 0
      +        self._prev_time = None
      +        self._iter_times = [None] * self.n_iter
      +        self._stats_dict = {}
      +        self._displays = displays
      +
      +    @property
      +    def counter(self):
      +        """Progress iteration count."""
      +        return self._counter
      +
      +    @counter.setter
      +    def counter(self, value):
      +        self._counter = max(0, min(value, self.n_iter))
      +
      +    @property
      +    def description(self):
      +        """Description of task being tracked."""
      +        return self._description
      +
      +    @property
      +    def stats(self):
      +        """Comma-delimited string list of statistic key=value pairs."""
      +        return ', '.join(f'{k}={v:#.3g}' for k, v in self._stats_dict.items())
      +
      +    @property
      +    def prefix(self):
      +        """Text to prefix progress bar with."""
      +        return f'{self.description + ": " if self.description else ""}'
      +
      +    @property
      +    def postfix(self):
      +        """Text to postfix progress bar with."""
      +        return f' [{self.stats}]' if self._stats_dict else ''
      +
      +    @property
      +    def completed_labels(self):
      +        """Labels corresponding to completed iterations."""
      +        return [
      +            f'{label} [{_format_time(time)}]' for label, time in
      +            zip(self._labels[:self._counter], self._iter_times[:self._counter])]
      +
      +    @property
      +    def current_label(self):
      +        """Label corresponding to current iteration."""
      +        return self._labels[self._counter] if self.counter < self.n_iter else ''
      +
      +    @property
      +    def progress_bar(self):
      +        """Progress bar string."""
      +        labels = self.completed_labels
      +        if self.counter < self.n_iter:
      +            labels.append(self.current_label)
      +        return ' > '.join(labels)
      +
      +    def reset(self):
      +        """Reset progress bar state."""
      +        self._counter = 0
      +        self._prev_time = timer()
      +        self._iter_times = [None] * self.n_iter
      +        self._stats_dict = {}
      +
      +    def update(self, iter_count, iter_dict=None, refresh=True):
      +        """Update progress bar state
      +
      +        Args:
      +            status (string): New value for status string.
      +            iter_dict (None or Dict[str, float]): Dictionary of iteration
      +                statistics key-value pairs to use to update postfix stats.
      +            refresh (bool): Whether to refresh display(s).
      +        """
      +        if iter_count == 0:
      +            self.reset()
      +        else:
      +            self.counter = iter_count
      +            if iter_dict is not None:
      +                _update_stats_running_means(iter, self._stats_dict, iter_dict)
      +            curr_time = timer()
      +            self._iter_times[iter_count - 1] = curr_time - self._prev_time
      +            self._prev_time = curr_time
      +        if refresh:
      +            self.refresh()
      +
      +    def refresh(self):
      +        """Refresh visual display(s) of status bar."""
      +        for display in self._displays:
      +            display.update(self)
      +
      +    def __str__(self):
      +        return f'{self.prefix}{self.progress_bar}{self.postfix}'
      +
      +    def __repr__(self):
      +        return self.__str__()
      +
      +    def __enter__(self):
      +        super().__enter__()
      +        self.reset()
      +        if self._displays is None:
      +            self._displays = [_create_display(self, self._position)]
      +        self.refresh()
      +        return self
      +
      +    def __exit__(self, *args):
      +        ret_val = super().__exit__()
      +        if self.counter != self.n_iter:
      +            self.refresh()
      +        return ret_val
      +
      +

      Ancestors

      + +

      Instance variables

      +
      +
      var counter
      +
      +

      Progress iteration count.

      +
      + +Expand source code +Browse git + +
      @property
      +def counter(self):
      +    """Progress iteration count."""
      +    return self._counter
      +
      +
      +
      var description
      +
      +

      Description of task being tracked.

      +
      + +Expand source code +Browse git + +
      @property
      +def description(self):
      +    """Description of task being tracked."""
      +    return self._description
      +
      +
      +
      var stats
      +
      +

      Comma-delimited string list of statistic key=value pairs.

      +
      + +Expand source code +Browse git + +
      @property
      +def stats(self):
      +    """Comma-delimited string list of statistic key=value pairs."""
      +    return ', '.join(f'{k}={v:#.3g}' for k, v in self._stats_dict.items())
      +
      +
      +
      var prefix
      +
      +

      Text to prefix progress bar with.

      +
      + +Expand source code +Browse git + +
      @property
      +def prefix(self):
      +    """Text to prefix progress bar with."""
      +    return f'{self.description + ": " if self.description else ""}'
      +
      +
      +
      var postfix
      +
      +

      Text to postfix progress bar with.

      +
      + +Expand source code +Browse git + +
      @property
      +def postfix(self):
      +    """Text to postfix progress bar with."""
      +    return f' [{self.stats}]' if self._stats_dict else ''
      +
      +
      +
      var completed_labels
      +
      +

      Labels corresponding to completed iterations.

      +
      + +Expand source code +Browse git + +
      @property
      +def completed_labels(self):
      +    """Labels corresponding to completed iterations."""
      +    return [
      +        f'{label} [{_format_time(time)}]' for label, time in
      +        zip(self._labels[:self._counter], self._iter_times[:self._counter])]
      +
      +
      +
      var current_label
      +
      +

      Label corresponding to current iteration.

      +
      + +Expand source code +Browse git + +
      @property
      +def current_label(self):
      +    """Label corresponding to current iteration."""
      +    return self._labels[self._counter] if self.counter < self.n_iter else ''
      +
      +
      +
      var progress_bar
      +
      +

      Progress bar string.

      +
      + +Expand source code +Browse git + +
      @property
      +def progress_bar(self):
      +    """Progress bar string."""
      +    labels = self.completed_labels
      +    if self.counter < self.n_iter:
      +        labels.append(self.current_label)
      +    return ' > '.join(labels)
      +
      +
      +
      var sequence
      +
      +

      Sequence iterated over.

      +
      +
      +

      Methods

      +
      +
      +def reset(self) +
      +
      +

      Reset progress bar state.

      +
      + +Expand source code +Browse git + +
      def reset(self):
      +    """Reset progress bar state."""
      +    self._counter = 0
      +    self._prev_time = timer()
      +    self._iter_times = [None] * self.n_iter
      +    self._stats_dict = {}
      +
      +
      +
      +def update(self, iter_count, iter_dict=None, refresh=True) +
      +
      +

      Update progress bar state

      +

      Args

      +
      +
      status : string
      +
      New value for status string.
      +
      iter_dict : None or Dict[str, float]
      +
      Dictionary of iteration +statistics key-value pairs to use to update postfix stats.
      +
      refresh : bool
      +
      Whether to refresh display(s).
      +
      +
      + +Expand source code +Browse git + +
      def update(self, iter_count, iter_dict=None, refresh=True):
      +    """Update progress bar state
      +
      +    Args:
      +        status (string): New value for status string.
      +        iter_dict (None or Dict[str, float]): Dictionary of iteration
      +            statistics key-value pairs to use to update postfix stats.
      +        refresh (bool): Whether to refresh display(s).
      +    """
      +    if iter_count == 0:
      +        self.reset()
      +    else:
      +        self.counter = iter_count
      +        if iter_dict is not None:
      +            _update_stats_running_means(iter, self._stats_dict, iter_dict)
      +        curr_time = timer()
      +        self._iter_times[iter_count - 1] = curr_time - self._prev_time
      +        self._prev_time = curr_time
      +    if refresh:
      +        self.refresh()
      +
      +
      +
      +def refresh(self) +
      +
      +

      Refresh visual display(s) of status bar.

      +
      + +Expand source code +Browse git + +
      def refresh(self):
      +    """Refresh visual display(s) of status bar."""
      +    for display in self._displays:
      +        display.update(self)
      +
      +
      +
      +
      +
      +class FileDisplay +(position=(0, 1), file=None) +
      +
      +

      Use file which supports ANSI escape sequences as an updatable display

      +

      Args

      +
      +
      position : Tuple[int, int]
      +
      Tuple specifying position of +display line within a sequence lines with first entry +corresponding to zero-indexed line and the second entry +the total number of lines.
      +
      file : None or File
      +
      File object to write updates to. Must support +ANSI escape sequences \x1b[A} (cursor up) and \x1b[B +(cursor down) for manipulating write position. Defaults to +sys.stdout if None.
      +
      +
      + +Expand source code +Browse git + +
      class FileDisplay:
      +    """Use file which supports ANSI escape sequences as an updatable display"""
      +
      +    CURSOR_UP = '\x1b[A'
      +    """ANSI escape sequence to move cursor up one line."""
      +
      +    CURSOR_DOWN = '\x1b[B'
      +    """ANSI escape sequence to move cursor down one line."""
      +
      +    def __init__(self, position=(0, 1), file=None):
      +        """
      +        Args:
      +            position (Tuple[int, int]): Tuple specifying position of
      +                display line within a sequence lines with first entry
      +                corresponding to zero-indexed line and the second entry
      +                the total number of lines.
      +            file (None or File): File object to write updates to. Must support
                       ANSI escape sequences `\\x1b[A}` (cursor up) and `\\x1b[B`
                       (cursor down) for manipulating write position. Defaults to
                       `sys.stdout` if `None`.
      @@ -1513,7 +2124,8 @@ 

      Args

      self._position = position self._file = file if file is not None else sys.stdout self._last_string_length = 0 - self._file.write('\n') + if self._position[0] == 0: + self._file.write('\n' * self._position[1]) self._file.flush() def _move_line(self, offset): @@ -1549,7 +2161,7 @@

      Methods

      Expand source code -Browse git +Browse git
      def update(self, obj):
           self._move_line(self._position[0] - self._position[1])
      @@ -1562,118 +2174,13 @@ 

      Methods

      -
      -class TqdmProgressBar -(n_iter, description=None, position=(0, 1)) -
      -
      -

      Wrapper of tqdm with same interface as ProgressBar.

      -

      Args

      -
      -
      n_iter : int
      -
      Number of iterations to iterate over.
      -
      description : None or str
      -
      Description of task to prefix progress -bar with.
      -
      position : Tuple[int, int]
      -
      Tuple specifying position of progress -bar within a sequence with first entry corresponding to -zero-indexed position and the second entry the total number of -progress bars.
      -
      -
      - -Expand source code -Browse git - -
      class TqdmProgressBar(BaseProgressBar):
      -    """Wrapper of `tqdm` with same interface as `ProgressBar`."""
      -
      -    def __init__(self, n_iter, description=None, position=(0, 1)):
      -        super().__init__(n_iter, description, position)
      -        self._stats_dict = {}
      -        self._tqdm_obj = None
      -
      -    def update(self, iter, iter_dict=None, refresh=True):
      -        if self._tqdm_obj is None:
      -            raise RuntimeError(
      -                'Must enter object first in context manager.')
      -        if iter == 0:
      -            self._tqdm_obj.reset()
      -        elif not self._tqdm_obj.disable:
      -            self._tqdm_obj.update(iter - self._tqdm_obj.n)
      -            if iter_dict is not None:
      -                _update_stats_running_means(
      -                    iter, self._stats_dict, iter_dict)
      -                self._tqdm_obj.set_postfix(self._stats_dict)
      -            if iter == self._n_iter:
      -                self._tqdm_obj.close()
      -            if refresh:
      -                self._tqdm_obj.refresh()
      -
      -    def __enter__(self):
      -        self._tqdm_obj = tqdm.trange(
      -            self._n_iter, desc=self._description,
      -            position=self._position[0]).__enter__()
      -        return self
      -
      -    def __exit__(self, *args):
      -        return self._tqdm_obj.__exit__(*args)
      -
      -

      Ancestors

      - -

      Methods

      -
      -
      -def update(self, iter, iter_dict=None, refresh=True) -
      -
      -

      Update progress bar state.

      -

      Args

      -
      -
      iter : int
      -
      New value for iteration counter.
      -
      iter_dict : None or Dict[str, float]
      -
      Dictionary of iteration -statistics key-value pairs to use to update postfix stats.
      -
      refresh : bool
      -
      Whether to refresh display(s).
      -
      -
      - -Expand source code -Browse git - -
      def update(self, iter, iter_dict=None, refresh=True):
      -    if self._tqdm_obj is None:
      -        raise RuntimeError(
      -            'Must enter object first in context manager.')
      -    if iter == 0:
      -        self._tqdm_obj.reset()
      -    elif not self._tqdm_obj.disable:
      -        self._tqdm_obj.update(iter - self._tqdm_obj.n)
      -        if iter_dict is not None:
      -            _update_stats_running_means(
      -                iter, self._stats_dict, iter_dict)
      -            self._tqdm_obj.set_postfix(self._stats_dict)
      -        if iter == self._n_iter:
      -            self._tqdm_obj.close()
      -        if refresh:
      -            self._tqdm_obj.refresh()
      -
      -
      -
      -
  • diff --git a/docs/docs/samplers.html b/docs/docs/samplers.html index 832264a..837175a 100644 --- a/docs/docs/samplers.html +++ b/docs/docs/samplers.html @@ -3,14 +3,14 @@ - + mici.samplers API documentation - + @@ -31,60 +31,91 @@
  • mici
  • -
  • Functions

    - -
  • Classes

  • @@ -92,14 +123,14 @@

    -

    Package mici.samplers

    +

    Module mici.samplers

    Monte Carlo sampler classes for peforming inference.

    Expand source code -Browse git +Browse git
    """Monte Carlo sampler classes for peforming inference."""
     
    @@ -117,7 +148,10 @@ 

    Package mici.samplers

    import numpy as np import mici.transitions as trans from mici.states import ChainState -from mici.progressbars import ProgressBar, DummyProgressBar, _ProxyProgressBar +from mici.progressbars import (ProgressBar, LabelledSequenceProgressBar, + DummyProgressBar, _ProxyProgressBar) +from mici.errors import AdaptationError +from mici.adapters import DualAveragingStepSizeAdapter try: @@ -134,7 +168,7 @@

    Package mici.samplers

    RANDOMGEN_AVAILABLE = False # Preferentially import from multiprocess library if available as able to -# serialise much wider range of types including autograd functions +# serialize much wider range of types including autograd functions try: from multiprocess import Pool from multiprocess.managers import SyncManager @@ -148,17 +182,17 @@

    Package mici.samplers

    logger = logging.getLogger(__name__) -def _ignore_sigint_initialiser(): - """Initialiser for processes to force ignoring SIGINT interrupt signals.""" +def _ignore_sigint_initializer(): + """Initializer for processes to force ignoring SIGINT interrupt signals.""" signal.signal(signal.SIGINT, signal.SIG_IGN) @contextmanager -def ignore_sigint_manager(): +def _ignore_sigint_manager(): """Context-managed SyncManager which ignores SIGINT interrupt signals.""" manager = SyncManager() try: - manager.start(_ignore_sigint_initialiser) + manager.start(_ignore_sigint_initializer) yield manager finally: manager.shutdown() @@ -244,9 +278,9 @@

    Package mici.samplers

    return ChainState(**state) if isinstance(state, dict) else state -def _init_chain_stats(transitions, n_sample, memmap_enabled, memmap_path, +def _init_chain_stats(transitions, n_iter, memmap_enabled, memmap_path, chain_index): - """Initialise dictionary of per-transition chain statistics array dicts.""" + """Initialize dictionary of per-transition chain statistics array dicts.""" chain_stats = {} for trans_key, trans in transitions.items(): chain_stats[trans_key] = {} @@ -257,15 +291,15 @@

    Package mici.samplers

    memmap_path, 'stats', f'{trans_key}_{key}', chain_index) chain_stats[trans_key][key] = _open_new_memmap( - filename, n_sample, val, dtype) + filename, n_iter, val, dtype) else: - chain_stats[trans_key][key] = np.full(n_sample, val, dtype) + chain_stats[trans_key][key] = np.full(n_iter, val, dtype) return chain_stats -def _init_traces(trace_funcs, init_state, n_sample, memmap_enabled, +def _init_traces(trace_funcs, init_state, n_iter, memmap_enabled, memmap_path, chain_index): - """Initialise dictionary of chain trace arrays.""" + """Initialize dictionary of chain trace arrays.""" traces = {} for trace_func in trace_funcs: for key, val in trace_func(init_state).items(): @@ -275,9 +309,9 @@

    Package mici.samplers

    filename = _generate_memmap_filename( memmap_path, 'trace', key, chain_index) traces[key] = _open_new_memmap( - filename, (n_sample,) + val.shape, init, val.dtype) + filename, (n_iter,) + val.shape, init, val.dtype) else: - traces[key] = np.full((n_sample,) + val.shape, init, val.dtype) + traces[key] = np.full((n_iter,) + val.shape, init, val.dtype) return traces @@ -341,15 +375,17 @@

    Package mici.samplers

    f' memory-mapping enabled (`memmap_enabled=True`).') -def _construct_chain_iterators(n_sample, chain_iterator_class, n_chain=None): +def _construct_chain_iterators( + n_iter, chain_iterator_class, n_chain=None, position_offset=0): """Set up chain iterator progress bar object(s).""" if n_chain is None: - return chain_iterator_class(n_iter=n_sample, description='Chain 1/1') + return chain_iterator_class(range(n_iter), description='Chain 1/1') else: return [ chain_iterator_class( - n_iter=n_sample, description=f'Chain {c+1}/{n_chain}', - position=(c, n_chain)) for c in range(n_chain)] + range(n_iter), description=f'Chain {c+1}/{n_chain}', + position=(c + position_offset, n_chain + position_offset)) + for c in range(n_chain)] def _update_chain_stats(sample_index, chain_stats, trans_key, trans_stats): @@ -406,7 +442,7 @@

    Package mici.samplers

    def _truncate_chain_data(sample_index, traces, chain_stats): - """Truncate first dimension of chain arrays to sample_index < n_sample.""" + """Truncate first dimension of chain arrays to sample_index < n_iter.""" for key in traces: traces[key] = _try_resize_dim_0_inplace(traces[key], sample_index) for trans_stats in chain_stats.values(): @@ -417,7 +453,7 @@

    Package mici.samplers

    def _sample_chain(init_state, chain_iterator, rng, transitions, trace_funcs, chain_index=0, parallel_chains=False, memmap_enabled=False, - memmap_path=None, monitor_stats=None): + memmap_path=None, monitor_stats=None, adapters=None): """Sample a chain by iteratively appyling a sequence of transition kernels. Args: @@ -429,7 +465,7 @@

    Package mici.samplers

    is iterated over to produce sample indices and (empty) iteration statistic dictionaries to output monitored chain statistics to during sampling. - rng (RandomState): Numpy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. transitions (OrderedDict[str, Transition]): Ordered dictionary of Markov transitions kernels to sequentially sample from on each chain iteration. @@ -462,6 +498,17 @@

    Package mici.samplers

    the `chain_stats` dictionary. The mean over samples computed so far of the chain statistics associated with any valid key-pairs will be monitored during sampling by printing as postfix to progress bar. + adapters (Dict[str, Iterable[Adapter]): Dictionary of iterables of + `mici.adapters.Adapter` instances keyed by strings corresponding to + the key of the transition in the `transitions` dictionary to apply + the adapters to. Each adapter is able to adaptatively set the + parameters of a transition while sampling a chain. Note that the + adapter updates for each transition are applied in the order the + adapters appear in the iterable and so if multiple adapters change + the same parameter(s) the order will matter. Adaptation based on the + chain state history breaks the Markov property and so any chain + samples while adaptation is active should not be used in estimates + of expectations. Returns: final_state (mici.states.ChainState): State of chain after final @@ -481,18 +528,31 @@

    Package mici.samplers

    dimension of each array corresponding to the sampling (draw) index. The key for each value is a string description of the corresponding integration transition statistic. - interrupted (bool): Whether sampling was manually interrupted before - all chain iterations were completed. + exception (None or Exception): Any handled exception which may affect + how the returned outputs are processed by the caller. """ state = _check_and_process_init_state(init_state, transitions) - n_sample = len(chain_iterator) + n_iter = len(chain_iterator) # Create temporary directory if memory mapping and no path provided if memmap_enabled and memmap_path is None: memmap_path = tempfile.mkdtemp() chain_stats = _init_chain_stats( - transitions, n_sample, memmap_enabled, memmap_path, chain_index) + transitions, n_iter, memmap_enabled, memmap_path, chain_index) traces = _init_traces( - trace_funcs, state, n_sample, memmap_enabled, memmap_path, chain_index) + trace_funcs, state, n_iter, memmap_enabled, memmap_path, chain_index) + adapter_states = {} + try: + if adapters is not None: + for trans_key, adapter_list in adapters.items(): + adapter_states[trans_key] = [] + for adapter in adapter_list: + adapter_states[trans_key].append( + adapter.initialize(state, transitions[trans_key])) + except AdaptationError as exception: + logger.error( + f'Initialisation of {type(adapter).__name__} for chain ' + f'{chain_index + 1} failed: {exception}') + return state, traces, chain_stats, adapter_states, exception try: sample_index = 0 if parallel_chains and not memmap_enabled: @@ -501,6 +561,11 @@

    Package mici.samplers

    for sample_index, monitor_dict in chain_iterator: for trans_key, transition in transitions.items(): state, trans_stats = transition.sample(state, rng) + if adapters is not None and trans_key in adapters: + for adapter, adapter_state in zip( + adapters[trans_key], adapter_states[trans_key]): + adapter.update( + adapter_state, state, trans_stats, transition) _update_chain_stats( sample_index, chain_stats, trans_key, trans_stats) for trace_func in trace_funcs: @@ -509,28 +574,24 @@

    Package mici.samplers

    if monitor_stats is not None: _update_monitor_stats( sample_index, chain_stats, monitor_stats, monitor_dict) - except KeyboardInterrupt: - interrupted = True - if sample_index != n_sample: - if not parallel_chains: - logger.error( - f'Sampling manually interrupted at chain {chain_index + 1}' - f' iteration {sample_index}. Arrays containing chain ' - f'traces and statistics computed before interruption will ' - f'be returned.') - # Sampling interrupted therefore truncate returned arrays - # No point truncating if using memory mapping with parallel chains - # as will only return file paths of arrays - if not (parallel_chains and memmap_enabled): - _truncate_chain_data(sample_index, traces, chain_stats) + except KeyboardInterrupt as e: + exception = e + logger.error( + f'Sampling manually interrupted for chain {chain_index + 1} at' + f' iteration {sample_index}. Arrays containing chain traces and' + f' statistics computed before interruption will be returned.') + # Sampling interrupted therefore truncate returned arrays unless using + # memory mapping with parallel chains as will only return file paths + if not (parallel_chains and memmap_enabled): + _truncate_chain_data(sample_index, traces, chain_stats) else: - interrupted = False + exception = None if memmap_enabled: _flush_memmap_chain_data(traces, chain_stats) if parallel_chains and memmap_enabled: - traces = _memmaps_to_file_paths(traces) - chain_stats = _memmaps_to_file_paths(chain_stats) - return state, traces, chain_stats, interrupted + traces = _memmaps_to_file_paths(traces) + chain_stats = _memmaps_to_file_paths(chain_stats) + return state, traces, chain_stats, adapter_states, exception def _collate_chain_outputs(chain_outputs): @@ -542,8 +603,10 @@

    Package mici.samplers

    """ final_states_stack = [] traces_stack = {} - chain_stats_stack = {} - for chain_index, (final_state, traces, stats) in enumerate(chain_outputs): + stats_stack = {} + adapt_states_stack = {} + for chain_index, (final_state, traces, + stats, adapt_states) in enumerate(chain_outputs): final_states_stack.append(final_state) for key, val in traces.items(): # if value is string => file path to memory mapped array @@ -555,16 +618,22 @@

    Package mici.samplers

    traces_stack[key].append(val) for trans_key, trans_stats in stats.items(): if chain_index == 0: - chain_stats_stack[trans_key] = {} + stats_stack[trans_key] = {} for key, val in trans_stats.items(): # if value is string => file path to memory mapped array if isinstance(val, str): val = np.lib.format.open_memmap(val) if chain_index == 0: - chain_stats_stack[trans_key][key] = [val] + stats_stack[trans_key][key] = [val] else: - chain_stats_stack[trans_key][key].append(val) - return final_states_stack, traces_stack, chain_stats_stack + stats_stack[trans_key][key].append(val) + for trans_key, adapt_state_list in adapt_states.items(): + if trans_key not in adapt_states_stack: + adapt_states_stack[trans_key] = [[a] for a in adapt_state_list] + else: + for i, adapt_state in enumerate(adapt_state_list): + adapt_states_stack[trans_key][i].append(adapt_state) + return final_states_stack, traces_stack, stats_stack, adapt_states_stack def _get_per_chain_rngs(base_rng, n_chain): @@ -611,13 +680,18 @@

    Package mici.samplers

    chain_outputs = [] for chain_index, (init_state, rng, chain_iterator) in enumerate( zip(init_states, rngs, chain_iterators)): - final_state, traces, stats, interrupted = _sample_chain( + *outputs, exception = _sample_chain( chain_iterator=chain_iterator, init_state=init_state, rng=rng, chain_index=chain_index, parallel_chains=False, **kwargs) - chain_outputs.append((final_state, traces, stats)) - if interrupted: + # Returned exception being AdaptationError indicates chain terminated + # due to adapter initialisation failing therefore do not store returned + # chain outputs + if not isinstance(exception, AdaptationError): + chain_outputs.append(outputs) + # If returned handled exception was a manual interrupt break and return + if isinstance(exception, KeyboardInterrupt): break - return _collate_chain_outputs(chain_outputs) + return (*_collate_chain_outputs(chain_outputs), exception) def _sample_chains_worker(chain_queue, iter_queue): @@ -629,46 +703,62 @@

    Package mici.samplers

    chain_outputs = [] while not chain_queue.empty(): try: - chain_index, init_state, rng, n_sample, kwargs = chain_queue.get( + chain_index, init_state, rng, n_iter, kwargs = chain_queue.get( block=False) - *outputs, interrupted = _sample_chain( + *outputs, exception = _sample_chain( init_state=init_state, rng=rng, chain_index=chain_index, chain_iterator=_ProxyProgressBar( - n_sample, chain_index, iter_queue), + range(n_iter), chain_index, iter_queue), parallel_chains=True, **kwargs) - chain_outputs.append((chain_index, outputs)) - if interrupted: + # Returned exception being AdaptationError indicates chain + # terminated due to adapter initialisation failing therefore do not + # store returned chain outputs and put None value on iteration queue + # to indicate to parent process chain terminated + if isinstance(exception, AdaptationError): + iter_queue.put(None) + else: + chain_outputs.append((chain_index, outputs)) + # If returned handled exception was a manual interrupt put exception + # on iteration queue to communicate to parent process and break + if isinstance(exception, KeyboardInterrupt): + iter_queue.put(exception) break except queue.Empty: pass - except KeyboardInterrupt: - # Put sentinel value on iteration queue to force exit from - # iteration update loop - iter_queue.put(None) - except Exception as e: - # Put sentinel value on iteration queue to force exit from - # iteration update loop - iter_queue.put(None) - raise e + except Exception as exception: + # Log exception here so that correct traceback is logged + logger.error('Exception encountered in chain worker process:', + exc_info=exception) + # Put exception on iteration queue to be reraised in parent process + iter_queue.put(exception) return chain_outputs +def _finalize_adapters(adapter_states, adapters, transitions): + """Finalize adapter updates to transitions based on final adapter states.""" + for trans_key, adapter_state_list in adapter_states.items(): + for adapter_state, adapter in zip( + adapter_state_list, adapters[trans_key]): + adapter.finalize(adapter_state, transitions[trans_key]) + + def _sample_chains_parallel(init_states, rngs, chain_iterators, n_process, **kwargs): """Sample multiple chains in parallel over multiple processes.""" - n_samples = [len(it) for it in chain_iterators] + n_iters = [len(it) for it in chain_iterators] n_chain = len(chain_iterators) - with ignore_sigint_manager() as manager, Pool(n_process) as pool: + with _ignore_sigint_manager() as manager, Pool(n_process) as pool: results = None + exception = None try: # Shared queue for workers to output chain progress updates to iter_queue = manager.Queue() # Shared queue for workers to get arguments for _sample_chain calls # from on initialising each chain chain_queue = manager.Queue() - for c, (init_state, rng, n_sample) in enumerate( - zip(init_states, rngs, n_samples)): - chain_queue.put((c, init_state, rng, n_sample, kwargs)) + for c, (init_state, rng, n_iter) in enumerate( + zip(init_states, rngs, n_iters)): + chain_queue.put((c, init_state, rng, n_iter, kwargs)) # Start n_process worker processes which each have access to the # shared queues, returning results asynchronously results = pool.starmap_async( @@ -687,14 +777,31 @@

    Package mici.samplers

    chains_completed = 0 while not (iter_queue.empty() and chains_completed == n_chain): iter_queue_item = iter_queue.get() - # Check if queue item is sentinel value and if so break + # Queue item being None indicates a chain terminated early + # due to a non-fatal error e.g. an error in initialising an + # adapter. In this case we continue sampling any other + # remaining chains but increment the completed chains + # counter to ensure correct termination of chain progress + # update loop if iter_queue_item is None: - break - # Otherwise unpack and update progress bar - chain_index, sample_index, data_dict = iter_queue_item - pbars[chain_index].update(sample_index, data_dict) - if sample_index == n_samples[chain_index]: chains_completed += 1 + # If queue item is KeyboardInterrupt exception break out of + # chain progress update loop but do not reraise exception + # so that partial chain outputs are returned + elif isinstance(iter_queue_item, KeyboardInterrupt): + exception = iter_queue_item + break + # Re raise any other exception passed from worker processes + elif isinstance(iter_queue_item, Exception): + raise RuntimeError( + 'Unhandled exception in chain worker process.' + ) from iter_queue_item + else: + # Otherwise unpack and update progress bar + chain_index, sample_index, data_dict = iter_queue_item + pbars[chain_index].update(sample_index, data_dict) + if sample_index == n_iters[chain_index]: + chains_completed += 1 except (PicklingError, AttributeError) as e: if not MULTIPROCESS_AVAILABLE and ( isinstance(e, PicklingError) or 'pickle' in str(e)): @@ -714,12 +821,9 @@

    Package mici.samplers

    ) from e else: raise e - except KeyboardInterrupt: + except KeyboardInterrupt as e: # Interrupts handled in child processes therefore ignore here - logger.error( - 'Sampling manually interrupted. Arrays containing chain traces' - ' and statistics computed prior to interruption will be ' - 'returned.') + exception = e if results is not None: # Join all output lists from per-process workers in to single list indexed_chain_outputs = sum((res for res in results.get()), []) @@ -728,7 +832,77 @@

    Package mici.samplers

    chain_outputs = [outp for i, outp in sorted(indexed_chain_outputs)] else: chain_outputs = [] - return _collate_chain_outputs(chain_outputs) + return (*_collate_chain_outputs(chain_outputs), exception) + + +def _set_up_sampling_stages( + n_warm_up_iter, n_main_iter, fast_adapters, slow_adapters, + trace_funcs, n_init_slow_window_iter, n_init_fast_stage_iter, + n_final_fast_stage_iter, slow_window_multiplier): + """Create dictionary specifying labels and parameters of sampling stages. + + Constructs an ordered dictionary with entries corresponding to the sequence + of sampling stages when running chains with one or more initial adaptation + stages. The keys of each entry are string labels for the sampling stage and + the values a 3-tuple `(n_iter, adapters, trace_funcs)` with `n_iter` the + number of chain iterations in the stage, `adapters` a dictionary of + transition adapters to pass to the `_sample_chain` call (or `None` if no + adaptation to be used) and `trace_func` a list of trace functions to pass + to the `_sample_chain` call (list may be empty if no values to be traced). + """ + use_single_adaptive_stage = slow_adapters is None or len(slow_adapters) == 0 + if not use_single_adaptive_stage and ( + n_init_fast_stage_iter + n_init_slow_window_iter + + n_final_fast_stage_iter > n_warm_up_iter): + n_init_fast_stage_iter = int(0.15 * n_warm_up_iter) + n_final_fast_stage_iter = int(0.1 * n_warm_up_iter) + n_init_slow_window_iter = ( + n_warm_up_iter - n_init_fast_stage_iter - n_final_fast_stage_iter) + if use_single_adaptive_stage: + sampling_stages = OrderedDict( + {'Adaptive warm up': (n_warm_up_iter, fast_adapters, [])}) + else: + # slow adaptation windows use both fast and slow adapters + fast_and_slow_adapters = { + trans_key: adapter_list.copy() + for trans_key, adapter_list in fast_adapters.items()} + for trans_key, adapter_list in slow_adapters.items(): + if trans_key in fast_and_slow_adapters: + fast_and_slow_adapters[trans_key] += adapter_list + else: + fast_and_slow_adapters[trans_key] = adapter_list + # initial fast adaptation stage + sampling_stages = OrderedDict( + {'Initial fast adaptive': ( + n_init_fast_stage_iter, fast_adapters, [])}) + # growing size slow adaptation windows + n_window_iter = n_init_slow_window_iter + slow_windows = [] + counter = 0 + n_slow_stage_iter = ( + n_warm_up_iter - n_init_fast_stage_iter - n_final_fast_stage_iter) + while counter < n_slow_stage_iter: + # check if iteration counter at end of next loop iteration will be + # greater than total number of warm up iterations and if so set + # number of iterations in current window to be equal to all + # remaining warm up iterations + counter_next = ( + counter + int((1 + slow_window_multiplier) * n_window_iter)) + if counter_next > n_slow_stage_iter: + n_window_iter = n_slow_stage_iter - counter + slow_windows.append(n_window_iter) + counter += n_window_iter + n_window_iter = int(slow_window_multiplier * n_window_iter) + for i, n_iter in enumerate(slow_windows): + sampling_stages[ + f'Slow adaptive ({i + 1}/{len(slow_windows)})'] = ( + n_iter, fast_and_slow_adapters, []) + # final fast adaptation stage + sampling_stages['Final fast adaptive'] = ( + n_final_fast_stage_iter, fast_adapters, []) + # main non-adaptive stage + sampling_stages['Main non-adaptive'] = (n_main_iter, None, trace_funcs) + return sampling_stages class MarkovChainMonteCarloMethod(object): @@ -741,7 +915,7 @@

    Package mici.samplers

    def __init__(self, rng, transitions): """ Args: - rng (RandomState): Numpy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. transitions (OrderedDict[str, Transition]): Ordered dictionary of Markov transitions kernels to sequentially sample from on each chain iteration. @@ -760,7 +934,7 @@

    Package mici.samplers

    elif 'progress_bar_class' not in kwargs: kwargs['progress_bar_class'] = ProgressBar - def sample_chain(self, n_sample, init_state, trace_funcs, **kwargs): + def sample_chain(self, n_iter, init_state, trace_funcs, **kwargs): """Sample a Markov chain from a given initial state. Performs a specified number of chain iterations (each of which may be @@ -768,7 +942,7 @@

    Package mici.samplers

    outputs of functions of the sampled chain state after each iteration. Args: - n_sample (int): Number of samples (iterations) to draw per chain. + n_iter (int): Number of iterations (samples to draw) per chain. init_state (mici.states.ChainState or Dict[str, object]): Initial chain state. Either a `mici.states.ChainState` object or a dictionary with entries specifying initial values for all state @@ -810,6 +984,17 @@

    Package mici.samplers

    factory function for progress bar to use to show chain progress if enabled (`display_progress=True`). Defaults to `mici.progressbars.ProgressBar`. + adapters (Dict[str, Iterable[Adapter]): Dictionary of iterables of + `mici.adapters.Adapter` instances keyed by strings corresponding + to the key of the transition in the `transitions` dictionary to + apply the adapters to. Each adapter is able to adaptatively set + the parameters of a transition while sampling a chain. Note that + the adapter updates for each transition are applied in the order + the adapters appear in the iterable and so if multiple adapters + change the same parameter(s) the order will matter. Adaptation + based on the chain state history breaks the Markov property and + so any chain samples while adaptation is active should not be + used in estimates of expectations. Returns: final_state (mici.states.ChainState): State of chain after final @@ -833,14 +1018,18 @@

    Package mici.samplers

    """ self.__set_sample_chain_kwargs_defaults(kwargs) chain_iterator = _construct_chain_iterators( - n_sample, kwargs.pop('progress_bar_class')) - final_state, traces, chain_stats, interrupted = _sample_chain( + n_iter, kwargs.pop('progress_bar_class')) + final_state, traces, chain_stats, adapter_states, _ = _sample_chain( init_state=init_state, chain_iterator=chain_iterator, transitions=self.transitions, rng=self.rng, trace_funcs=trace_funcs, parallel_chains=False, **kwargs) + if len(adapter_states) > 0: + _finalize_adapters( + adapter_states, kwargs['adapters'], self.transitions) + return final_state, traces, chain_stats - def sample_chains(self, n_sample, init_states, trace_funcs, n_process=1, + def sample_chains(self, n_iter, init_states, trace_funcs, n_process=1, **kwargs): """Sample one or more Markov chains from given initial states. @@ -851,7 +1040,7 @@

    Package mici.samplers

    or sequentially. In all cases all chains use independent random draws. Args: - n_sample (int): Number of samples (iterations) to draw per chain. + n_iter (int): Number of iterations (samples to draw) per chain. init_states (Iterable[ChainState] or Iterable[Dict[str, object]]): Initial chain states. Each entry can be either a `ChainState` object or a dictionary with entries specifying initial values @@ -900,6 +1089,17 @@

    Package mici.samplers

    factory function for progress bar to use to show chain progress if enabled (`display_progress=True`). Defaults to `mici.progressbars.ProgressBar`. + adapters (Dict[str, Iterable[Adapter]): Dictionary of iterables of + `mici.adapters.Adapter` instances keyed by strings corresponding + to the key of the transition in the `transitions` dictionary to + apply the adapters to. Each adapter is able to adaptatively set + the parameters of a transition while sampling a chain. Note that + the adapter updates for each transition are applied in the order + the adapters appear in the iterable and so if multiple adapters + change the same parameter(s) the order will matter. Adaptation + based on the chain state history breaks the Markov property and + so any chain samples while adaptation is active should not be + used in estimates of expectations. Returns: final_states (List[ChainState]): States of chains after final @@ -927,24 +1127,239 @@

    Package mici.samplers

    n_chain = len(init_states) rngs = _get_per_chain_rngs(self.rng, n_chain) chain_iterators = _construct_chain_iterators( - n_sample, kwargs.pop('progress_bar_class'), n_chain) + n_iter, kwargs.pop('progress_bar_class'), n_chain) if n_process == 1: # Using single process therefore run chains sequentially - return _sample_chains_sequential( + *states_traces_stats, adapter_states, _ = _sample_chains_sequential( init_states=init_states, rngs=rngs, chain_iterators=chain_iterators, transitions=self.transitions, trace_funcs=trace_funcs, **kwargs) else: # Run chains in parallel using a multiprocess(ing).Pool - return _sample_chains_parallel( + *states_traces_stats, adapter_states, _ = _sample_chains_parallel( init_states=init_states, rngs=rngs, chain_iterators=chain_iterators, transitions=self.transitions, trace_funcs=trace_funcs, n_process=n_process, **kwargs) + if len(adapter_states) > 0: + _finalize_adapters( + adapter_states, kwargs['adapters'], self.transitions) + return states_traces_stats + + def sample_chains_with_adaptive_warm_up( + self, n_warm_up_iter, n_main_iter, init_states, trace_funcs, + fast_adapters, slow_adapters=None, n_process=1, + n_init_slow_window_iter=25, n_init_fast_stage_iter=75, + n_final_fast_stage_iter=50, slow_window_multiplier=2, **kwargs): + """Sample Markov chains from given initial states with adaptive warm up. + + One or more Markov chains are sampled, with each chain iteration + consisting of one or more Markov transitions. The chains are split into + multiple *stages* with one or more adaptive warm up stages followed by + the main non-adaptive sampling stage. During the adaptive stage(s) + parameters of the transition(s) are adaptively tuned based on the chain + state and/or transition statistics. + + Following the approach of [Stan](https://mc-stan.org) the adaptive + stages are split in to two types - 'fast' adaptation stages which adjust + only transition parameters which can be adapted quickly using local + information and 'slow' adaptation stages which *addtionally* adjust + transition parameters which require more global information. The + adapters to be used in both the fast and slow adaptation stages will be + referred to as the *fast adapters* and the adapters to use in only the + slow adaptation stages the *slow adapters*. + + If only fast adapters are specified the adaptive warm up iterations will + form a single fast adaptive stage. If both slow and fast adapters are + specified the adaptive warm up iterations will be split into three + stages: + + 1. An initial fast adaptive stage with only fast adapters active. + 2. A slow adaptive stage with both slow and fast adapters active. + 3. A final adaptive stage with only fast adapters active. + + The slow sampling stage (2) is further split in to a sequence of + growing, memoryless windows with the adapter stages reset at the + beginning of each window, and the number of iterations in each window + increasing (by default doubling). The split of the iterations in each of + these stages can be controlled using the keyword arguments + `n_init_fast_stage_iter`, `n_init_slow_window_iter`, + `n_final_fast_stage_iter` and `slow_window_multiplier` (see descriptions + below). + + In both cases after the initial adaptive warm up stage(s) a subsequent + main sampling stage with no further adaptation is performed. Only in + this main sampling stage are traces of the chain state recorded by + storing the outputs of functions of the sampled chain state after each + iteration. + + The chains (including both adaptive and non-adaptive stages) may be run + in parallel across multiple independent processes or sequentially. In + all cases all chains use independent random draws. + + Args: + n_warm_up_iter (int): Number of adaptive warm up iterations per + chain. Depending on the adapters specified by the + `fast_adapters` and `slow_adapters` arguments the warm up + iterations may be split between one or more adaptive stages. + The keyword arguments `n_init_fast_stage_iter`, + `n_init_slow_window_iter`, `n_final_fast_stage_iter` and + `slow_window_multiplier` can be used to control the split of + the warm up iterations into these different stages - for details + see descriptions of the individual keyword arguments below. + n_main_iter (int): Number of iterations (samples to draw) per chain + during main (non-adaptive) sampling stage. + init_states (Iterable[ChainState] or Iterable[Dict[str, object]]): + Initial chain states. Each entry can be either a `ChainState` + object or a dictionary with entries specifying initial values + for all state variables used by chain transition `sample` + methods. + trace_funcs (Iterable[Callable[[ChainState], Dict[str, array]]]): + List of functions which compute the variables to be recorded at + each chain iteration during the main non-adaptive sampling + stage, with each trace function being passed the current state + and returning a dictionary of scalar or array values + corresponding to the variable(s) to be stored. The keys in the + returned dictionaries are used to index the trace arrays in the + returned traces dictionary. If a key appears in multiple + dictionaries only the the value corresponding to the last trace + function to return that key will be stored. + fast_adapters (Dict[str, Iterable[Adapter]): Dictionary of iterables + of `mici.adapters.Adapter` instances keyed by strings + corresponding to the key of the transition in the `transitions` + dictionary to apply the adapters to, to use to adaptatively set + parameters of the transitions during the adaptive (both fast and + slow) stages of the chains. Note that the adapter updates are + applied in the order the adapters appear in the iterables and so + if multiple adapters change the same parameter(s) the order will + matter. + Kwargs: + slow_adapters (Dict[str, Iterable[Adapter]): Dictionary of iterables + of `mici.adapters.Adapter` instances keyed by strings + corresponding to the key of the transition in the `transitions` + dictionary to apply the adapters to, to use to adaptatively set + parameters of the transitions during the slow adaptive stage of + the chains. Note that the adapter updates are applied in the + order the adapters appear in the iterables and so if multiple + adapters change the same parameter(s) the order will matter. + Default is to use no slow adapters. + n_process (int or None): Number of parallel processes to run chains + over. If `n_process=1` then chains will be run sequentially + otherwise a `multiprocessing.Pool` object will be used to + dynamically assign the chains across multiple processes. If set + to `None` then the number of processes will be set to the + output of `os.cpu_count()`. Default is `n_process=1`. + n_init_slow_window_iter (int): Number of iterations in the initial + (smallest) window in the slow adaptation stage. Defaults to 25. + If the sum of `n_init_slow_window_iter`, + `n_init_fast_stage_iter` and `n_final_fast_stage_iter` is more + than `n_warm_up_iter` then `n_init_slow_window_iter` is set to + approximately 75% of `n_warm_up_iter` (with a single window + being used in the slow adaptation stage in this case). + n_init_fast_stage_iter (int): Number of iterations in the initial + fast adaptation stage. Defaults to 75. If the sum of + `n_init_slow_window_iter`, n_init_fast_stage_iter` and + `n_final_fast_stage_iter` is more than `n_warm_up_iter` then + `n_init_fast_stage_iter` is set to approximately 15% of + `n_warm_up_iter`. + n_final_fast_stage_iter (int): Number of iterations in the final + fast adaptation stage. Defaults to 50. If the sum of + `n_init_slow_window_iter`, `n_init_fast_stage_iter` and + `n_final_fast_stage_iter` is more than `n_warm_up_iter` then + `n_init_fast_stage_iter` is set to approximately 10% of + `n_warm_up_iter`. + slow_window_multiplier (float): Multiplier by which to increase the + number of iterations of each subsequent slow adaptation window + by. Defaults to 2 such that each window doubles in size. + memmap_enabled (bool): Whether to memory-map arrays used to store + chain data to files on disk to avoid excessive system memory + usage for long chains and/or large chain states. The chain data + is written to `.npy` files in the directory specified by + `memmap_path` (or a temporary directory if not provided). These + files persist after the termination of the function so should + be manually deleted when no longer required. Default is to + for memory mapping to be disabled. + memmap_path (str): Path to directory to write memory-mapped chain + data to. If not provided, a temporary directory will be created + and the chain data written to files there. + monitor_stats (Iterable[Tuple[str, str]]): List of tuples of string + key pairs, with first entry the key of a Markov transition in + the `transitions` dict passed to the the `__init__` method and + the second entry the key of a chain statistic that will be + returned in the `chain_stats` dictionary. The mean over samples + computed so far of the chain statistics associated with any + valid key-pairs will be monitored during sampling by printing + as postfix to progress bar. + display_progress (bool): Whether to display a progress bar to + track the completed chain sampling iterations. Default value + is `True`, i.e. to display progress bar. + progress_bar_class (mici.progressbars.BaseProgressBar): Class or + factory function for progress bar to use to show chain + progress if enabled (`display_progress=True`). Defaults to + `mici.progressbars.ProgressBar`. -def _pos_trace_func(state): - """Trace function which records the state position (pos) component.""" - return {'pos': state.pos} + Returns: + final_states (List[ChainState]): States of chains after final + iteration. May be used to resume sampling a chain by passing as + the initial states to a new `sample_chains` call. + traces (Dict[str, List[array]]): Dictionary of chain trace arrays. + Values in dictionary are list of arrays of variables outputted + by trace functions in `trace_funcs` with each array in the list + corresponding to a single chain and the leading dimension of + each array corresponding to the iteration (draw) index in the + main non-adaptive sampling stage. The key for each value is the + corresponding key in the dictionary returned by the trace + function which computed the traced value. + chain_stats (Dict[str, Dict[str, List[array]]]): Dictionary of + chain transition statistic dictionaries. Values in outer + dictionary are dictionaries of statistics for each chain + transition, keyed by the string key for the transition. The + values in each inner transition dictionary are lists of arrays + of chain statistic values with each array in the list + corresponding to a single chain and the leading dimension of + each array corresponding to the iteration (draw) index in the + main non-adaptive sampling stage. The key for each value is a + string description of the corresponding integration transition + statistic. + """ + self.__set_sample_chain_kwargs_defaults(kwargs) + if 'adapters' in kwargs: + raise ValueError( + 'Transition adapters should be specified via `fast_adapters` ' + 'and `slow_adapters` arguments rather than `adapters`.') + n_chain = len(init_states) + rngs = _get_per_chain_rngs(self.rng, n_chain) + progress_bar_class = kwargs.pop('progress_bar_class') + common_sample_chains_kwargs = { + 'rngs': rngs, 'transitions': self.transitions, **kwargs} + if n_process > 1: + sample_chains_func = _sample_chains_parallel + common_sample_chains_kwargs['n_process'] = n_process + else: + sample_chains_func = _sample_chains_sequential + sampling_stages = _set_up_sampling_stages( + n_warm_up_iter, n_main_iter, fast_adapters, slow_adapters, + trace_funcs, n_init_slow_window_iter, n_init_fast_stage_iter, + n_final_fast_stage_iter, slow_window_multiplier) + with LabelledSequenceProgressBar( + sampling_stages, 'Sampling stage', position=(0, n_chain + 1) + ) as sampling_stages_pb: + chain_iterators = _construct_chain_iterators( + n_warm_up_iter, progress_bar_class, n_chain, 1) + for (n_iter, adapters, trace_funcs), _ in sampling_stages_pb: + for chain_it in chain_iterators: + chain_it.sequence = range(n_iter) + chain_states, traces, stats, adapter_states, exception = ( + sample_chains_func( + init_states=init_states, trace_funcs=trace_funcs, + adapters=adapters, chain_iterators=chain_iterators, + **common_sample_chains_kwargs)) + if len(adapter_states) > 0: + _finalize_adapters( + adapter_states, adapters, self.transitions) + if isinstance(exception, KeyboardInterrupt): + return chain_states, traces, stats + return chain_states, traces, stats class HamiltonianMCMC(MarkovChainMonteCarloMethod): @@ -983,7 +1398,7 @@

    Package mici.samplers

    """ Args: system (mici.systems.System): Hamiltonian system to be simulated. - rng (RandomState): Numpy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. integration_transition (mici.transitions.IntegrationTransition): Markov transition kernel which leaves canonical distribution invariant and jointly updates the position and momentum @@ -1020,9 +1435,11 @@

    Package mici.samplers

    return init_state def __set_sample_chain_kwargs_defaults(self, kwargs): - # default to tracing only position component of state + # default to tracing position component of state and Hamiltonian if 'trace_funcs' not in kwargs: - kwargs['trace_funcs'] = [_pos_trace_func] + def default_trace_func(state): + return {'pos': state.pos, 'hamiltonian': self.system.h(state)} + kwargs['trace_funcs'] = [default_trace_func] # if `monitor_stats` specified, expand all statistics keys to key pairs # with transition key set to `integration_transition` if 'monitor_stats' in kwargs: @@ -1031,9 +1448,14 @@

    Package mici.samplers

    for stats_key in kwargs['monitor_stats']] else: kwargs['monitor_stats'] = [ - ('integration_transition', 'accept_prob')] - - def sample_chain(self, n_sample, init_state, **kwargs): + ('integration_transition', 'accept_stat')] + # if adapters kwarg specified, wrap adapter list in dictionary with + # adapters applied to integration transition + for key in ['adapters', 'fast_adapters', 'slow_adapters']: + if key in kwargs and kwargs[key] is not None: + kwargs[key] = {'integration_transition': kwargs[key]} + + def sample_chain(self, n_iter, init_state, **kwargs): """Sample a Markov chain from a given initial state. Performs a specified number of chain iterations (each of which may be @@ -1041,7 +1463,7 @@

    Package mici.samplers

    outputs of functions of the sampled chain state after each iteration. Args: - n_sample (int): Number of samples (iterations) to draw per chain. + n_iter (int): Number of iterations (samples to draw) per chain. init_state (mici.states.ChainState or array): Initial chain state. The state can be either an array specifying the state position component or a `mici.states.ChainState` instance. If an array @@ -1058,22 +1480,25 @@

    Package mici.samplers

    in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace - function to return that key will be stored. + function to return that key will be stored. Default is to use a + single function which recordes the position component of the + state under the key `pos` and the Hamiltonian at the state + under the key `hamiltonian`. memmap_enabled (bool): Whether to memory-map arrays used to store chain data to files on disk to avoid excessive system memory usage for long chains and/or large chain states. The chain data is written to `.npy` files in the directory specified by `memmap_path` (or a temporary directory if not provided). These files persist after the termination of the function so should - be manually deleted when no longer required. Default is to - for memory mapping to be disabled. + be manually deleted when no longer required. Default is for + memory mapping to be disabled. memmap_path (str): Path to directory to write memory-mapped chain data to. If not provided, a temporary directory will be created and the chain data written to files there. monitor_stats (Iterable[str]): List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default - is to print only the mean `accept_prob` statistic. + is to print only the mean `accept_stat` statistic. display_progress (bool): Whether to display a progress bar to track the completed chain sampling iterations. Default value is `True`, i.e. to display progress bar. @@ -1081,6 +1506,16 @@

    Package mici.samplers

    factory function for progress bar to use to show chain progress if enabled (`display_progress=True`). Defaults to `mici.progressbars.ProgressBar`. + adapters (Iterable[Adapter]): Sequence of `mici.adapters.Adapter` + instances to use to adaptatively set parameters of the + integration transition such as the step size while sampling a + chain. Note that the adapter updates are applied in the order + the adapters appear in the iterable and so if multiple adapters + change the same parameter(s) the order will matter. Adaptation + based on the chain state history breaks the Markov property and + so any chain samples while adaptation is active should not be + used in estimates of expectations. Default is to use no + adapters. Returns: final_state (mici.states.ChainState): State of chain after final @@ -1102,21 +1537,21 @@

    Package mici.samplers

    init_state = self._preprocess_init_state(init_state) self.__set_sample_chain_kwargs_defaults(kwargs) final_state, traces, chain_stats = super().sample_chain( - n_sample, init_state, **kwargs) + n_iter, init_state, **kwargs) chain_stats = chain_stats.get('integration_transition', {}) return final_state, traces, chain_stats - def sample_chains(self, n_sample, init_states, **kwargs): + def sample_chains(self, n_iter, init_states, **kwargs): """Sample one or more Markov chains from given initial states. - Performs a specified number of chain iterations (each of consists of a - momentum transition and integration transition), recording the outputs - of functions of the sampled chain state after each iteration. The - chains may be run in parallel across multiple independent processes or - sequentially. In all cases all chains use independent random draws. + Performs a specified number of chain iterations, each of consisting of a + momentum transition followed by an integration transition, recording the + outputs of functions of the sampled chain state after each iteration. + The chains may be run in parallel across multiple independent processes + or sequentially. In all cases all chains use independent random draws. Args: - n_sample (int): Number of samples (iterations) to draw per chain. + n_iter (int): Number of iterations (samples to draw) per chain. init_states (Iterable[ChainState] or Iterable[array]): Initial chain states. Each state can be either an array specifying the state position component or a `mici.states.ChainState` @@ -1127,7 +1562,7 @@

    Package mici.samplers

    Kwargs: n_process (int or None): Number of parallel processes to run chains - over. If set to one then chains will be run sequentially in + over. If `n_process=1` then chains will be run sequentially otherwise a `multiprocessing.Pool` object will be used to dynamically assign the chains across multiple processes. If set to `None` then the number of processes will be set to the @@ -1140,22 +1575,25 @@

    Package mici.samplers

    in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace - function to return that key will be stored. + function to return that key will be stored. Default is to use a + single function which recordes the position component of the + state under the key `pos` and the Hamiltonian at the state + under the key `hamiltonian`. memmap_enabled (bool): Whether to memory-map arrays used to store chain data to files on disk to avoid excessive system memory usage for long chains and/or large chain states. The chain data is written to `.npy` files in the directory specified by `memmap_path` (or a temporary directory if not provided). These files persist after the termination of the function so should - be manually deleted when no longer required. Default is to - for memory mapping to be disabled. + be manually deleted when no longer required. Default is for + memory mapping to be disabled. memmap_path (str): Path to directory to write memory-mapped chain - data to. If not provided, a temporary directory will be created - and the chain data written to files there. + data to. If not provided (the default), a temporary directory + will be created and the chain data written to files there. monitor_stats (Iterable[str]): List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default - is to print only the mean `accept_prob` statistic. + is to print only the mean `accept_stat` statistic. display_progress (bool): Whether to display a progress bar to track the completed chain sampling iterations. Default value is `True`, i.e. to display progress bar. @@ -1163,6 +1601,16 @@

    Package mici.samplers

    factory function for progress bar to use to show chain progress if enabled (`display_progress=True`). Defaults to `mici.progressbars.ProgressBar`. + adapters (Iterable[Adapter]): Sequence of `mici.adapters.Adapter` + instances to use to adaptatively set parameters of the + integration transition such as the step size while sampling a + chain. Note that the adapter updates are applied in the order + the adapters appear in the iterable and so if multiple adapters + change the same parameter(s) the order will matter. Adaptation + based on the chain state history breaks the Markov property and + so any chain samples while adaptation is active should not be + used in estimates of expectations. Default is to use no + adapters. Returns: final_states (List[ChainState]): States of chains after final @@ -1172,21 +1620,210 @@

    Package mici.samplers

    Values in dictionary are list of arrays of variables outputted by trace functions in `trace_funcs` with each array in the list corresponding to a single chain and the leading dimension of - each array corresponding to the sampling (draw) index. The key + each array corresponding to the iteration (draw) index. The key for each value is the corresponding key in the dictionary returned by the trace function which computed the traced value. chain_stats (Dict[str, List[array]]): Dictionary of chain integration transition statistics. Values in dictionary are lists of arrays of chain statistic values with each array in the list corresponding to a single chain and the leading - dimension of each array corresponding to the sampling (draw) + dimension of each array corresponding to the iteration (draw) index. The key for each value is a string description of the corresponding integration transition statistic. """ init_states = [self._preprocess_init_state(i) for i in init_states] self.__set_sample_chain_kwargs_defaults(kwargs) final_states, traces, chain_stats = super().sample_chains( - n_sample, init_states, **kwargs) + n_iter, init_states, **kwargs) + chain_stats = chain_stats.get('integration_transition', {}) + return final_states, traces, chain_stats + + def sample_chains_with_adaptive_warm_up( + self, n_warm_up_iter, n_main_iter, init_states, **kwargs): + """Sample Markov chains from given initial states with adaptive warm up. + + One or more Markov chains are sampled, with each chain iteration + consisting of a momentum transition followed by an integration + transition. The chains are split into multiple *stages* with one or more + adaptive warm up stages followed by the main non-adaptive sampling + stage. During the adaptive stage(s) parameters of the integration + transition such as the integrator step size are adaptively tuned based + on the chain state and/or transition statistics. + + Following the approach of [Stan](https://mc-stan.org) the adaptive + stages are split in to two types - 'fast' adaptation stages which adjust + only transition parameters which can be adapted quickly using local + information (such as the integrator step size) and 'slow' adaptation + stages which *addtionally* adjust transition parameters which require + more global information (such as the metric matrix representation for + Euclidean metric systems which requires estimates of the (co)variances + of the target distribution). The adapters to be used in both the fast + and slow adaptation stages will be referred to as the *fast adapters* + and the adapters to use in only the slow adaptation stages the *slow + adapters*. + + If only fast adapters are specified the adaptive warm up iterations will + form a single fast adaptive stage. If both slow and fast adapters are + specified the adaptive warm up iterations will be split into three + stages: + + 1. An initial fast adaptive stage with only fast adapters active. + 2. A slow adaptive stage with both slow and fast adapters active. + 3. A final adaptive stage with only fast adapters active. + + The slow sampling stage (2) is further split in to a sequence of + growing, memoryless windows with the adapter stages reset at the + beginning of each window, and the number of iterations in each window + increasing (by default doubling). The split of the iterations in each of + these stages can be controlled using the keyword arguments + `n_init_fast_stage_iter`, `n_init_slow_window_iter`, + `n_final_fast_stage_iter` and `slow_window_multiplier` (see descriptions + below). + + In both cases after the initial adaptive warm up stage(s) a subsequent + main sampling stage with no further adaptation is performed. Only in + this main sampling stage are traces of the chain state recorded by + storing the outputs of functions of the sampled chain state after each + iteration. + + The default settings use a single (fast) `DualAveragingStepSizeAdapter` + adapter instance which adapts the integrator step-size using a + dual-averaging algorithm in a single adaptive stage. + + The chains (including both adaptive and non-adaptive stages) may be run + in parallel across multiple independent processes or sequentially. In + all cases all chains use independent random draws. + + Args: + n_warm_up_iter (int): Number of adaptive warm up iterations per + chain. Depending on the adapters specified by the + `fast_adapters` and `slow_adapters` arguments the warm up + iterations may be split between one or more adaptive stages. + The keyword arguments `n_init_fast_stage_iter`, + `n_init_slow_window_iter`, `n_final_fast_stage_iter` and + `slow_window_multiplier` can be used to control the split of + the warm up iterations into these different stages - for details + see descriptions of the individual keyword arguments below. + n_main_iter (int): Number of iterations (samples to draw) per chain + during main (non-adaptive) sampling stage. + init_states (Iterable[ChainState] or Iterable[array]): Initial + chain states. Each state can be either an array specifying the + state position component or a `mici.states.ChainState` + instance. If an array is passed or the `mom` attribute of the + state is not set, a momentum component will be independently + sampled from its conditional distribution. One chain will be + run for each state in the iterable sequence. + + Kwargs: + n_process (int or None): Number of parallel processes to run chains + over. If `n_process=1` then chains will be run sequentially + otherwise a `multiprocessing.Pool` object will be used to + dynamically assign the chains across multiple processes. If set + to `None` then the number of processes will be set to the + output of `os.cpu_count()`. Default is `n_process=1`. + trace_funcs (Iterable[Callable[[ChainState], Dict[str, array]]]): + List of functions which compute the variables to be recorded at + each chain iteration during the main non-adaptive sampling + stage, with each trace function being passed the current state + and returning a dictionary of scalar or array values + corresponding to the variable(s) to be stored. The keys in the + returned dictionaries are used to index the trace arrays in the + returned traces dictionary. If a key appears in multiple + dictionaries only the the value corresponding to the last trace + function to return that key will be stored. Default is to use a + single function which recordes the position component of the + state under the key `pos` and the Hamiltonian at the state under + the key `hamiltonian`. + fast_adapters (Iterable[Adapter]): List of `mici.adapters.Adapter` + instances to use to adaptatively set parameters of the + integration transition such as the step size during the adaptive + (both fast and slow) stages of the chains. Note that the adapter + updates are applied in the order the adapters appear in the + iterable and so if multiple adapters change the same + parameter(s) the order will matter. Default is to use a single + instance of `mici.adapters.DualAveragingStepSizeAdapter` with + its default parameters. + slow_adapters (Iterable[Adapter]): List of `mici.adapters.Adapter` + instances to use to adaptatively set parameters of the + integration transition such as the metric of Euclidean + Hamiltonian systems during the slow adaptive stage of the + chains. Note that the adapter updates are applied in the order + the adapters appear in the iterable and so if multiple adapters + change the same parameter(s) the order will matter. Default is + to use no slow adapters. + n_init_slow_window_iter (int): Number of iterations in the initial + (smallest) window in the slow adaptation stage. Defaults to 25. + If the sum of `n_init_slow_window_iter`, + `n_init_fast_stage_iter` and `n_final_fast_stage_iter` is more + than `n_warm_up_iter` then `n_init_slow_window_iter` is set to + approximately 75% of `n_warm_up_iter` (with a single window + being used in the slow adaptation stage in this case). + n_init_fast_stage_iter (int): Number of iterations in the initial + fast adaptation stage. Defaults to 75. If the sum of + `n_init_slow_window_iter`, n_init_fast_stage_iter` and + `n_final_fast_stage_iter` is more than `n_warm_up_iter` then + `n_init_fast_stage_iter` is set to approximately 15% of + `n_warm_up_iter`. + n_final_fast_stage_iter (int): Number of iterations in the final + fast adaptation stage. Defaults to 50. If the sum of + `n_init_slow_window_iter`, `n_init_fast_stage_iter` and + `n_final_fast_stage_iter` is more than `n_warm_up_iter` then + `n_init_fast_stage_iter` is set to approximately 10% of + `n_warm_up_iter`. + slow_window_multiplier (float): Multiplier by which to increase the + number of iterations of each subsequent slow adaptation window + by. Defaults to 2 such that each window doubles in size. + memmap_enabled (bool): Whether to memory-map arrays used to store + chain data to files on disk to avoid excessive system memory + usage for long chains and/or large chain states. The chain data + is written to `.npy` files in the directory specified by + `memmap_path` (or a temporary directory if not provided). These + files persist after the termination of the function so should + be manually deleted when no longer required. Default is for + memory mapping to be disabled. + memmap_path (str): Path to directory to write memory-mapped chain + data to. If not provided (the default), a temporary directory + will be created and the chain data written to files there. + monitor_stats (Iterable[str]): List of string keys of chain + statistics to monitor mean of over samples computed so far + during sampling by printing as postfix to progress bar. Default + is to print only the mean `accept_stat` statistic. + display_progress (bool): Whether to display a progress bar to + track the completed chain sampling iterations. Default value + is `True`, i.e. to display progress bar. + progress_bar_class (mici.progressbars.BaseProgressBar): Class or + factory function for progress bar to use to show chain + progress if enabled (`display_progress=True`). Defaults to + `mici.progressbars.ProgressBar`. + + Returns: + final_states (List[ChainState]): States of chains after final + iteration. May be used to resume sampling a chain by passing as + the initial states to a new `sample_chains` call. + traces (Dict[str, List[array]]): Dictionary of chain trace arrays. + Values in dictionary are list of arrays of variables outputted + by trace functions in `trace_funcs` with each array in the list + corresponding to a single chain and the leading dimension of + each array corresponding to the iteration (draw) index within + the main non-adaptive sampling stage. The key for each value is + the corresponding key in the dictionary returned by the trace + function which computed the traced value. + chain_stats (Dict[str, List[array]]): Dictionary of chain + integration transition statistics. Values in dictionary are + lists of arrays of chain statistic values with each array in the + list corresponding to a single chain and the leading dimension + of each array corresponding to the iteration (draw) index within + the main non-adaptive sampling stage. The key for each value is + a string description of the corresponding integration transition + statistic. + """ + init_states = [self._preprocess_init_state(i) for i in init_states] + if 'fast_adapters' not in kwargs: + kwargs['fast_adapters'] = [DualAveragingStepSizeAdapter()] + self.__set_sample_chain_kwargs_defaults(kwargs) + final_states, traces, chain_stats = ( + super().sample_chains_with_adaptive_warm_up( + n_warm_up_iter, n_main_iter, init_states, **kwargs)) chain_stats = chain_stats.get('integration_transition', {}) return final_states, traces, chain_stats @@ -1222,7 +1859,7 @@

    Package mici.samplers

    """ Args: system (mici.systems.System): Hamiltonian system to be simulated. - rng (RandomState): Numpy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. integrator (mici.integrators.Integrator): Symplectic integrator to use to simulate dynamics in integration transition. n_step (int): Number of integrator steps to simulate in each @@ -1285,7 +1922,7 @@

    Package mici.samplers

    """ Args: system (mici.systems.System): Hamiltonian system to be simulated. - rng (RandomState): Numpy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. integrator (mici.integrators.Integrator): Symplectic integrator to use to simulate dynamics in integration transition. n_step_range (Tuple[int, int]): Tuple `(lower, upper)` with two @@ -1335,7 +1972,7 @@

    Package mici.samplers

    When used with the default settings of `riemannian_no_u_turn_criterion` termination criterion and extra subtree checks enabled, this sampler is equivalent to the default 'NUTS' MCMC algorithm (minus adaptation) used in - Stan as of version v2.23. + [Stan](https://mc-stan.org/) as of version v2.23. References: @@ -1353,7 +1990,7 @@

    Package mici.samplers

    """ Args: system (mici.systems.System): Hamiltonian system to be simulated. - rng (RandomState): Numpy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. integrator (mici.integrators.Integrator): Symplectic integrator to use to simulate dynamics in integration transition. max_tree_depth (int): Maximum depth to expand trajectory binary @@ -1381,8 +2018,8 @@

    Package mici.samplers

    behaviour is seen by which the termination criterion fails to detect that the trajectory has expanded past a half-period i.e. has 'U-turned' resulting in trajectories continuing to expand, - potentially up until the `max_tree_depth` limit is hit. For - more details see the Stan Discourse discussion at kutt.it/yAkIES + potentially up until the `max_tree_depth` limit is hit. For more + details see [this Stan Discourse discussion](kutt.it/yAkIES). If `do_extra_subtree_checks` is set to `True` additional termination criterion checks are performed on overlapping subtrees which help to reduce this resonant behaviour at the @@ -1453,7 +2090,7 @@

    Package mici.samplers

    """ Args: system (mici.systems.System): Hamiltonian system to be simulated. - rng (RandomState): Numpy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. integrator (mici.integrators.Integrator): Symplectic integrator to use to simulate dynamics in integration transition. max_tree_depth (int): Maximum depth to expand trajectory binary @@ -1481,8 +2118,8 @@

    Package mici.samplers

    behaviour is seen by which the termination criterion fails to detect that the trajectory has expanded past a half-period i.e. has 'U-turned' resulting in trajectories continuing to expand, - potentially up until the `max_tree_depth` limit is hit. For - more details see the Stan Discourse discussion at kutt.it/yAkIES + potentially up until the `max_tree_depth` limit is hit. For more + details see [this Stan Discourse discussion](kutt.it/yAkIES). If `do_extra_subtree_checks` is set to `True` additional termination criterion checks are performed on overlapping subtrees which help to reduce this resonant behaviour at the @@ -1528,30 +2165,6 @@

    Package mici.samplers

    -

    Functions

    -
    -
    -def ignore_sigint_manager() -
    -
    -

    Context-managed SyncManager which ignores SIGINT interrupt signals.

    -
    - -Expand source code -Browse git - -
    @contextmanager
    -def ignore_sigint_manager():
    -    """Context-managed SyncManager which ignores SIGINT interrupt signals."""
    -    manager = SyncManager()
    -    try:
    -        manager.start(_ignore_sigint_initialiser)
    -        yield manager
    -    finally:
    -        manager.shutdown()
    -
    -
    -

    Classes

    @@ -1566,8 +2179,8 @@

    Classes

    a sequence of Markov transition operators.

    Args

    -
    rng : RandomState
    -
    Numpy RandomState random number generator.
    +
    rng : Generator or RandomState
    +
    Numpy random number generator.
    transitions : OrderedDict[str, Transition]
    Ordered dictionary of Markov transitions kernels to sequentially sample from on each @@ -1576,7 +2189,7 @@

    Args

    Expand source code -Browse git +Browse git
    class MarkovChainMonteCarloMethod(object):
         """Generic Markov chain Monte Carlo (MCMC) sampler.
    @@ -1588,7 +2201,7 @@ 

    Args

    def __init__(self, rng, transitions): """ Args: - rng (RandomState): Numpy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. transitions (OrderedDict[str, Transition]): Ordered dictionary of Markov transitions kernels to sequentially sample from on each chain iteration. @@ -1607,7 +2220,7 @@

    Args

    elif 'progress_bar_class' not in kwargs: kwargs['progress_bar_class'] = ProgressBar - def sample_chain(self, n_sample, init_state, trace_funcs, **kwargs): + def sample_chain(self, n_iter, init_state, trace_funcs, **kwargs): """Sample a Markov chain from a given initial state. Performs a specified number of chain iterations (each of which may be @@ -1615,7 +2228,7 @@

    Args

    outputs of functions of the sampled chain state after each iteration. Args: - n_sample (int): Number of samples (iterations) to draw per chain. + n_iter (int): Number of iterations (samples to draw) per chain. init_state (mici.states.ChainState or Dict[str, object]): Initial chain state. Either a `mici.states.ChainState` object or a dictionary with entries specifying initial values for all state @@ -1657,6 +2270,17 @@

    Args

    factory function for progress bar to use to show chain progress if enabled (`display_progress=True`). Defaults to `mici.progressbars.ProgressBar`. + adapters (Dict[str, Iterable[Adapter]): Dictionary of iterables of + `mici.adapters.Adapter` instances keyed by strings corresponding + to the key of the transition in the `transitions` dictionary to + apply the adapters to. Each adapter is able to adaptatively set + the parameters of a transition while sampling a chain. Note that + the adapter updates for each transition are applied in the order + the adapters appear in the iterable and so if multiple adapters + change the same parameter(s) the order will matter. Adaptation + based on the chain state history breaks the Markov property and + so any chain samples while adaptation is active should not be + used in estimates of expectations. Returns: final_state (mici.states.ChainState): State of chain after final @@ -1680,14 +2304,18 @@

    Args

    """ self.__set_sample_chain_kwargs_defaults(kwargs) chain_iterator = _construct_chain_iterators( - n_sample, kwargs.pop('progress_bar_class')) - final_state, traces, chain_stats, interrupted = _sample_chain( + n_iter, kwargs.pop('progress_bar_class')) + final_state, traces, chain_stats, adapter_states, _ = _sample_chain( init_state=init_state, chain_iterator=chain_iterator, transitions=self.transitions, rng=self.rng, trace_funcs=trace_funcs, parallel_chains=False, **kwargs) + if len(adapter_states) > 0: + _finalize_adapters( + adapter_states, kwargs['adapters'], self.transitions) + return final_state, traces, chain_stats - def sample_chains(self, n_sample, init_states, trace_funcs, n_process=1, + def sample_chains(self, n_iter, init_states, trace_funcs, n_process=1, **kwargs): """Sample one or more Markov chains from given initial states. @@ -1698,7 +2326,7 @@

    Args

    or sequentially. In all cases all chains use independent random draws. Args: - n_sample (int): Number of samples (iterations) to draw per chain. + n_iter (int): Number of iterations (samples to draw) per chain. init_states (Iterable[ChainState] or Iterable[Dict[str, object]]): Initial chain states. Each entry can be either a `ChainState` object or a dictionary with entries specifying initial values @@ -1747,6 +2375,17 @@

    Args

    factory function for progress bar to use to show chain progress if enabled (`display_progress=True`). Defaults to `mici.progressbars.ProgressBar`. + adapters (Dict[str, Iterable[Adapter]): Dictionary of iterables of + `mici.adapters.Adapter` instances keyed by strings corresponding + to the key of the transition in the `transitions` dictionary to + apply the adapters to. Each adapter is able to adaptatively set + the parameters of a transition while sampling a chain. Note that + the adapter updates for each transition are applied in the order + the adapters appear in the iterable and so if multiple adapters + change the same parameter(s) the order will matter. Adaptation + based on the chain state history breaks the Markov property and + so any chain samples while adaptation is active should not be + used in estimates of expectations. Returns: final_states (List[ChainState]): States of chains after final @@ -1774,19 +2413,239 @@

    Args

    n_chain = len(init_states) rngs = _get_per_chain_rngs(self.rng, n_chain) chain_iterators = _construct_chain_iterators( - n_sample, kwargs.pop('progress_bar_class'), n_chain) + n_iter, kwargs.pop('progress_bar_class'), n_chain) if n_process == 1: # Using single process therefore run chains sequentially - return _sample_chains_sequential( + *states_traces_stats, adapter_states, _ = _sample_chains_sequential( init_states=init_states, rngs=rngs, chain_iterators=chain_iterators, transitions=self.transitions, trace_funcs=trace_funcs, **kwargs) else: # Run chains in parallel using a multiprocess(ing).Pool - return _sample_chains_parallel( + *states_traces_stats, adapter_states, _ = _sample_chains_parallel( init_states=init_states, rngs=rngs, chain_iterators=chain_iterators, transitions=self.transitions, - trace_funcs=trace_funcs, n_process=n_process, **kwargs)
    + trace_funcs=trace_funcs, n_process=n_process, **kwargs) + if len(adapter_states) > 0: + _finalize_adapters( + adapter_states, kwargs['adapters'], self.transitions) + return states_traces_stats + + def sample_chains_with_adaptive_warm_up( + self, n_warm_up_iter, n_main_iter, init_states, trace_funcs, + fast_adapters, slow_adapters=None, n_process=1, + n_init_slow_window_iter=25, n_init_fast_stage_iter=75, + n_final_fast_stage_iter=50, slow_window_multiplier=2, **kwargs): + """Sample Markov chains from given initial states with adaptive warm up. + + One or more Markov chains are sampled, with each chain iteration + consisting of one or more Markov transitions. The chains are split into + multiple *stages* with one or more adaptive warm up stages followed by + the main non-adaptive sampling stage. During the adaptive stage(s) + parameters of the transition(s) are adaptively tuned based on the chain + state and/or transition statistics. + + Following the approach of [Stan](https://mc-stan.org) the adaptive + stages are split in to two types - 'fast' adaptation stages which adjust + only transition parameters which can be adapted quickly using local + information and 'slow' adaptation stages which *addtionally* adjust + transition parameters which require more global information. The + adapters to be used in both the fast and slow adaptation stages will be + referred to as the *fast adapters* and the adapters to use in only the + slow adaptation stages the *slow adapters*. + + If only fast adapters are specified the adaptive warm up iterations will + form a single fast adaptive stage. If both slow and fast adapters are + specified the adaptive warm up iterations will be split into three + stages: + + 1. An initial fast adaptive stage with only fast adapters active. + 2. A slow adaptive stage with both slow and fast adapters active. + 3. A final adaptive stage with only fast adapters active. + + The slow sampling stage (2) is further split in to a sequence of + growing, memoryless windows with the adapter stages reset at the + beginning of each window, and the number of iterations in each window + increasing (by default doubling). The split of the iterations in each of + these stages can be controlled using the keyword arguments + `n_init_fast_stage_iter`, `n_init_slow_window_iter`, + `n_final_fast_stage_iter` and `slow_window_multiplier` (see descriptions + below). + + In both cases after the initial adaptive warm up stage(s) a subsequent + main sampling stage with no further adaptation is performed. Only in + this main sampling stage are traces of the chain state recorded by + storing the outputs of functions of the sampled chain state after each + iteration. + + The chains (including both adaptive and non-adaptive stages) may be run + in parallel across multiple independent processes or sequentially. In + all cases all chains use independent random draws. + + Args: + n_warm_up_iter (int): Number of adaptive warm up iterations per + chain. Depending on the adapters specified by the + `fast_adapters` and `slow_adapters` arguments the warm up + iterations may be split between one or more adaptive stages. + The keyword arguments `n_init_fast_stage_iter`, + `n_init_slow_window_iter`, `n_final_fast_stage_iter` and + `slow_window_multiplier` can be used to control the split of + the warm up iterations into these different stages - for details + see descriptions of the individual keyword arguments below. + n_main_iter (int): Number of iterations (samples to draw) per chain + during main (non-adaptive) sampling stage. + init_states (Iterable[ChainState] or Iterable[Dict[str, object]]): + Initial chain states. Each entry can be either a `ChainState` + object or a dictionary with entries specifying initial values + for all state variables used by chain transition `sample` + methods. + trace_funcs (Iterable[Callable[[ChainState], Dict[str, array]]]): + List of functions which compute the variables to be recorded at + each chain iteration during the main non-adaptive sampling + stage, with each trace function being passed the current state + and returning a dictionary of scalar or array values + corresponding to the variable(s) to be stored. The keys in the + returned dictionaries are used to index the trace arrays in the + returned traces dictionary. If a key appears in multiple + dictionaries only the the value corresponding to the last trace + function to return that key will be stored. + fast_adapters (Dict[str, Iterable[Adapter]): Dictionary of iterables + of `mici.adapters.Adapter` instances keyed by strings + corresponding to the key of the transition in the `transitions` + dictionary to apply the adapters to, to use to adaptatively set + parameters of the transitions during the adaptive (both fast and + slow) stages of the chains. Note that the adapter updates are + applied in the order the adapters appear in the iterables and so + if multiple adapters change the same parameter(s) the order will + matter. + + Kwargs: + slow_adapters (Dict[str, Iterable[Adapter]): Dictionary of iterables + of `mici.adapters.Adapter` instances keyed by strings + corresponding to the key of the transition in the `transitions` + dictionary to apply the adapters to, to use to adaptatively set + parameters of the transitions during the slow adaptive stage of + the chains. Note that the adapter updates are applied in the + order the adapters appear in the iterables and so if multiple + adapters change the same parameter(s) the order will matter. + Default is to use no slow adapters. + n_process (int or None): Number of parallel processes to run chains + over. If `n_process=1` then chains will be run sequentially + otherwise a `multiprocessing.Pool` object will be used to + dynamically assign the chains across multiple processes. If set + to `None` then the number of processes will be set to the + output of `os.cpu_count()`. Default is `n_process=1`. + n_init_slow_window_iter (int): Number of iterations in the initial + (smallest) window in the slow adaptation stage. Defaults to 25. + If the sum of `n_init_slow_window_iter`, + `n_init_fast_stage_iter` and `n_final_fast_stage_iter` is more + than `n_warm_up_iter` then `n_init_slow_window_iter` is set to + approximately 75% of `n_warm_up_iter` (with a single window + being used in the slow adaptation stage in this case). + n_init_fast_stage_iter (int): Number of iterations in the initial + fast adaptation stage. Defaults to 75. If the sum of + `n_init_slow_window_iter`, n_init_fast_stage_iter` and + `n_final_fast_stage_iter` is more than `n_warm_up_iter` then + `n_init_fast_stage_iter` is set to approximately 15% of + `n_warm_up_iter`. + n_final_fast_stage_iter (int): Number of iterations in the final + fast adaptation stage. Defaults to 50. If the sum of + `n_init_slow_window_iter`, `n_init_fast_stage_iter` and + `n_final_fast_stage_iter` is more than `n_warm_up_iter` then + `n_init_fast_stage_iter` is set to approximately 10% of + `n_warm_up_iter`. + slow_window_multiplier (float): Multiplier by which to increase the + number of iterations of each subsequent slow adaptation window + by. Defaults to 2 such that each window doubles in size. + memmap_enabled (bool): Whether to memory-map arrays used to store + chain data to files on disk to avoid excessive system memory + usage for long chains and/or large chain states. The chain data + is written to `.npy` files in the directory specified by + `memmap_path` (or a temporary directory if not provided). These + files persist after the termination of the function so should + be manually deleted when no longer required. Default is to + for memory mapping to be disabled. + memmap_path (str): Path to directory to write memory-mapped chain + data to. If not provided, a temporary directory will be created + and the chain data written to files there. + monitor_stats (Iterable[Tuple[str, str]]): List of tuples of string + key pairs, with first entry the key of a Markov transition in + the `transitions` dict passed to the the `__init__` method and + the second entry the key of a chain statistic that will be + returned in the `chain_stats` dictionary. The mean over samples + computed so far of the chain statistics associated with any + valid key-pairs will be monitored during sampling by printing + as postfix to progress bar. + display_progress (bool): Whether to display a progress bar to + track the completed chain sampling iterations. Default value + is `True`, i.e. to display progress bar. + progress_bar_class (mici.progressbars.BaseProgressBar): Class or + factory function for progress bar to use to show chain + progress if enabled (`display_progress=True`). Defaults to + `mici.progressbars.ProgressBar`. + + Returns: + final_states (List[ChainState]): States of chains after final + iteration. May be used to resume sampling a chain by passing as + the initial states to a new `sample_chains` call. + traces (Dict[str, List[array]]): Dictionary of chain trace arrays. + Values in dictionary are list of arrays of variables outputted + by trace functions in `trace_funcs` with each array in the list + corresponding to a single chain and the leading dimension of + each array corresponding to the iteration (draw) index in the + main non-adaptive sampling stage. The key for each value is the + corresponding key in the dictionary returned by the trace + function which computed the traced value. + chain_stats (Dict[str, Dict[str, List[array]]]): Dictionary of + chain transition statistic dictionaries. Values in outer + dictionary are dictionaries of statistics for each chain + transition, keyed by the string key for the transition. The + values in each inner transition dictionary are lists of arrays + of chain statistic values with each array in the list + corresponding to a single chain and the leading dimension of + each array corresponding to the iteration (draw) index in the + main non-adaptive sampling stage. The key for each value is a + string description of the corresponding integration transition + statistic. + """ + self.__set_sample_chain_kwargs_defaults(kwargs) + if 'adapters' in kwargs: + raise ValueError( + 'Transition adapters should be specified via `fast_adapters` ' + 'and `slow_adapters` arguments rather than `adapters`.') + n_chain = len(init_states) + rngs = _get_per_chain_rngs(self.rng, n_chain) + progress_bar_class = kwargs.pop('progress_bar_class') + common_sample_chains_kwargs = { + 'rngs': rngs, 'transitions': self.transitions, **kwargs} + if n_process > 1: + sample_chains_func = _sample_chains_parallel + common_sample_chains_kwargs['n_process'] = n_process + else: + sample_chains_func = _sample_chains_sequential + sampling_stages = _set_up_sampling_stages( + n_warm_up_iter, n_main_iter, fast_adapters, slow_adapters, + trace_funcs, n_init_slow_window_iter, n_init_fast_stage_iter, + n_final_fast_stage_iter, slow_window_multiplier) + with LabelledSequenceProgressBar( + sampling_stages, 'Sampling stage', position=(0, n_chain + 1) + ) as sampling_stages_pb: + chain_iterators = _construct_chain_iterators( + n_warm_up_iter, progress_bar_class, n_chain, 1) + for (n_iter, adapters, trace_funcs), _ in sampling_stages_pb: + for chain_it in chain_iterators: + chain_it.sequence = range(n_iter) + chain_states, traces, stats, adapter_states, exception = ( + sample_chains_func( + init_states=init_states, trace_funcs=trace_funcs, + adapters=adapters, chain_iterators=chain_iterators, + **common_sample_chains_kwargs)) + if len(adapter_states) > 0: + _finalize_adapters( + adapter_states, adapters, self.transitions) + if isinstance(exception, KeyboardInterrupt): + return chain_states, traces, stats + return chain_states, traces, stats

    Subclasses

      @@ -1795,7 +2654,7 @@

      Subclasses

      Methods

      -def sample_chain(self, n_sample, init_state, trace_funcs, **kwargs) +def sample_chain(self, n_iter, init_state, trace_funcs, **kwargs)

      Sample a Markov chain from a given initial state.

      @@ -1804,8 +2663,8 @@

      Methods

      outputs of functions of the sampled chain state after each iteration.

      Args

      -
      n_sample : int
      -
      Number of samples (iterations) to draw per chain.
      +
      n_iter : int
      +
      Number of iterations (samples to draw) per chain.
      init_state : ChainState or Dict[str, object]
      Initial chain state. Either a ChainState object or a @@ -1856,6 +2715,18 @@

      Kwargs

      factory function for progress bar to use to show chain progress if enabled (display_progress=True). Defaults to ProgressBar.
      +
      adapters : Dict[str, Iterable[Adapter]
      +
      Dictionary of iterables of +Adapter instances keyed by strings corresponding +to the key of the transition in the transitions dictionary to +apply the adapters to. Each adapter is able to adaptatively set +the parameters of a transition while sampling a chain. Note that +the adapter updates for each transition are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Adaptation +based on the chain state history breaks the Markov property and +so any chain samples while adaptation is active should not be +used in estimates of expectations.

      Returns

      @@ -1884,9 +2755,9 @@

      Returns

      Expand source code -Browse git +Browse git -
      def sample_chain(self, n_sample, init_state, trace_funcs, **kwargs):
      +
      def sample_chain(self, n_iter, init_state, trace_funcs, **kwargs):
           """Sample a Markov chain from a given initial state.
       
           Performs a specified number of chain iterations (each of which may be
      @@ -1894,7 +2765,7 @@ 

      Returns

      outputs of functions of the sampled chain state after each iteration. Args: - n_sample (int): Number of samples (iterations) to draw per chain. + n_iter (int): Number of iterations (samples to draw) per chain. init_state (mici.states.ChainState or Dict[str, object]): Initial chain state. Either a `mici.states.ChainState` object or a dictionary with entries specifying initial values for all state @@ -1936,6 +2807,17 @@

      Returns

      factory function for progress bar to use to show chain progress if enabled (`display_progress=True`). Defaults to `mici.progressbars.ProgressBar`. + adapters (Dict[str, Iterable[Adapter]): Dictionary of iterables of + `mici.adapters.Adapter` instances keyed by strings corresponding + to the key of the transition in the `transitions` dictionary to + apply the adapters to. Each adapter is able to adaptatively set + the parameters of a transition while sampling a chain. Note that + the adapter updates for each transition are applied in the order + the adapters appear in the iterable and so if multiple adapters + change the same parameter(s) the order will matter. Adaptation + based on the chain state history breaks the Markov property and + so any chain samples while adaptation is active should not be + used in estimates of expectations. Returns: final_state (mici.states.ChainState): State of chain after final @@ -1959,16 +2841,20 @@

      Returns

      """ self.__set_sample_chain_kwargs_defaults(kwargs) chain_iterator = _construct_chain_iterators( - n_sample, kwargs.pop('progress_bar_class')) - final_state, traces, chain_stats, interrupted = _sample_chain( + n_iter, kwargs.pop('progress_bar_class')) + final_state, traces, chain_stats, adapter_states, _ = _sample_chain( init_state=init_state, chain_iterator=chain_iterator, transitions=self.transitions, rng=self.rng, trace_funcs=trace_funcs, parallel_chains=False, **kwargs) + if len(adapter_states) > 0: + _finalize_adapters( + adapter_states, kwargs['adapters'], self.transitions) + return final_state, traces, chain_stats
      -def sample_chains(self, n_sample, init_states, trace_funcs, n_process=1, **kwargs) +def sample_chains(self, n_iter, init_states, trace_funcs, n_process=1, **kwargs)

      Sample one or more Markov chains from given initial states.

      @@ -1979,8 +2865,8 @@

      Returns

      or sequentially. In all cases all chains use independent random draws.

      Args

      -
      n_sample : int
      -
      Number of samples (iterations) to draw per chain.
      +
      n_iter : int
      +
      Number of iterations (samples to draw) per chain.
      init_states : Iterable[ChainState] or Iterable[Dict[str, object]]

      Initial chain states. Each entry can be either a ChainState @@ -2041,6 +2927,18 @@

      Kwargs

      factory function for progress bar to use to show chain progress if enabled (display_progress=True). Defaults to ProgressBar.
      +
      adapters : Dict[str, Iterable[Adapter]
      +
      Dictionary of iterables of +Adapter instances keyed by strings corresponding +to the key of the transition in the transitions dictionary to +apply the adapters to. Each adapter is able to adaptatively set +the parameters of a transition while sampling a chain. Note that +the adapter updates for each transition are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Adaptation +based on the chain state history breaks the Markov property and +so any chain samples while adaptation is active should not be +used in estimates of expectations.

      Returns

      @@ -2071,9 +2969,9 @@

      Returns

      Expand source code -Browse git +Browse git -
      def sample_chains(self, n_sample, init_states, trace_funcs, n_process=1,
      +
      def sample_chains(self, n_iter, init_states, trace_funcs, n_process=1,
                         **kwargs):
           """Sample one or more Markov chains from given initial states.
       
      @@ -2084,7 +2982,7 @@ 

      Returns

      or sequentially. In all cases all chains use independent random draws. Args: - n_sample (int): Number of samples (iterations) to draw per chain. + n_iter (int): Number of iterations (samples to draw) per chain. init_states (Iterable[ChainState] or Iterable[Dict[str, object]]): Initial chain states. Each entry can be either a `ChainState` object or a dictionary with entries specifying initial values @@ -2133,6 +3031,17 @@

      Returns

      factory function for progress bar to use to show chain progress if enabled (`display_progress=True`). Defaults to `mici.progressbars.ProgressBar`. + adapters (Dict[str, Iterable[Adapter]): Dictionary of iterables of + `mici.adapters.Adapter` instances keyed by strings corresponding + to the key of the transition in the `transitions` dictionary to + apply the adapters to. Each adapter is able to adaptatively set + the parameters of a transition while sampling a chain. Note that + the adapter updates for each transition are applied in the order + the adapters appear in the iterable and so if multiple adapters + change the same parameter(s) the order will matter. Adaptation + based on the chain state history breaks the Markov property and + so any chain samples while adaptation is active should not be + used in estimates of expectations. Returns: final_states (List[ChainState]): States of chains after final @@ -2160,23 +3069,441 @@

      Returns

      n_chain = len(init_states) rngs = _get_per_chain_rngs(self.rng, n_chain) chain_iterators = _construct_chain_iterators( - n_sample, kwargs.pop('progress_bar_class'), n_chain) + n_iter, kwargs.pop('progress_bar_class'), n_chain) if n_process == 1: # Using single process therefore run chains sequentially - return _sample_chains_sequential( + *states_traces_stats, adapter_states, _ = _sample_chains_sequential( init_states=init_states, rngs=rngs, chain_iterators=chain_iterators, transitions=self.transitions, trace_funcs=trace_funcs, **kwargs) else: # Run chains in parallel using a multiprocess(ing).Pool - return _sample_chains_parallel( + *states_traces_stats, adapter_states, _ = _sample_chains_parallel( init_states=init_states, rngs=rngs, chain_iterators=chain_iterators, transitions=self.transitions, - trace_funcs=trace_funcs, n_process=n_process, **kwargs)
      + trace_funcs=trace_funcs, n_process=n_process, **kwargs) + if len(adapter_states) > 0: + _finalize_adapters( + adapter_states, kwargs['adapters'], self.transitions) + return states_traces_stats
      -
      - +
      +def sample_chains_with_adaptive_warm_up(self, n_warm_up_iter, n_main_iter, init_states, trace_funcs, fast_adapters, slow_adapters=None, n_process=1, n_init_slow_window_iter=25, n_init_fast_stage_iter=75, n_final_fast_stage_iter=50, slow_window_multiplier=2, **kwargs) +
      +
      +

      Sample Markov chains from given initial states with adaptive warm up.

      +

      One or more Markov chains are sampled, with each chain iteration +consisting of one or more Markov transitions. The chains are split into +multiple stages with one or more adaptive warm up stages followed by +the main non-adaptive sampling stage. During the adaptive stage(s) +parameters of the transition(s) are adaptively tuned based on the chain +state and/or transition statistics.

      +

      Following the approach of Stan the adaptive +stages are split in to two types - 'fast' adaptation stages which adjust +only transition parameters which can be adapted quickly using local +information and 'slow' adaptation stages which addtionally adjust +transition parameters which require more global information. The +adapters to be used in both the fast and slow adaptation stages will be +referred to as the fast adapters and the adapters to use in only the +slow adaptation stages the slow adapters.

      +

      If only fast adapters are specified the adaptive warm up iterations will +form a single fast adaptive stage. If both slow and fast adapters are +specified the adaptive warm up iterations will be split into three +stages:

      +
        +
      1. An initial fast adaptive stage with only fast adapters active.
      2. +
      3. A slow adaptive stage with both slow and fast adapters active.
      4. +
      5. A final adaptive stage with only fast adapters active.
      6. +
      +

      The slow sampling stage (2) is further split in to a sequence of +growing, memoryless windows with the adapter stages reset at the +beginning of each window, and the number of iterations in each window +increasing (by default doubling). The split of the iterations in each of +these stages can be controlled using the keyword arguments +n_init_fast_stage_iter, n_init_slow_window_iter, +n_final_fast_stage_iter and slow_window_multiplier (see descriptions +below).

      +

      In both cases after the initial adaptive warm up stage(s) a subsequent +main sampling stage with no further adaptation is performed. Only in +this main sampling stage are traces of the chain state recorded by +storing the outputs of functions of the sampled chain state after each +iteration.

      +

      The chains (including both adaptive and non-adaptive stages) may be run +in parallel across multiple independent processes or sequentially. In +all cases all chains use independent random draws.

      +

      Args

      +
      +
      n_warm_up_iter : int
      +
      Number of adaptive warm up iterations per +chain. Depending on the adapters specified by the +fast_adapters and slow_adapters arguments the warm up +iterations may be split between one or more adaptive stages. +The keyword arguments n_init_fast_stage_iter, +n_init_slow_window_iter, n_final_fast_stage_iter and +slow_window_multiplier can be used to control the split of +the warm up iterations into these different stages - for details +see descriptions of the individual keyword arguments below.
      +
      n_main_iter : int
      +
      Number of iterations (samples to draw) per chain +during main (non-adaptive) sampling stage.
      +
      init_states : Iterable[ChainState] or Iterable[Dict[str, object]]
      +
      +

      Initial chain states. Each entry can be either a ChainState +object or a dictionary with entries specifying initial values +for all state variables used by chain transition sample +methods.

      +
      +
      trace_funcs : Iterable[Callable[[ChainState], Dict[str, array]]]
      +
      +

      List of functions which compute the variables to be recorded at +each chain iteration during the main non-adaptive sampling +stage, with each trace function being passed the current state +and returning a dictionary of scalar or array values +corresponding to the variable(s) to be stored. The keys in the +returned dictionaries are used to index the trace arrays in the +returned traces dictionary. If a key appears in multiple +dictionaries only the the value corresponding to the last trace +function to return that key will be stored.

      +
      +
      fast_adapters : Dict[str, Iterable[Adapter]
      +
      Dictionary of iterables +of Adapter instances keyed by strings +corresponding to the key of the transition in the transitions +dictionary to apply the adapters to, to use to adaptatively set +parameters of the transitions during the adaptive (both fast and +slow) stages of the chains. Note that the adapter updates are +applied in the order the adapters appear in the iterables and so +if multiple adapters change the same parameter(s) the order will +matter.
      +
      +

      Kwargs

      +
      +
      slow_adapters : Dict[str, Iterable[Adapter]
      +
      Dictionary of iterables +of Adapter instances keyed by strings +corresponding to the key of the transition in the transitions +dictionary to apply the adapters to, to use to adaptatively set +parameters of the transitions during the slow adaptive stage of +the chains. Note that the adapter updates are applied in the +order the adapters appear in the iterables and so if multiple +adapters change the same parameter(s) the order will matter. +Default is to use no slow adapters.
      +
      n_process : int or None
      +
      Number of parallel processes to run chains +over. If n_process=1 then chains will be run sequentially +otherwise a multiprocessing.Pool object will be used to +dynamically assign the chains across multiple processes. If set +to None then the number of processes will be set to the +output of os.cpu_count(). Default is n_process=1.
      +
      n_init_slow_window_iter : int
      +
      Number of iterations in the initial +(smallest) window in the slow adaptation stage. Defaults to 25. +If the sum of n_init_slow_window_iter, +n_init_fast_stage_iter and n_final_fast_stage_iter is more +than n_warm_up_iter then n_init_slow_window_iter is set to +approximately 75% of n_warm_up_iter (with a single window +being used in the slow adaptation stage in this case).
      +
      n_init_fast_stage_iter : int
      +
      Number of iterations in the initial +fast adaptation stage. Defaults to 75. If the sum of +n_init_slow_window_iter, n_init_fast_stage_iterandn_final_fast_stage_iteris more thann_warm_up_iterthenn_init_fast_stage_iteris set to approximately 15% ofn_warm_up_iter`.
      +
      n_final_fast_stage_iter : int
      +
      Number of iterations in the final +fast adaptation stage. Defaults to 50. If the sum of +n_init_slow_window_iter, n_init_fast_stage_iter and +n_final_fast_stage_iter is more than n_warm_up_iter then +n_init_fast_stage_iter is set to approximately 10% of +n_warm_up_iter.
      +
      slow_window_multiplier : float
      +
      Multiplier by which to increase the +number of iterations of each subsequent slow adaptation window +by. Defaults to 2 such that each window doubles in size.
      +
      memmap_enabled : bool
      +
      Whether to memory-map arrays used to store +chain data to files on disk to avoid excessive system memory +usage for long chains and/or large chain states. The chain data +is written to .npy files in the directory specified by +memmap_path (or a temporary directory if not provided). These +files persist after the termination of the function so should +be manually deleted when no longer required. Default is to +for memory mapping to be disabled.
      +
      memmap_path : str
      +
      Path to directory to write memory-mapped chain +data to. If not provided, a temporary directory will be created +and the chain data written to files there.
      +
      monitor_stats : Iterable[Tuple[str, str]]
      +
      List of tuples of string +key pairs, with first entry the key of a Markov transition in +the transitions dict passed to the the __init__ method and +the second entry the key of a chain statistic that will be +returned in the chain_stats dictionary. The mean over samples +computed so far of the chain statistics associated with any +valid key-pairs will be monitored during sampling +by printing +as postfix to progress bar.
      +
      display_progress : bool
      +
      Whether to display a progress bar to +track the completed chain sampling iterations. Default value +is True, i.e. to display progress bar.
      +
      progress_bar_class : BaseProgressBar
      +
      Class or +factory function for progress bar to use to show chain +progress if enabled (display_progress=True). Defaults to +ProgressBar.
      +
      +

      Returns

      +
      +
      final_states : List[ChainState]
      +
      States of chains after final +iteration. May be used to resume sampling a chain by passing as +the initial states to a new sample_chains call.
      +
      traces : Dict[str, List[array]]
      +
      Dictionary of chain trace arrays. +Values in dictionary are list of arrays of variables outputted +by trace functions in trace_funcs with each array in the list +corresponding to a single chain and the leading dimension of +each array corresponding to the iteration (draw) index in the +main non-adaptive sampling stage. The key for each value is the +corresponding key in the dictionary returned by the trace +function which computed the traced value.
      +
      chain_stats : Dict[str, Dict[str, List[array]]]
      +
      Dictionary of +chain transition statistic dictionaries. Values in outer +dictionary are dictionaries of statistics for each chain +transition, keyed by the string key for the transition. The +values in each inner transition dictionary are lists of arrays +of chain statistic values with each array in the list +corresponding to a single chain and the leading dimension of +each array corresponding to the iteration (draw) index in the +main non-adaptive sampling stage. The key for each value is a +string description of the corresponding integration transition +statistic.
      +
      +
      + +Expand source code +Browse git + +
      def sample_chains_with_adaptive_warm_up(
      +        self, n_warm_up_iter, n_main_iter, init_states, trace_funcs,
      +        fast_adapters, slow_adapters=None, n_process=1,
      +        n_init_slow_window_iter=25, n_init_fast_stage_iter=75,
      +        n_final_fast_stage_iter=50, slow_window_multiplier=2, **kwargs):
      +    """Sample Markov chains from given initial states with adaptive warm up.
      +
      +    One or more Markov chains are sampled, with each chain iteration
      +    consisting of one or more Markov transitions. The chains are split into
      +    multiple *stages* with one or more adaptive warm up stages followed by
      +    the main non-adaptive sampling stage. During the adaptive stage(s)
      +    parameters of the transition(s) are adaptively tuned based on the chain
      +    state and/or transition statistics.
      +
      +    Following the approach of [Stan](https://mc-stan.org) the adaptive
      +    stages are split in to two types - 'fast' adaptation stages which adjust
      +    only transition parameters which can be adapted quickly using local
      +    information and 'slow' adaptation stages which *addtionally* adjust
      +    transition parameters which require more global information. The
      +    adapters to be used in both the fast and slow adaptation stages will be
      +    referred to as the *fast adapters* and the adapters to use in only the
      +    slow adaptation stages the *slow adapters*.
      +
      +    If only fast adapters are specified the adaptive warm up iterations will
      +    form a single fast adaptive stage. If both slow and fast adapters are
      +    specified the adaptive warm up iterations will be split into three
      +    stages:
      +
      +      1. An initial fast adaptive stage with only fast adapters active.
      +      2. A slow adaptive stage with both slow and fast adapters active.
      +      3. A final adaptive stage with only fast adapters active.
      +
      +    The slow sampling stage (2) is further split in to a sequence of
      +    growing, memoryless windows with the adapter stages reset at the
      +    beginning of each window, and the number of iterations in each window
      +    increasing (by default doubling). The split of the iterations in each of
      +    these stages can be controlled using the keyword arguments
      +    `n_init_fast_stage_iter`, `n_init_slow_window_iter`,
      +    `n_final_fast_stage_iter` and `slow_window_multiplier` (see descriptions
      +    below).
      +
      +    In both cases after the initial adaptive warm up stage(s) a subsequent
      +    main sampling stage with no further adaptation is performed. Only in
      +    this main sampling stage are traces of the chain state recorded by
      +    storing the outputs of functions of the sampled chain state after each
      +    iteration.
      +
      +    The chains (including both adaptive and non-adaptive stages) may be run
      +    in parallel across multiple independent processes or sequentially. In
      +    all cases all chains use independent random draws.
      +
      +    Args:
      +        n_warm_up_iter (int): Number of adaptive warm up iterations per
      +            chain. Depending on the adapters specified by the
      +            `fast_adapters` and `slow_adapters` arguments the warm up
      +            iterations may be split between one or more adaptive stages.
      +            The keyword arguments `n_init_fast_stage_iter`,
      +            `n_init_slow_window_iter`, `n_final_fast_stage_iter` and
      +            `slow_window_multiplier` can be used to control the split of
      +            the warm up iterations into these different stages - for details
      +            see descriptions of the individual keyword arguments below.
      +        n_main_iter (int): Number of iterations (samples to draw) per chain
      +            during main (non-adaptive) sampling stage.
      +        init_states (Iterable[ChainState] or Iterable[Dict[str, object]]):
      +            Initial chain states. Each entry can be either a `ChainState`
      +            object or a dictionary with entries specifying initial values
      +            for all state variables used by chain transition `sample`
      +            methods.
      +        trace_funcs (Iterable[Callable[[ChainState], Dict[str, array]]]):
      +            List of functions which compute the variables to be recorded at
      +            each chain iteration during the main non-adaptive sampling
      +            stage, with each trace function being passed the current state
      +            and returning a dictionary of scalar or array values
      +            corresponding to the variable(s) to be stored. The keys in the
      +            returned dictionaries are used to index the trace arrays in the
      +            returned traces dictionary. If a key appears in multiple
      +            dictionaries only the the value corresponding to the last trace
      +            function to return that key will be stored.
      +        fast_adapters (Dict[str, Iterable[Adapter]): Dictionary of iterables
      +            of `mici.adapters.Adapter` instances keyed by strings
      +            corresponding to the key of the transition in the `transitions`
      +            dictionary to apply the adapters to, to use to adaptatively set
      +            parameters of the transitions during the adaptive (both fast and
      +            slow) stages of the chains. Note that the adapter updates are
      +            applied in the order the adapters appear in the iterables and so
      +            if multiple adapters change the same parameter(s) the order will
      +            matter.
      +
      +    Kwargs:
      +        slow_adapters (Dict[str, Iterable[Adapter]): Dictionary of iterables
      +            of `mici.adapters.Adapter` instances keyed by strings
      +            corresponding to the key of the transition in the `transitions`
      +            dictionary to apply the adapters to, to use to adaptatively set
      +            parameters of the transitions during the slow adaptive stage of
      +            the chains. Note that the adapter updates are applied in the
      +            order the adapters appear in the iterables and so if multiple
      +            adapters change the same parameter(s) the order will matter.
      +            Default is to use no slow adapters.
      +        n_process (int or None): Number of parallel processes to run chains
      +            over. If `n_process=1` then chains will be run sequentially
      +            otherwise a `multiprocessing.Pool` object will be used to
      +            dynamically assign the chains across multiple processes. If set
      +            to `None` then the number of processes will be set to the
      +            output of `os.cpu_count()`. Default is `n_process=1`.
      +        n_init_slow_window_iter (int): Number of iterations in the initial
      +            (smallest) window in the slow adaptation stage. Defaults to 25.
      +            If the sum of `n_init_slow_window_iter`,
      +            `n_init_fast_stage_iter` and `n_final_fast_stage_iter` is more
      +            than `n_warm_up_iter` then `n_init_slow_window_iter` is set to
      +            approximately 75% of `n_warm_up_iter` (with a single window
      +            being used in the slow adaptation stage in this case).
      +        n_init_fast_stage_iter (int): Number of iterations in the initial
      +            fast adaptation stage. Defaults to 75. If the sum of
      +            `n_init_slow_window_iter`, n_init_fast_stage_iter` and
      +            `n_final_fast_stage_iter` is more than `n_warm_up_iter` then
      +            `n_init_fast_stage_iter` is set to approximately 15% of
      +            `n_warm_up_iter`.
      +        n_final_fast_stage_iter (int): Number of iterations in the final
      +            fast adaptation stage. Defaults to 50. If the sum of
      +            `n_init_slow_window_iter`, `n_init_fast_stage_iter` and
      +            `n_final_fast_stage_iter` is more than `n_warm_up_iter` then
      +            `n_init_fast_stage_iter` is set to approximately 10% of
      +            `n_warm_up_iter`.
      +        slow_window_multiplier (float): Multiplier by which to increase the
      +            number of iterations of each subsequent slow adaptation window
      +            by. Defaults to 2 such that each window doubles in size.
      +        memmap_enabled (bool): Whether to memory-map arrays used to store
      +            chain data to files on disk to avoid excessive system memory
      +            usage for long chains and/or large chain states. The chain data
      +            is written to `.npy` files in the directory specified by
      +            `memmap_path` (or a temporary directory if not provided). These
      +            files persist after the termination of the function so should
      +            be manually deleted when no longer required. Default is to
      +            for memory mapping to be disabled.
      +        memmap_path (str): Path to directory to write memory-mapped chain
      +            data to. If not provided, a temporary directory will be created
      +            and the chain data written to files there.
      +        monitor_stats (Iterable[Tuple[str, str]]): List of tuples of string
      +            key pairs, with first entry the key of a Markov transition in
      +            the `transitions` dict passed to the the `__init__` method and
      +            the second entry the key of a chain statistic that will be
      +            returned in the `chain_stats` dictionary. The mean over samples
      +            computed so far of the chain statistics associated with any
      +            valid key-pairs will be monitored during sampling  by printing
      +            as postfix to progress bar.
      +        display_progress (bool): Whether to display a progress bar to
      +            track the completed chain sampling iterations. Default value
      +            is `True`, i.e. to display progress bar.
      +        progress_bar_class (mici.progressbars.BaseProgressBar): Class or
      +            factory function for progress bar to use to show chain
      +            progress if enabled (`display_progress=True`). Defaults to
      +            `mici.progressbars.ProgressBar`.
      +
      +    Returns:
      +        final_states (List[ChainState]): States of chains after final
      +            iteration. May be used to resume sampling a chain by passing as
      +            the initial states to a new `sample_chains` call.
      +        traces (Dict[str, List[array]]): Dictionary of chain trace arrays.
      +            Values in dictionary are list of arrays of variables outputted
      +            by trace functions in `trace_funcs` with each array in the list
      +            corresponding to a single chain and the leading dimension of
      +            each array corresponding to the iteration (draw) index in the
      +            main non-adaptive sampling stage. The key for each value is the
      +            corresponding key in the dictionary returned by the trace
      +            function which computed the traced value.
      +        chain_stats (Dict[str, Dict[str, List[array]]]): Dictionary of
      +            chain transition statistic dictionaries. Values in outer
      +            dictionary are dictionaries of statistics for each chain
      +            transition, keyed by the string key for the transition. The
      +            values in each inner transition dictionary are lists of arrays
      +            of chain statistic values with each array in the list
      +            corresponding to a single chain and the leading dimension of
      +            each array corresponding to the iteration (draw) index in the
      +            main non-adaptive sampling stage. The key for each value is a
      +            string description of the corresponding integration transition
      +            statistic.
      +    """
      +    self.__set_sample_chain_kwargs_defaults(kwargs)
      +    if 'adapters' in kwargs:
      +        raise ValueError(
      +            'Transition adapters should be specified via `fast_adapters` '
      +            'and `slow_adapters` arguments rather than `adapters`.')
      +    n_chain = len(init_states)
      +    rngs = _get_per_chain_rngs(self.rng, n_chain)
      +    progress_bar_class = kwargs.pop('progress_bar_class')
      +    common_sample_chains_kwargs = {
      +        'rngs': rngs, 'transitions': self.transitions, **kwargs}
      +    if n_process > 1:
      +        sample_chains_func = _sample_chains_parallel
      +        common_sample_chains_kwargs['n_process'] = n_process
      +    else:
      +        sample_chains_func = _sample_chains_sequential
      +    sampling_stages = _set_up_sampling_stages(
      +        n_warm_up_iter, n_main_iter, fast_adapters, slow_adapters,
      +        trace_funcs, n_init_slow_window_iter, n_init_fast_stage_iter,
      +        n_final_fast_stage_iter, slow_window_multiplier)
      +    with LabelledSequenceProgressBar(
      +                sampling_stages, 'Sampling stage', position=(0, n_chain + 1)
      +            ) as sampling_stages_pb:
      +        chain_iterators = _construct_chain_iterators(
      +            n_warm_up_iter, progress_bar_class, n_chain, 1)
      +        for (n_iter, adapters, trace_funcs), _ in sampling_stages_pb:
      +            for chain_it in chain_iterators:
      +                chain_it.sequence = range(n_iter)
      +            chain_states, traces, stats, adapter_states, exception = (
      +                sample_chains_func(
      +                    init_states=init_states, trace_funcs=trace_funcs,
      +                    adapters=adapters, chain_iterators=chain_iterators,
      +                    **common_sample_chains_kwargs))
      +            if len(adapter_states) > 0:
      +                _finalize_adapters(
      +                    adapter_states, adapters, self.transitions)
      +            if isinstance(exception, KeyboardInterrupt):
      +                return chain_states, traces, stats
      +    return chain_states, traces, stats
      +
      +
      + +
      class HamiltonianMCMC (system, rng, integration_transition, momentum_transition=None) @@ -2212,8 +3539,8 @@

      Args

      system : System
      Hamiltonian system to be simulated.
      -
      rng : RandomState
      -
      Numpy RandomState random number generator.
      +
      rng : Generator or RandomState
      +
      Numpy random number generator.
      integration_transition : IntegrationTransition

      Markov transition kernel which leaves canonical distribution @@ -2235,7 +3562,7 @@

      Args

      Expand source code -Browse git +Browse git
      class HamiltonianMCMC(MarkovChainMonteCarloMethod):
           """Wrapper class for Hamiltonian Markov chain Monte Carlo (H-MCMC) methods.
      @@ -2273,7 +3600,7 @@ 

      Args

      """ Args: system (mici.systems.System): Hamiltonian system to be simulated. - rng (RandomState): Numpy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. integration_transition (mici.transitions.IntegrationTransition): Markov transition kernel which leaves canonical distribution invariant and jointly updates the position and momentum @@ -2310,9 +3637,11 @@

      Args

      return init_state def __set_sample_chain_kwargs_defaults(self, kwargs): - # default to tracing only position component of state + # default to tracing position component of state and Hamiltonian if 'trace_funcs' not in kwargs: - kwargs['trace_funcs'] = [_pos_trace_func] + def default_trace_func(state): + return {'pos': state.pos, 'hamiltonian': self.system.h(state)} + kwargs['trace_funcs'] = [default_trace_func] # if `monitor_stats` specified, expand all statistics keys to key pairs # with transition key set to `integration_transition` if 'monitor_stats' in kwargs: @@ -2321,9 +3650,14 @@

      Args

      for stats_key in kwargs['monitor_stats']] else: kwargs['monitor_stats'] = [ - ('integration_transition', 'accept_prob')] - - def sample_chain(self, n_sample, init_state, **kwargs): + ('integration_transition', 'accept_stat')] + # if adapters kwarg specified, wrap adapter list in dictionary with + # adapters applied to integration transition + for key in ['adapters', 'fast_adapters', 'slow_adapters']: + if key in kwargs and kwargs[key] is not None: + kwargs[key] = {'integration_transition': kwargs[key]} + + def sample_chain(self, n_iter, init_state, **kwargs): """Sample a Markov chain from a given initial state. Performs a specified number of chain iterations (each of which may be @@ -2331,7 +3665,7 @@

      Args

      outputs of functions of the sampled chain state after each iteration. Args: - n_sample (int): Number of samples (iterations) to draw per chain. + n_iter (int): Number of iterations (samples to draw) per chain. init_state (mici.states.ChainState or array): Initial chain state. The state can be either an array specifying the state position component or a `mici.states.ChainState` instance. If an array @@ -2348,22 +3682,25 @@

      Args

      in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace - function to return that key will be stored. + function to return that key will be stored. Default is to use a + single function which recordes the position component of the + state under the key `pos` and the Hamiltonian at the state + under the key `hamiltonian`. memmap_enabled (bool): Whether to memory-map arrays used to store chain data to files on disk to avoid excessive system memory usage for long chains and/or large chain states. The chain data is written to `.npy` files in the directory specified by `memmap_path` (or a temporary directory if not provided). These files persist after the termination of the function so should - be manually deleted when no longer required. Default is to - for memory mapping to be disabled. + be manually deleted when no longer required. Default is for + memory mapping to be disabled. memmap_path (str): Path to directory to write memory-mapped chain data to. If not provided, a temporary directory will be created and the chain data written to files there. monitor_stats (Iterable[str]): List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default - is to print only the mean `accept_prob` statistic. + is to print only the mean `accept_stat` statistic. display_progress (bool): Whether to display a progress bar to track the completed chain sampling iterations. Default value is `True`, i.e. to display progress bar. @@ -2371,6 +3708,16 @@

      Args

      factory function for progress bar to use to show chain progress if enabled (`display_progress=True`). Defaults to `mici.progressbars.ProgressBar`. + adapters (Iterable[Adapter]): Sequence of `mici.adapters.Adapter` + instances to use to adaptatively set parameters of the + integration transition such as the step size while sampling a + chain. Note that the adapter updates are applied in the order + the adapters appear in the iterable and so if multiple adapters + change the same parameter(s) the order will matter. Adaptation + based on the chain state history breaks the Markov property and + so any chain samples while adaptation is active should not be + used in estimates of expectations. Default is to use no + adapters. Returns: final_state (mici.states.ChainState): State of chain after final @@ -2392,21 +3739,21 @@

      Args

      init_state = self._preprocess_init_state(init_state) self.__set_sample_chain_kwargs_defaults(kwargs) final_state, traces, chain_stats = super().sample_chain( - n_sample, init_state, **kwargs) + n_iter, init_state, **kwargs) chain_stats = chain_stats.get('integration_transition', {}) return final_state, traces, chain_stats - def sample_chains(self, n_sample, init_states, **kwargs): + def sample_chains(self, n_iter, init_states, **kwargs): """Sample one or more Markov chains from given initial states. - Performs a specified number of chain iterations (each of consists of a - momentum transition and integration transition), recording the outputs - of functions of the sampled chain state after each iteration. The - chains may be run in parallel across multiple independent processes or - sequentially. In all cases all chains use independent random draws. + Performs a specified number of chain iterations, each of consisting of a + momentum transition followed by an integration transition, recording the + outputs of functions of the sampled chain state after each iteration. + The chains may be run in parallel across multiple independent processes + or sequentially. In all cases all chains use independent random draws. Args: - n_sample (int): Number of samples (iterations) to draw per chain. + n_iter (int): Number of iterations (samples to draw) per chain. init_states (Iterable[ChainState] or Iterable[array]): Initial chain states. Each state can be either an array specifying the state position component or a `mici.states.ChainState` @@ -2417,7 +3764,7 @@

      Args

      Kwargs: n_process (int or None): Number of parallel processes to run chains - over. If set to one then chains will be run sequentially in + over. If `n_process=1` then chains will be run sequentially otherwise a `multiprocessing.Pool` object will be used to dynamically assign the chains across multiple processes. If set to `None` then the number of processes will be set to the @@ -2430,22 +3777,25 @@

      Args

      in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace - function to return that key will be stored. + function to return that key will be stored. Default is to use a + single function which recordes the position component of the + state under the key `pos` and the Hamiltonian at the state + under the key `hamiltonian`. memmap_enabled (bool): Whether to memory-map arrays used to store chain data to files on disk to avoid excessive system memory usage for long chains and/or large chain states. The chain data is written to `.npy` files in the directory specified by `memmap_path` (or a temporary directory if not provided). These files persist after the termination of the function so should - be manually deleted when no longer required. Default is to - for memory mapping to be disabled. + be manually deleted when no longer required. Default is for + memory mapping to be disabled. memmap_path (str): Path to directory to write memory-mapped chain - data to. If not provided, a temporary directory will be created - and the chain data written to files there. + data to. If not provided (the default), a temporary directory + will be created and the chain data written to files there. monitor_stats (Iterable[str]): List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default - is to print only the mean `accept_prob` statistic. + is to print only the mean `accept_stat` statistic. display_progress (bool): Whether to display a progress bar to track the completed chain sampling iterations. Default value is `True`, i.e. to display progress bar. @@ -2453,6 +3803,16 @@

      Args

      factory function for progress bar to use to show chain progress if enabled (`display_progress=True`). Defaults to `mici.progressbars.ProgressBar`. + adapters (Iterable[Adapter]): Sequence of `mici.adapters.Adapter` + instances to use to adaptatively set parameters of the + integration transition such as the step size while sampling a + chain. Note that the adapter updates are applied in the order + the adapters appear in the iterable and so if multiple adapters + change the same parameter(s) the order will matter. Adaptation + based on the chain state history breaks the Markov property and + so any chain samples while adaptation is active should not be + used in estimates of expectations. Default is to use no + adapters. Returns: final_states (List[ChainState]): States of chains after final @@ -2462,21 +3822,210 @@

      Args

      Values in dictionary are list of arrays of variables outputted by trace functions in `trace_funcs` with each array in the list corresponding to a single chain and the leading dimension of - each array corresponding to the sampling (draw) index. The key + each array corresponding to the iteration (draw) index. The key for each value is the corresponding key in the dictionary returned by the trace function which computed the traced value. chain_stats (Dict[str, List[array]]): Dictionary of chain integration transition statistics. Values in dictionary are lists of arrays of chain statistic values with each array in the list corresponding to a single chain and the leading - dimension of each array corresponding to the sampling (draw) + dimension of each array corresponding to the iteration (draw) index. The key for each value is a string description of the corresponding integration transition statistic. """ init_states = [self._preprocess_init_state(i) for i in init_states] self.__set_sample_chain_kwargs_defaults(kwargs) final_states, traces, chain_stats = super().sample_chains( - n_sample, init_states, **kwargs) + n_iter, init_states, **kwargs) + chain_stats = chain_stats.get('integration_transition', {}) + return final_states, traces, chain_stats + + def sample_chains_with_adaptive_warm_up( + self, n_warm_up_iter, n_main_iter, init_states, **kwargs): + """Sample Markov chains from given initial states with adaptive warm up. + + One or more Markov chains are sampled, with each chain iteration + consisting of a momentum transition followed by an integration + transition. The chains are split into multiple *stages* with one or more + adaptive warm up stages followed by the main non-adaptive sampling + stage. During the adaptive stage(s) parameters of the integration + transition such as the integrator step size are adaptively tuned based + on the chain state and/or transition statistics. + + Following the approach of [Stan](https://mc-stan.org) the adaptive + stages are split in to two types - 'fast' adaptation stages which adjust + only transition parameters which can be adapted quickly using local + information (such as the integrator step size) and 'slow' adaptation + stages which *addtionally* adjust transition parameters which require + more global information (such as the metric matrix representation for + Euclidean metric systems which requires estimates of the (co)variances + of the target distribution). The adapters to be used in both the fast + and slow adaptation stages will be referred to as the *fast adapters* + and the adapters to use in only the slow adaptation stages the *slow + adapters*. + + If only fast adapters are specified the adaptive warm up iterations will + form a single fast adaptive stage. If both slow and fast adapters are + specified the adaptive warm up iterations will be split into three + stages: + + 1. An initial fast adaptive stage with only fast adapters active. + 2. A slow adaptive stage with both slow and fast adapters active. + 3. A final adaptive stage with only fast adapters active. + + The slow sampling stage (2) is further split in to a sequence of + growing, memoryless windows with the adapter stages reset at the + beginning of each window, and the number of iterations in each window + increasing (by default doubling). The split of the iterations in each of + these stages can be controlled using the keyword arguments + `n_init_fast_stage_iter`, `n_init_slow_window_iter`, + `n_final_fast_stage_iter` and `slow_window_multiplier` (see descriptions + below). + + In both cases after the initial adaptive warm up stage(s) a subsequent + main sampling stage with no further adaptation is performed. Only in + this main sampling stage are traces of the chain state recorded by + storing the outputs of functions of the sampled chain state after each + iteration. + + The default settings use a single (fast) `DualAveragingStepSizeAdapter` + adapter instance which adapts the integrator step-size using a + dual-averaging algorithm in a single adaptive stage. + + The chains (including both adaptive and non-adaptive stages) may be run + in parallel across multiple independent processes or sequentially. In + all cases all chains use independent random draws. + + Args: + n_warm_up_iter (int): Number of adaptive warm up iterations per + chain. Depending on the adapters specified by the + `fast_adapters` and `slow_adapters` arguments the warm up + iterations may be split between one or more adaptive stages. + The keyword arguments `n_init_fast_stage_iter`, + `n_init_slow_window_iter`, `n_final_fast_stage_iter` and + `slow_window_multiplier` can be used to control the split of + the warm up iterations into these different stages - for details + see descriptions of the individual keyword arguments below. + n_main_iter (int): Number of iterations (samples to draw) per chain + during main (non-adaptive) sampling stage. + init_states (Iterable[ChainState] or Iterable[array]): Initial + chain states. Each state can be either an array specifying the + state position component or a `mici.states.ChainState` + instance. If an array is passed or the `mom` attribute of the + state is not set, a momentum component will be independently + sampled from its conditional distribution. One chain will be + run for each state in the iterable sequence. + + Kwargs: + n_process (int or None): Number of parallel processes to run chains + over. If `n_process=1` then chains will be run sequentially + otherwise a `multiprocessing.Pool` object will be used to + dynamically assign the chains across multiple processes. If set + to `None` then the number of processes will be set to the + output of `os.cpu_count()`. Default is `n_process=1`. + trace_funcs (Iterable[Callable[[ChainState], Dict[str, array]]]): + List of functions which compute the variables to be recorded at + each chain iteration during the main non-adaptive sampling + stage, with each trace function being passed the current state + and returning a dictionary of scalar or array values + corresponding to the variable(s) to be stored. The keys in the + returned dictionaries are used to index the trace arrays in the + returned traces dictionary. If a key appears in multiple + dictionaries only the the value corresponding to the last trace + function to return that key will be stored. Default is to use a + single function which recordes the position component of the + state under the key `pos` and the Hamiltonian at the state under + the key `hamiltonian`. + fast_adapters (Iterable[Adapter]): List of `mici.adapters.Adapter` + instances to use to adaptatively set parameters of the + integration transition such as the step size during the adaptive + (both fast and slow) stages of the chains. Note that the adapter + updates are applied in the order the adapters appear in the + iterable and so if multiple adapters change the same + parameter(s) the order will matter. Default is to use a single + instance of `mici.adapters.DualAveragingStepSizeAdapter` with + its default parameters. + slow_adapters (Iterable[Adapter]): List of `mici.adapters.Adapter` + instances to use to adaptatively set parameters of the + integration transition such as the metric of Euclidean + Hamiltonian systems during the slow adaptive stage of the + chains. Note that the adapter updates are applied in the order + the adapters appear in the iterable and so if multiple adapters + change the same parameter(s) the order will matter. Default is + to use no slow adapters. + n_init_slow_window_iter (int): Number of iterations in the initial + (smallest) window in the slow adaptation stage. Defaults to 25. + If the sum of `n_init_slow_window_iter`, + `n_init_fast_stage_iter` and `n_final_fast_stage_iter` is more + than `n_warm_up_iter` then `n_init_slow_window_iter` is set to + approximately 75% of `n_warm_up_iter` (with a single window + being used in the slow adaptation stage in this case). + n_init_fast_stage_iter (int): Number of iterations in the initial + fast adaptation stage. Defaults to 75. If the sum of + `n_init_slow_window_iter`, n_init_fast_stage_iter` and + `n_final_fast_stage_iter` is more than `n_warm_up_iter` then + `n_init_fast_stage_iter` is set to approximately 15% of + `n_warm_up_iter`. + n_final_fast_stage_iter (int): Number of iterations in the final + fast adaptation stage. Defaults to 50. If the sum of + `n_init_slow_window_iter`, `n_init_fast_stage_iter` and + `n_final_fast_stage_iter` is more than `n_warm_up_iter` then + `n_init_fast_stage_iter` is set to approximately 10% of + `n_warm_up_iter`. + slow_window_multiplier (float): Multiplier by which to increase the + number of iterations of each subsequent slow adaptation window + by. Defaults to 2 such that each window doubles in size. + memmap_enabled (bool): Whether to memory-map arrays used to store + chain data to files on disk to avoid excessive system memory + usage for long chains and/or large chain states. The chain data + is written to `.npy` files in the directory specified by + `memmap_path` (or a temporary directory if not provided). These + files persist after the termination of the function so should + be manually deleted when no longer required. Default is for + memory mapping to be disabled. + memmap_path (str): Path to directory to write memory-mapped chain + data to. If not provided (the default), a temporary directory + will be created and the chain data written to files there. + monitor_stats (Iterable[str]): List of string keys of chain + statistics to monitor mean of over samples computed so far + during sampling by printing as postfix to progress bar. Default + is to print only the mean `accept_stat` statistic. + display_progress (bool): Whether to display a progress bar to + track the completed chain sampling iterations. Default value + is `True`, i.e. to display progress bar. + progress_bar_class (mici.progressbars.BaseProgressBar): Class or + factory function for progress bar to use to show chain + progress if enabled (`display_progress=True`). Defaults to + `mici.progressbars.ProgressBar`. + + Returns: + final_states (List[ChainState]): States of chains after final + iteration. May be used to resume sampling a chain by passing as + the initial states to a new `sample_chains` call. + traces (Dict[str, List[array]]): Dictionary of chain trace arrays. + Values in dictionary are list of arrays of variables outputted + by trace functions in `trace_funcs` with each array in the list + corresponding to a single chain and the leading dimension of + each array corresponding to the iteration (draw) index within + the main non-adaptive sampling stage. The key for each value is + the corresponding key in the dictionary returned by the trace + function which computed the traced value. + chain_stats (Dict[str, List[array]]): Dictionary of chain + integration transition statistics. Values in dictionary are + lists of arrays of chain statistic values with each array in the + list corresponding to a single chain and the leading dimension + of each array corresponding to the iteration (draw) index within + the main non-adaptive sampling stage. The key for each value is + a string description of the corresponding integration transition + statistic. + """ + init_states = [self._preprocess_init_state(i) for i in init_states] + if 'fast_adapters' not in kwargs: + kwargs['fast_adapters'] = [DualAveragingStepSizeAdapter()] + self.__set_sample_chain_kwargs_defaults(kwargs) + final_states, traces, chain_stats = ( + super().sample_chains_with_adaptive_warm_up( + n_warm_up_iter, n_main_iter, init_states, **kwargs)) chain_stats = chain_stats.get('integration_transition', {}) return final_states, traces, chain_stats
      @@ -2494,7 +4043,7 @@

      Subclasses

      Methods

      -def sample_chain(self, n_sample, init_state, **kwargs) +def sample_chain(self, n_iter, init_state, **kwargs)

      Sample a Markov chain from a given initial state.

      @@ -2503,8 +4052,8 @@

      Methods

      outputs of functions of the sampled chain state after each iteration.

      Args

      -
      n_sample : int
      -
      Number of samples (iterations) to draw per chain.
      +
      n_iter : int
      +
      Number of iterations (samples to draw) per chain.
      init_state : ChainState or array
      Initial chain state. The state can be either an array specifying the state position @@ -2524,7 +4073,10 @@

      Kwargs

      in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace -function to return that key will be stored.

      +function to return that key will be stored. Default is to use a +single function which recordes the position component of the +state under the key pos and the Hamiltonian at the state +under the key hamiltonian.

      memmap_enabled : bool
      Whether to memory-map arrays used to store @@ -2533,8 +4085,8 @@

      Kwargs

      is written to .npy files in the directory specified by memmap_path (or a temporary directory if not provided). These files persist after the termination of the function so should -be manually deleted when no longer required. Default is to -for memory mapping to be disabled.
      +be manually deleted when no longer required. Default is for +memory mapping to be disabled.
      memmap_path : str
      Path to directory to write memory-mapped chain data to. If not provided, a temporary directory will be created @@ -2543,7 +4095,7 @@

      Kwargs

      List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default -is to print only the mean accept_prob statistic.
      +is to print only the mean accept_stat statistic.
      display_progress : bool
      Whether to display a progress bar to track the completed chain sampling iterations. Default value @@ -2553,6 +4105,17 @@

      Kwargs

      factory function for progress bar to use to show chain progress if enabled (display_progress=True). Defaults to ProgressBar.
      +
      adapters : Iterable[Adapter]
      +
      Sequence of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the step size while sampling a +chain. Note that the adapter updates are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Adaptation +based on the chain state history breaks the Markov property and +so any chain samples while adaptation is active should not be +used in estimates of expectations. Default is to use no +adapters.

      Returns

      @@ -2578,9 +4141,9 @@

      Returns

      Expand source code -Browse git +Browse git -
      def sample_chain(self, n_sample, init_state, **kwargs):
      +
      def sample_chain(self, n_iter, init_state, **kwargs):
           """Sample a Markov chain from a given initial state.
       
           Performs a specified number of chain iterations (each of which may be
      @@ -2588,7 +4151,7 @@ 

      Returns

      outputs of functions of the sampled chain state after each iteration. Args: - n_sample (int): Number of samples (iterations) to draw per chain. + n_iter (int): Number of iterations (samples to draw) per chain. init_state (mici.states.ChainState or array): Initial chain state. The state can be either an array specifying the state position component or a `mici.states.ChainState` instance. If an array @@ -2605,22 +4168,25 @@

      Returns

      in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace - function to return that key will be stored. + function to return that key will be stored. Default is to use a + single function which recordes the position component of the + state under the key `pos` and the Hamiltonian at the state + under the key `hamiltonian`. memmap_enabled (bool): Whether to memory-map arrays used to store chain data to files on disk to avoid excessive system memory usage for long chains and/or large chain states. The chain data is written to `.npy` files in the directory specified by `memmap_path` (or a temporary directory if not provided). These files persist after the termination of the function so should - be manually deleted when no longer required. Default is to - for memory mapping to be disabled. + be manually deleted when no longer required. Default is for + memory mapping to be disabled. memmap_path (str): Path to directory to write memory-mapped chain data to. If not provided, a temporary directory will be created and the chain data written to files there. monitor_stats (Iterable[str]): List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default - is to print only the mean `accept_prob` statistic. + is to print only the mean `accept_stat` statistic. display_progress (bool): Whether to display a progress bar to track the completed chain sampling iterations. Default value is `True`, i.e. to display progress bar. @@ -2628,6 +4194,16 @@

      Returns

      factory function for progress bar to use to show chain progress if enabled (`display_progress=True`). Defaults to `mici.progressbars.ProgressBar`. + adapters (Iterable[Adapter]): Sequence of `mici.adapters.Adapter` + instances to use to adaptatively set parameters of the + integration transition such as the step size while sampling a + chain. Note that the adapter updates are applied in the order + the adapters appear in the iterable and so if multiple adapters + change the same parameter(s) the order will matter. Adaptation + based on the chain state history breaks the Markov property and + so any chain samples while adaptation is active should not be + used in estimates of expectations. Default is to use no + adapters. Returns: final_state (mici.states.ChainState): State of chain after final @@ -2649,25 +4225,25 @@

      Returns

      init_state = self._preprocess_init_state(init_state) self.__set_sample_chain_kwargs_defaults(kwargs) final_state, traces, chain_stats = super().sample_chain( - n_sample, init_state, **kwargs) + n_iter, init_state, **kwargs) chain_stats = chain_stats.get('integration_transition', {}) return final_state, traces, chain_stats
      -def sample_chains(self, n_sample, init_states, **kwargs) +def sample_chains(self, n_iter, init_states, **kwargs)

      Sample one or more Markov chains from given initial states.

      -

      Performs a specified number of chain iterations (each of consists of a -momentum transition and integration transition), recording the outputs -of functions of the sampled chain state after each iteration. The -chains may be run in parallel across multiple independent processes or -sequentially. In all cases all chains use independent random draws.

      +

      Performs a specified number of chain iterations, each of consisting of a +momentum transition followed by an integration transition, recording the +outputs of functions of the sampled chain state after each iteration. +The chains may be run in parallel across multiple independent processes +or sequentially. In all cases all chains use independent random draws.

      Args

      -
      n_sample : int
      -
      Number of samples (iterations) to draw per chain.
      +
      n_iter : int
      +
      Number of iterations (samples to draw) per chain.
      init_states : Iterable[ChainState] or Iterable[array]
      Initial chain states. Each state can be either an array specifying the @@ -2681,7 +4257,7 @@

      Kwargs

      n_process : int or None
      Number of parallel processes to run chains -over. If set to one then chains will be run sequentially in +over. If n_process=1 then chains will be run sequentially otherwise a multiprocessing.Pool object will be used to dynamically assign the chains across multiple processes. If set to None then the number of processes will be set to the @@ -2695,7 +4271,11 @@

      Kwargs

      in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace -function to return that key will be stored.

      +function to return that key will be stored. +Default is to use a +single function which recordes the position component of the +state under the key pos and the Hamiltonian at the state +under the key hamiltonian.

      memmap_enabled : bool
      Whether to memory-map arrays used to store @@ -2704,17 +4284,17 @@

      Kwargs

      is written to .npy files in the directory specified by memmap_path (or a temporary directory if not provided). These files persist after the termination of the function so should -be manually deleted when no longer required. Default is to -for memory mapping to be disabled.
      +be manually deleted when no longer required. Default is for +memory mapping to be disabled.
      memmap_path : str
      Path to directory to write memory-mapped chain -data to. If not provided, a temporary directory will be created -and the chain data written to files there.
      +data to. If not provided (the default), a temporary directory +will be created and the chain data written to files there.
      monitor_stats : Iterable[str]
      List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default -is to print only the mean accept_prob statistic.
      +is to print only the mean accept_stat statistic.
      display_progress : bool
      Whether to display a progress bar to track the completed chain sampling iterations. Default value @@ -2724,6 +4304,17 @@

      Kwargs

      factory function for progress bar to use to show chain progress if enabled (display_progress=True). Defaults to ProgressBar.
      +
      adapters : Iterable[Adapter]
      +
      Sequence of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the step size while sampling a +chain. Note that the adapter updates are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Adaptation +based on the chain state history breaks the Markov property and +so any chain samples while adaptation is active should not be +used in estimates of expectations. Default is to use no +adapters.

      Returns

      @@ -2736,7 +4327,7 @@

      Returns

      Values in dictionary are list of arrays of variables outputted by trace functions in trace_funcs with each array in the list corresponding to a single chain and the leading dimension of -each array corresponding to the sampling (draw) index. The key +each array corresponding to the iteration (draw) index. The key for each value is the corresponding key in the dictionary returned by the trace function which computed the traced value.
      chain_stats : Dict[str, List[array]]
      @@ -2744,26 +4335,26 @@

      Returns

      integration transition statistics. Values in dictionary are lists of arrays of chain statistic values with each array in the list corresponding to a single chain and the leading -dimension of each array corresponding to the sampling (draw) +dimension of each array corresponding to the iteration (draw) index. The key for each value is a string description of the corresponding integration transition statistic.
    Expand source code -Browse git +Browse git -
    def sample_chains(self, n_sample, init_states, **kwargs):
    +
    def sample_chains(self, n_iter, init_states, **kwargs):
         """Sample one or more Markov chains from given initial states.
     
    -    Performs a specified number of chain iterations (each of consists of a
    -    momentum transition and integration transition), recording the outputs
    -    of functions of the sampled chain state after each iteration. The
    -    chains may be run in parallel across multiple independent processes or
    -    sequentially. In all cases all chains use independent random draws.
    +    Performs a specified number of chain iterations, each of consisting of a
    +    momentum transition followed by an integration transition, recording the
    +    outputs of functions of the sampled chain state after each iteration.
    +    The chains may be run in parallel across multiple independent processes
    +    or sequentially. In all cases all chains use independent random draws.
     
         Args:
    -        n_sample (int): Number of samples (iterations) to draw per chain.
    +        n_iter (int): Number of iterations (samples to draw) per chain.
             init_states (Iterable[ChainState] or Iterable[array]): Initial
                 chain states. Each state can be either an array specifying the
                 state position component or a `mici.states.ChainState`
    @@ -2774,7 +4365,7 @@ 

    Returns

    Kwargs: n_process (int or None): Number of parallel processes to run chains - over. If set to one then chains will be run sequentially in + over. If `n_process=1` then chains will be run sequentially otherwise a `multiprocessing.Pool` object will be used to dynamically assign the chains across multiple processes. If set to `None` then the number of processes will be set to the @@ -2787,22 +4378,25 @@

    Returns

    in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace - function to return that key will be stored. + function to return that key will be stored. Default is to use a + single function which recordes the position component of the + state under the key `pos` and the Hamiltonian at the state + under the key `hamiltonian`. memmap_enabled (bool): Whether to memory-map arrays used to store chain data to files on disk to avoid excessive system memory usage for long chains and/or large chain states. The chain data is written to `.npy` files in the directory specified by `memmap_path` (or a temporary directory if not provided). These files persist after the termination of the function so should - be manually deleted when no longer required. Default is to - for memory mapping to be disabled. + be manually deleted when no longer required. Default is for + memory mapping to be disabled. memmap_path (str): Path to directory to write memory-mapped chain - data to. If not provided, a temporary directory will be created - and the chain data written to files there. + data to. If not provided (the default), a temporary directory + will be created and the chain data written to files there. monitor_stats (Iterable[str]): List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default - is to print only the mean `accept_prob` statistic. + is to print only the mean `accept_stat` statistic. display_progress (bool): Whether to display a progress bar to track the completed chain sampling iterations. Default value is `True`, i.e. to display progress bar. @@ -2810,6 +4404,16 @@

    Returns

    factory function for progress bar to use to show chain progress if enabled (`display_progress=True`). Defaults to `mici.progressbars.ProgressBar`. + adapters (Iterable[Adapter]): Sequence of `mici.adapters.Adapter` + instances to use to adaptatively set parameters of the + integration transition such as the step size while sampling a + chain. Note that the adapter updates are applied in the order + the adapters appear in the iterable and so if multiple adapters + change the same parameter(s) the order will matter. Adaptation + based on the chain state history breaks the Markov property and + so any chain samples while adaptation is active should not be + used in estimates of expectations. Default is to use no + adapters. Returns: final_states (List[ChainState]): States of chains after final @@ -2819,21 +4423,411 @@

    Returns

    Values in dictionary are list of arrays of variables outputted by trace functions in `trace_funcs` with each array in the list corresponding to a single chain and the leading dimension of - each array corresponding to the sampling (draw) index. The key + each array corresponding to the iteration (draw) index. The key for each value is the corresponding key in the dictionary returned by the trace function which computed the traced value. chain_stats (Dict[str, List[array]]): Dictionary of chain integration transition statistics. Values in dictionary are lists of arrays of chain statistic values with each array in the list corresponding to a single chain and the leading - dimension of each array corresponding to the sampling (draw) + dimension of each array corresponding to the iteration (draw) index. The key for each value is a string description of the corresponding integration transition statistic. """ init_states = [self._preprocess_init_state(i) for i in init_states] self.__set_sample_chain_kwargs_defaults(kwargs) final_states, traces, chain_stats = super().sample_chains( - n_sample, init_states, **kwargs) + n_iter, init_states, **kwargs) + chain_stats = chain_stats.get('integration_transition', {}) + return final_states, traces, chain_stats
    +
    + +
    +def sample_chains_with_adaptive_warm_up(self, n_warm_up_iter, n_main_iter, init_states, **kwargs) +
    +
    +

    Sample Markov chains from given initial states with adaptive warm up.

    +

    One or more Markov chains are sampled, with each chain iteration +consisting of a momentum transition followed by an integration +transition. The chains are split into multiple stages with one or more +adaptive warm up stages followed by the main non-adaptive sampling +stage. During the adaptive stage(s) parameters of the integration +transition such as the integrator step size are adaptively tuned based +on the chain state and/or transition statistics.

    +

    Following the approach of Stan the adaptive +stages are split in to two types - 'fast' adaptation stages which adjust +only transition parameters which can be adapted quickly using local +information (such as the integrator step size) and 'slow' adaptation +stages which addtionally adjust transition parameters which require +more global information (such as the metric matrix representation for +Euclidean metric systems which requires estimates of the (co)variances +of the target distribution). The adapters to be used in both the fast +and slow adaptation stages will be referred to as the fast adapters +and the adapters to use in only the slow adaptation stages the slow +adapters.

    +

    If only fast adapters are specified the adaptive warm up iterations will +form a single fast adaptive stage. If both slow and fast adapters are +specified the adaptive warm up iterations will be split into three +stages:

    +
      +
    1. An initial fast adaptive stage with only fast adapters active.
    2. +
    3. A slow adaptive stage with both slow and fast adapters active.
    4. +
    5. A final adaptive stage with only fast adapters active.
    6. +
    +

    The slow sampling stage (2) is further split in to a sequence of +growing, memoryless windows with the adapter stages reset at the +beginning of each window, and the number of iterations in each window +increasing (by default doubling). The split of the iterations in each of +these stages can be controlled using the keyword arguments +n_init_fast_stage_iter, n_init_slow_window_iter, +n_final_fast_stage_iter and slow_window_multiplier (see descriptions +below).

    +

    In both cases after the initial adaptive warm up stage(s) a subsequent +main sampling stage with no further adaptation is performed. Only in +this main sampling stage are traces of the chain state recorded by +storing the outputs of functions of the sampled chain state after each +iteration.

    +

    The default settings use a single (fast) DualAveragingStepSizeAdapter +adapter instance which adapts the integrator step-size using a +dual-averaging algorithm in a single adaptive stage.

    +

    The chains (including both adaptive and non-adaptive stages) may be run +in parallel across multiple independent processes or sequentially. In +all cases all chains use independent random draws.

    +

    Args

    +
    +
    n_warm_up_iter : int
    +
    Number of adaptive warm up iterations per +chain. Depending on the adapters specified by the +fast_adapters and slow_adapters arguments the warm up +iterations may be split between one or more adaptive stages. +The keyword arguments n_init_fast_stage_iter, +n_init_slow_window_iter, n_final_fast_stage_iter and +slow_window_multiplier can be used to control the split of +the warm up iterations into these different stages - for details +see descriptions of the individual keyword arguments below.
    +
    n_main_iter : int
    +
    Number of iterations (samples to draw) per chain +during main (non-adaptive) sampling stage.
    +
    init_states : Iterable[ChainState] or Iterable[array]
    +
    Initial +chain states. Each state can be either an array specifying the +state position component or a ChainState +instance. If an array is passed or the mom attribute of the +state is not set, a momentum component will be independently +sampled from its conditional distribution. One chain will be +run for each state in the iterable sequence.
    +
    +

    Kwargs

    +
    +
    n_process : int or None
    +
    Number of parallel processes to run chains +over. If n_process=1 then chains will be run sequentially +otherwise a multiprocessing.Pool object will be used to +dynamically assign the chains across multiple processes. If set +to None then the number of processes will be set to the +output of os.cpu_count(). Default is n_process=1.
    +
    trace_funcs : Iterable[Callable[[ChainState], Dict[str, array]]]
    +
    +

    List of functions which compute the variables to be recorded at +each chain iteration during the main non-adaptive sampling +stage, with each trace function being passed the current state +and returning a dictionary of scalar or array values +corresponding to the variable(s) to be stored. The keys in the +returned dictionaries are used to index the trace arrays in the +returned traces dictionary. If a key appears in multiple +dictionaries only the the value corresponding to the last trace +function to return that key will be stored. +Default is to use a +single function which recordes the position component of the +state under the key pos and the Hamiltonian at the state under +the key hamiltonian.

    +
    +
    fast_adapters : Iterable[Adapter]
    +
    List of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the step size during the adaptive +(both fast and slow) stages of the chains. Note that the adapter +updates are applied in the order the adapters appear in the +iterable and so if multiple adapters change the same +parameter(s) the order will matter. Default is to use a single +instance of DualAveragingStepSizeAdapter with +its default parameters.
    +
    slow_adapters : Iterable[Adapter]
    +
    List of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the metric of Euclidean +Hamiltonian systems during the slow adaptive stage of the +chains. Note that the adapter updates are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Default is +to use no slow adapters.
    +
    n_init_slow_window_iter : int
    +
    Number of iterations in the initial +(smallest) window in the slow adaptation stage. Defaults to 25. +If the sum of n_init_slow_window_iter, +n_init_fast_stage_iter and n_final_fast_stage_iter is more +than n_warm_up_iter then n_init_slow_window_iter is set to +approximately 75% of n_warm_up_iter (with a single window +being used in the slow adaptation stage in this case).
    +
    n_init_fast_stage_iter : int
    +
    Number of iterations in the initial +fast adaptation stage. Defaults to 75. If the sum of +n_init_slow_window_iter, n_init_fast_stage_iterandn_final_fast_stage_iteris more thann_warm_up_iterthenn_init_fast_stage_iteris set to approximately 15% ofn_warm_up_iter`.
    +
    n_final_fast_stage_iter : int
    +
    Number of iterations in the final +fast adaptation stage. Defaults to 50. If the sum of +n_init_slow_window_iter, n_init_fast_stage_iter and +n_final_fast_stage_iter is more than n_warm_up_iter then +n_init_fast_stage_iter is set to approximately 10% of +n_warm_up_iter.
    +
    slow_window_multiplier : float
    +
    Multiplier by which to increase the +number of iterations of each subsequent slow adaptation window +by. Defaults to 2 such that each window doubles in size.
    +
    memmap_enabled : bool
    +
    Whether to memory-map arrays used to store +chain data to files on disk to avoid excessive system memory +usage for long chains and/or large chain states. The chain data +is written to .npy files in the directory specified by +memmap_path (or a temporary directory if not provided). These +files persist after the termination of the function so should +be manually deleted when no longer required. Default is for +memory mapping to be disabled.
    +
    memmap_path : str
    +
    Path to directory to write memory-mapped chain +data to. If not provided (the default), a temporary directory +will be created and the chain data written to files there.
    +
    monitor_stats : Iterable[str]
    +
    List of string keys of chain +statistics to monitor mean of over samples computed so far +during sampling by printing as postfix to progress bar. Default +is to print only the mean accept_stat statistic.
    +
    display_progress : bool
    +
    Whether to display a progress bar to +track the completed chain sampling iterations. Default value +is True, i.e. to display progress bar.
    +
    progress_bar_class : BaseProgressBar
    +
    Class or +factory function for progress bar to use to show chain +progress if enabled (display_progress=True). Defaults to +ProgressBar.
    +
    +

    Returns

    +
    +
    final_states : List[ChainState]
    +
    States of chains after final +iteration. May be used to resume sampling a chain by passing as +the initial states to a new sample_chains call.
    +
    traces : Dict[str, List[array]]
    +
    Dictionary of chain trace arrays. +Values in dictionary are list of arrays of variables outputted +by trace functions in trace_funcs with each array in the list +corresponding to a single chain and the leading dimension of +each array corresponding to the iteration (draw) index within +the main non-adaptive sampling stage. The key for each value is +the corresponding key in the dictionary returned by the trace +function which computed the traced value.
    +
    chain_stats : Dict[str, List[array]]
    +
    Dictionary of chain +integration transition statistics. Values in dictionary are +lists of arrays of chain statistic values with each array in the +list corresponding to a single chain and the leading dimension +of each array corresponding to the iteration (draw) index within +the main non-adaptive sampling stage. The key for each value is +a string description of the corresponding integration transition +statistic.
    +
    +
    + +Expand source code +Browse git + +
    def sample_chains_with_adaptive_warm_up(
    +        self, n_warm_up_iter, n_main_iter, init_states, **kwargs):
    +    """Sample Markov chains from given initial states with adaptive warm up.
    +
    +    One or more Markov chains are sampled, with each chain iteration
    +    consisting of a momentum transition followed by an integration
    +    transition. The chains are split into multiple *stages* with one or more
    +    adaptive warm up stages followed by the main non-adaptive sampling
    +    stage. During the adaptive stage(s) parameters of the integration
    +    transition such as the integrator step size are adaptively tuned based
    +    on the chain state and/or transition statistics.
    +
    +    Following the approach of [Stan](https://mc-stan.org) the adaptive
    +    stages are split in to two types - 'fast' adaptation stages which adjust
    +    only transition parameters which can be adapted quickly using local
    +    information (such as the integrator step size) and 'slow' adaptation
    +    stages which *addtionally* adjust transition parameters which require
    +    more global information (such as the metric matrix representation for
    +    Euclidean metric systems which requires estimates of the (co)variances
    +    of the target distribution). The adapters to be used in both the fast
    +    and slow adaptation stages will be referred to as the *fast adapters*
    +    and the adapters to use in only the slow adaptation stages the *slow
    +    adapters*.
    +
    +    If only fast adapters are specified the adaptive warm up iterations will
    +    form a single fast adaptive stage. If both slow and fast adapters are
    +    specified the adaptive warm up iterations will be split into three
    +    stages:
    +
    +      1. An initial fast adaptive stage with only fast adapters active.
    +      2. A slow adaptive stage with both slow and fast adapters active.
    +      3. A final adaptive stage with only fast adapters active.
    +
    +    The slow sampling stage (2) is further split in to a sequence of
    +    growing, memoryless windows with the adapter stages reset at the
    +    beginning of each window, and the number of iterations in each window
    +    increasing (by default doubling). The split of the iterations in each of
    +    these stages can be controlled using the keyword arguments
    +    `n_init_fast_stage_iter`, `n_init_slow_window_iter`,
    +    `n_final_fast_stage_iter` and `slow_window_multiplier` (see descriptions
    +    below).
    +
    +    In both cases after the initial adaptive warm up stage(s) a subsequent
    +    main sampling stage with no further adaptation is performed. Only in
    +    this main sampling stage are traces of the chain state recorded by
    +    storing the outputs of functions of the sampled chain state after each
    +    iteration.
    +
    +    The default settings use a single (fast) `DualAveragingStepSizeAdapter`
    +    adapter instance which adapts the integrator step-size using a
    +    dual-averaging algorithm in a single adaptive stage.
    +
    +    The chains (including both adaptive and non-adaptive stages) may be run
    +    in parallel across multiple independent processes or sequentially. In
    +    all cases all chains use independent random draws.
    +
    +    Args:
    +        n_warm_up_iter (int): Number of adaptive warm up iterations per
    +            chain. Depending on the adapters specified by the
    +            `fast_adapters` and `slow_adapters` arguments the warm up
    +            iterations may be split between one or more adaptive stages.
    +            The keyword arguments `n_init_fast_stage_iter`,
    +            `n_init_slow_window_iter`, `n_final_fast_stage_iter` and
    +            `slow_window_multiplier` can be used to control the split of
    +            the warm up iterations into these different stages - for details
    +            see descriptions of the individual keyword arguments below.
    +        n_main_iter (int): Number of iterations (samples to draw) per chain
    +            during main (non-adaptive) sampling stage.
    +        init_states (Iterable[ChainState] or Iterable[array]): Initial
    +            chain states. Each state can be either an array specifying the
    +            state position component or a `mici.states.ChainState`
    +            instance. If an array is passed or the `mom` attribute of the
    +            state is not set, a momentum component will be independently
    +            sampled from its conditional distribution. One chain will be
    +            run for each state in the iterable sequence.
    +
    +    Kwargs:
    +        n_process (int or None): Number of parallel processes to run chains
    +            over. If `n_process=1` then chains will be run sequentially
    +            otherwise a `multiprocessing.Pool` object will be used to
    +            dynamically assign the chains across multiple processes. If set
    +            to `None` then the number of processes will be set to the
    +            output of `os.cpu_count()`. Default is `n_process=1`.
    +        trace_funcs (Iterable[Callable[[ChainState], Dict[str, array]]]):
    +            List of functions which compute the variables to be recorded at
    +            each chain iteration during the main non-adaptive sampling
    +            stage, with each trace function being passed the current state
    +            and returning a dictionary of scalar or array values
    +            corresponding to the variable(s) to be stored. The keys in the
    +            returned dictionaries are used to index the trace arrays in the
    +            returned traces dictionary. If a key appears in multiple
    +            dictionaries only the the value corresponding to the last trace
    +            function to return that key will be stored.  Default is to use a
    +            single function which recordes the position component of the
    +            state under the key `pos` and the Hamiltonian at the state under
    +            the key `hamiltonian`.
    +        fast_adapters (Iterable[Adapter]): List of `mici.adapters.Adapter`
    +            instances to use to adaptatively set parameters of the
    +            integration transition such as the step size during the adaptive
    +            (both fast and slow) stages of the chains. Note that the adapter
    +            updates are applied in the order the adapters appear in the
    +            iterable and so if multiple adapters change the same
    +            parameter(s) the order will matter. Default is to use a single
    +            instance of `mici.adapters.DualAveragingStepSizeAdapter` with
    +            its default parameters.
    +        slow_adapters (Iterable[Adapter]): List of `mici.adapters.Adapter`
    +            instances to use to adaptatively set parameters of the
    +            integration transition such as the metric of Euclidean
    +            Hamiltonian systems during the slow adaptive stage of the
    +            chains. Note that the adapter updates are applied in the order
    +            the adapters appear in the iterable and so if multiple adapters
    +            change the same parameter(s) the order will matter. Default is
    +            to use no slow adapters.
    +        n_init_slow_window_iter (int): Number of iterations in the initial
    +            (smallest) window in the slow adaptation stage. Defaults to 25.
    +            If the sum of `n_init_slow_window_iter`,
    +            `n_init_fast_stage_iter` and `n_final_fast_stage_iter` is more
    +            than `n_warm_up_iter` then `n_init_slow_window_iter` is set to
    +            approximately 75% of `n_warm_up_iter` (with a single window
    +            being used in the slow adaptation stage in this case).
    +        n_init_fast_stage_iter (int): Number of iterations in the initial
    +            fast adaptation stage. Defaults to 75. If the sum of
    +            `n_init_slow_window_iter`, n_init_fast_stage_iter` and
    +            `n_final_fast_stage_iter` is more than `n_warm_up_iter` then
    +            `n_init_fast_stage_iter` is set to approximately 15% of
    +            `n_warm_up_iter`.
    +        n_final_fast_stage_iter (int): Number of iterations in the final
    +            fast adaptation stage. Defaults to 50. If the sum of
    +            `n_init_slow_window_iter`, `n_init_fast_stage_iter` and
    +            `n_final_fast_stage_iter` is more than `n_warm_up_iter` then
    +            `n_init_fast_stage_iter` is set to approximately 10% of
    +            `n_warm_up_iter`.
    +        slow_window_multiplier (float): Multiplier by which to increase the
    +            number of iterations of each subsequent slow adaptation window
    +            by. Defaults to 2 such that each window doubles in size.
    +        memmap_enabled (bool): Whether to memory-map arrays used to store
    +            chain data to files on disk to avoid excessive system memory
    +            usage for long chains and/or large chain states. The chain data
    +            is written to `.npy` files in the directory specified by
    +            `memmap_path` (or a temporary directory if not provided). These
    +            files persist after the termination of the function so should
    +            be manually deleted when no longer required. Default is for
    +            memory mapping to be disabled.
    +        memmap_path (str): Path to directory to write memory-mapped chain
    +            data to. If not provided (the default), a temporary directory
    +            will be created and the chain data written to files there.
    +        monitor_stats (Iterable[str]): List of string keys of chain
    +            statistics to monitor mean of over samples computed so far
    +            during sampling by printing as postfix to progress bar. Default
    +            is to print only the mean `accept_stat` statistic.
    +        display_progress (bool): Whether to display a progress bar to
    +            track the completed chain sampling iterations. Default value
    +            is `True`, i.e. to display progress bar.
    +        progress_bar_class (mici.progressbars.BaseProgressBar): Class or
    +            factory function for progress bar to use to show chain
    +            progress if enabled (`display_progress=True`). Defaults to
    +            `mici.progressbars.ProgressBar`.
    +
    +    Returns:
    +        final_states (List[ChainState]): States of chains after final
    +            iteration. May be used to resume sampling a chain by passing as
    +            the initial states to a new `sample_chains` call.
    +        traces (Dict[str, List[array]]): Dictionary of chain trace arrays.
    +            Values in dictionary are list of arrays of variables outputted
    +            by trace functions in `trace_funcs` with each array in the list
    +            corresponding to a single chain and the leading dimension of
    +            each array corresponding to the iteration (draw) index within
    +            the main non-adaptive sampling stage. The key for each value is
    +            the corresponding key in the dictionary returned by the trace
    +            function which computed the traced value.
    +        chain_stats (Dict[str, List[array]]): Dictionary of chain
    +            integration transition statistics. Values in dictionary are
    +            lists of arrays of chain statistic values with each array in the
    +            list corresponding to a single chain and the leading dimension
    +            of each array corresponding to the iteration (draw) index within
    +            the main non-adaptive sampling stage. The key for each value is
    +            a string description of the corresponding integration transition
    +            statistic.
    +    """
    +    init_states = [self._preprocess_init_state(i) for i in init_states]
    +    if 'fast_adapters' not in kwargs:
    +        kwargs['fast_adapters'] = [DualAveragingStepSizeAdapter()]
    +    self.__set_sample_chain_kwargs_defaults(kwargs)
    +    final_states, traces, chain_stats = (
    +        super().sample_chains_with_adaptive_warm_up(
    +            n_warm_up_iter, n_main_iter, init_states, **kwargs))
         chain_stats = chain_stats.get('integration_transition', {})
         return final_states, traces, chain_stats
    @@ -2869,8 +4863,8 @@

    Args

    system : System
    Hamiltonian system to be simulated.
    -
    rng : RandomState
    -
    Numpy RandomState random number generator.
    +
    rng : Generator or RandomState
    +
    Numpy random number generator.
    integrator : Integrator
    Symplectic integrator to use to simulate dynamics in integration transition.
    @@ -2891,7 +4885,7 @@

    Args

    Expand source code -Browse git +Browse git
    class StaticMetropolisHMC(HamiltonianMCMC):
         """Static integration time H-MCMC implementation with Metropolis sampling.
    @@ -2924,7 +4918,7 @@ 

    Args

    """ Args: system (mici.systems.System): Hamiltonian system to be simulated. - rng (RandomState): Numpy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. integrator (mici.integrators.Integrator): Symplectic integrator to use to simulate dynamics in integration transition. n_step (int): Number of integrator steps to simulate in each @@ -2966,7 +4960,7 @@

    Instance variables

    Expand source code -Browse git +Browse git
    @property
     def n_step(self):
    @@ -2978,7 +4972,7 @@ 

    Instance variables

    Methods

    -def sample_chain(self, n_sample, init_state, **kwargs) +def sample_chain(self, n_iter, init_state, **kwargs)

    Sample a Markov chain from a given initial state.

    @@ -2987,8 +4981,8 @@

    Methods

    outputs of functions of the sampled chain state after each iteration.

    Args

    -
    n_sample : int
    -
    Number of samples (iterations) to draw per chain.
    +
    n_iter : int
    +
    Number of iterations (samples to draw) per chain.
    init_state : ChainState or array
    Initial chain state. The state can be either an array specifying the state position @@ -3008,7 +5002,10 @@

    Kwargs

    in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace -function to return that key will be stored.

    +function to return that key will be stored. Default is to use a +single function which recordes the position component of the +state under the key pos and the Hamiltonian at the state +under the key hamiltonian.

    memmap_enabled : bool
    Whether to memory-map arrays used to store @@ -3017,8 +5014,8 @@

    Kwargs

    is written to .npy files in the directory specified by memmap_path (or a temporary directory if not provided). These files persist after the termination of the function so should -be manually deleted when no longer required. Default is to -for memory mapping to be disabled.
    +be manually deleted when no longer required. Default is for +memory mapping to be disabled.
    memmap_path : str
    Path to directory to write memory-mapped chain data to. If not provided, a temporary directory will be created @@ -3027,7 +5024,7 @@

    Kwargs

    List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default -is to print only the mean accept_prob statistic.
    +is to print only the mean accept_stat statistic.
    display_progress : bool
    Whether to display a progress bar to track the completed chain sampling iterations. Default value @@ -3037,6 +5034,17 @@

    Kwargs

    factory function for progress bar to use to show chain progress if enabled (display_progress=True). Defaults to ProgressBar.
    +
    adapters : Iterable[Adapter]
    +
    Sequence of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the step size while sampling a +chain. Note that the adapter updates are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Adaptation +based on the chain state history breaks the Markov property and +so any chain samples while adaptation is active should not be +used in estimates of expectations. Default is to use no +adapters.

    Returns

    @@ -3061,19 +5069,19 @@

    Returns

    -def sample_chains(self, n_sample, init_states, **kwargs) +def sample_chains(self, n_iter, init_states, **kwargs)

    Sample one or more Markov chains from given initial states.

    -

    Performs a specified number of chain iterations (each of consists of a -momentum transition and integration transition), recording the outputs -of functions of the sampled chain state after each iteration. The -chains may be run in parallel across multiple independent processes or -sequentially. In all cases all chains use independent random draws.

    +

    Performs a specified number of chain iterations, each of consisting of a +momentum transition followed by an integration transition, recording the +outputs of functions of the sampled chain state after each iteration. +The chains may be run in parallel across multiple independent processes +or sequentially. In all cases all chains use independent random draws.

    Args

    -
    n_sample : int
    -
    Number of samples (iterations) to draw per chain.
    +
    n_iter : int
    +
    Number of iterations (samples to draw) per chain.
    init_states : Iterable[ChainState] or Iterable[array]
    Initial chain states. Each state can be either an array specifying the @@ -3087,7 +5095,7 @@

    Kwargs

    n_process : int or None
    Number of parallel processes to run chains -over. If set to one then chains will be run sequentially in +over. If n_process=1 then chains will be run sequentially otherwise a multiprocessing.Pool object will be used to dynamically assign the chains across multiple processes. If set to None then the number of processes will be set to the @@ -3101,8 +5109,217 @@

    Kwargs

    in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace -function to return that key will be stored.

    +function to return that key will be stored. +Default is to use a +single function which recordes the position component of the +state under the key pos and the Hamiltonian at the state +under the key hamiltonian.

    +
    +
    memmap_enabled : bool
    +
    Whether to memory-map arrays used to store +chain data to files on disk to avoid excessive system memory +usage for long chains and/or large chain states. The chain data +is written to .npy files in the directory specified by +memmap_path (or a temporary directory if not provided). These +files persist after the termination of the function so should +be manually deleted when no longer required. Default is for +memory mapping to be disabled.
    +
    memmap_path : str
    +
    Path to directory to write memory-mapped chain +data to. If not provided (the default), a temporary directory +will be created and the chain data written to files there.
    +
    monitor_stats : Iterable[str]
    +
    List of string keys of chain +statistics to monitor mean of over samples computed so far +during sampling by printing as postfix to progress bar. Default +is to print only the mean accept_stat statistic.
    +
    display_progress : bool
    +
    Whether to display a progress bar to +track the completed chain sampling iterations. Default value +is True, i.e. to display progress bar.
    +
    progress_bar_class : BaseProgressBar
    +
    Class or +factory function for progress bar to use to show chain +progress if enabled (display_progress=True). Defaults to +ProgressBar.
    +
    adapters : Iterable[Adapter]
    +
    Sequence of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the step size while sampling a +chain. Note that the adapter updates are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Adaptation +based on the chain state history breaks the Markov property and +so any chain samples while adaptation is active should not be +used in estimates of expectations. Default is to use no +adapters.
    +
    +

    Returns

    +
    +
    final_states : List[ChainState]
    +
    States of chains after final +iteration. May be used to resume sampling a chain by passing as +the initial states to a new sample_chains call.
    +
    traces : Dict[str, List[array]]
    +
    Dictionary of chain trace arrays. +Values in dictionary are list of arrays of variables outputted +by trace functions in trace_funcs with each array in the list +corresponding to a single chain and the leading dimension of +each array corresponding to the iteration (draw) index. The key +for each value is the corresponding key in the dictionary +returned by the trace function which computed the traced value.
    +
    chain_stats : Dict[str, List[array]]
    +
    Dictionary of chain +integration transition statistics. Values in dictionary are +lists of arrays of chain statistic values with each array in +the list corresponding to a single chain and the leading +dimension of each array corresponding to the iteration (draw) +index. The key for each value is a string description of the +corresponding integration transition statistic.
    +
    +
    +
    +def sample_chains_with_adaptive_warm_up(self, n_warm_up_iter, n_main_iter, init_states, **kwargs) +
    +
    +

    Sample Markov chains from given initial states with adaptive warm up.

    +

    One or more Markov chains are sampled, with each chain iteration +consisting of a momentum transition followed by an integration +transition. The chains are split into multiple stages with one or more +adaptive warm up stages followed by the main non-adaptive sampling +stage. During the adaptive stage(s) parameters of the integration +transition such as the integrator step size are adaptively tuned based +on the chain state and/or transition statistics.

    +

    Following the approach of Stan the adaptive +stages are split in to two types - 'fast' adaptation stages which adjust +only transition parameters which can be adapted quickly using local +information (such as the integrator step size) and 'slow' adaptation +stages which addtionally adjust transition parameters which require +more global information (such as the metric matrix representation for +Euclidean metric systems which requires estimates of the (co)variances +of the target distribution). The adapters to be used in both the fast +and slow adaptation stages will be referred to as the fast adapters +and the adapters to use in only the slow adaptation stages the slow +adapters.

    +

    If only fast adapters are specified the adaptive warm up iterations will +form a single fast adaptive stage. If both slow and fast adapters are +specified the adaptive warm up iterations will be split into three +stages:

    +
      +
    1. An initial fast adaptive stage with only fast adapters active.
    2. +
    3. A slow adaptive stage with both slow and fast adapters active.
    4. +
    5. A final adaptive stage with only fast adapters active.
    6. +
    +

    The slow sampling stage (2) is further split in to a sequence of +growing, memoryless windows with the adapter stages reset at the +beginning of each window, and the number of iterations in each window +increasing (by default doubling). The split of the iterations in each of +these stages can be controlled using the keyword arguments +n_init_fast_stage_iter, n_init_slow_window_iter, +n_final_fast_stage_iter and slow_window_multiplier (see descriptions +below).

    +

    In both cases after the initial adaptive warm up stage(s) a subsequent +main sampling stage with no further adaptation is performed. Only in +this main sampling stage are traces of the chain state recorded by +storing the outputs of functions of the sampled chain state after each +iteration.

    +

    The default settings use a single (fast) DualAveragingStepSizeAdapter +adapter instance which adapts the integrator step-size using a +dual-averaging algorithm in a single adaptive stage.

    +

    The chains (including both adaptive and non-adaptive stages) may be run +in parallel across multiple independent processes or sequentially. In +all cases all chains use independent random draws.

    +

    Args

    +
    +
    n_warm_up_iter : int
    +
    Number of adaptive warm up iterations per +chain. Depending on the adapters specified by the +fast_adapters and slow_adapters arguments the warm up +iterations may be split between one or more adaptive stages. +The keyword arguments n_init_fast_stage_iter, +n_init_slow_window_iter, n_final_fast_stage_iter and +slow_window_multiplier can be used to control the split of +the warm up iterations into these different stages - for details +see descriptions of the individual keyword arguments below.
    +
    n_main_iter : int
    +
    Number of iterations (samples to draw) per chain +during main (non-adaptive) sampling stage.
    +
    init_states : Iterable[ChainState] or Iterable[array]
    +
    Initial +chain states. Each state can be either an array specifying the +state position component or a ChainState +instance. If an array is passed or the mom attribute of the +state is not set, a momentum component will be independently +sampled from its conditional distribution. One chain will be +run for each state in the iterable sequence.
    +
    +

    Kwargs

    +
    +
    n_process : int or None
    +
    Number of parallel processes to run chains +over. If n_process=1 then chains will be run sequentially +otherwise a multiprocessing.Pool object will be used to +dynamically assign the chains across multiple processes. If set +to None then the number of processes will be set to the +output of os.cpu_count(). Default is n_process=1.
    +
    trace_funcs : Iterable[Callable[[ChainState], Dict[str, array]]]
    +
    +

    List of functions which compute the variables to be recorded at +each chain iteration during the main non-adaptive sampling +stage, with each trace function being passed the current state +and returning a dictionary of scalar or array values +corresponding to the variable(s) to be stored. The keys in the +returned dictionaries are used to index the trace arrays in the +returned traces dictionary. If a key appears in multiple +dictionaries only the the value corresponding to the last trace +function to return that key will be stored. +Default is to use a +single function which recordes the position component of the +state under the key pos and the Hamiltonian at the state under +the key hamiltonian.

    +
    fast_adapters : Iterable[Adapter]
    +
    List of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the step size during the adaptive +(both fast and slow) stages of the chains. Note that the adapter +updates are applied in the order the adapters appear in the +iterable and so if multiple adapters change the same +parameter(s) the order will matter. Default is to use a single +instance of DualAveragingStepSizeAdapter with +its default parameters.
    +
    slow_adapters : Iterable[Adapter]
    +
    List of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the metric of Euclidean +Hamiltonian systems during the slow adaptive stage of the +chains. Note that the adapter updates are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Default is +to use no slow adapters.
    +
    n_init_slow_window_iter : int
    +
    Number of iterations in the initial +(smallest) window in the slow adaptation stage. Defaults to 25. +If the sum of n_init_slow_window_iter, +n_init_fast_stage_iter and n_final_fast_stage_iter is more +than n_warm_up_iter then n_init_slow_window_iter is set to +approximately 75% of n_warm_up_iter (with a single window +being used in the slow adaptation stage in this case).
    +
    n_init_fast_stage_iter : int
    +
    Number of iterations in the initial +fast adaptation stage. Defaults to 75. If the sum of +n_init_slow_window_iter, n_init_fast_stage_iterandn_final_fast_stage_iteris more thann_warm_up_iterthenn_init_fast_stage_iteris set to approximately 15% ofn_warm_up_iter`.
    +
    n_final_fast_stage_iter : int
    +
    Number of iterations in the final +fast adaptation stage. Defaults to 50. If the sum of +n_init_slow_window_iter, n_init_fast_stage_iter and +n_final_fast_stage_iter is more than n_warm_up_iter then +n_init_fast_stage_iter is set to approximately 10% of +n_warm_up_iter.
    +
    slow_window_multiplier : float
    +
    Multiplier by which to increase the +number of iterations of each subsequent slow adaptation window +by. Defaults to 2 such that each window doubles in size.
    memmap_enabled : bool
    Whether to memory-map arrays used to store chain data to files on disk to avoid excessive system memory @@ -3110,17 +5327,17 @@

    Kwargs

    is written to .npy files in the directory specified by memmap_path (or a temporary directory if not provided). These files persist after the termination of the function so should -be manually deleted when no longer required. Default is to -for memory mapping to be disabled.
    +be manually deleted when no longer required. Default is for +memory mapping to be disabled.
    memmap_path : str
    Path to directory to write memory-mapped chain -data to. If not provided, a temporary directory will be created -and the chain data written to files there.
    +data to. If not provided (the default), a temporary directory +will be created and the chain data written to files there.
    monitor_stats : Iterable[str]
    List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default -is to print only the mean accept_prob statistic.
    +is to print only the mean accept_stat statistic.
    display_progress : bool
    Whether to display a progress bar to track the completed chain sampling iterations. Default value @@ -3142,17 +5359,19 @@

    Returns

    Values in dictionary are list of arrays of variables outputted by trace functions in trace_funcs with each array in the list corresponding to a single chain and the leading dimension of -each array corresponding to the sampling (draw) index. The key -for each value is the corresponding key in the dictionary -returned by the trace function which computed the traced value.
    +each array corresponding to the iteration (draw) index within +the main non-adaptive sampling stage. The key for each value is +the corresponding key in the dictionary returned by the trace +function which computed the traced value.
    chain_stats : Dict[str, List[array]]
    Dictionary of chain integration transition statistics. Values in dictionary are -lists of arrays of chain statistic values with each array in -the list corresponding to a single chain and the leading -dimension of each array corresponding to the sampling (draw) -index. The key for each value is a string description of the -corresponding integration transition statistic.
    +lists of arrays of chain statistic values with each array in the +list corresponding to a single chain and the leading dimension +of each array corresponding to the iteration (draw) index within +the main non-adaptive sampling stage. The key for each value is +a string description of the corresponding integration transition +statistic. @@ -3188,8 +5407,8 @@

    Args

    system : System
    Hamiltonian system to be simulated.
    -
    rng : RandomState
    -
    Numpy RandomState random number generator.
    +
    rng : Generator or RandomState
    +
    Numpy random number generator.
    integrator : Integrator
    Symplectic integrator to use to simulate dynamics in integration transition.
    @@ -3214,7 +5433,7 @@

    Args

    Expand source code -Browse git +Browse git
    class RandomMetropolisHMC(HamiltonianMCMC):
         """Random integration time H-MCMC with Metropolis sampling of new state.
    @@ -3249,7 +5468,7 @@ 

    Args

    """ Args: system (mici.systems.System): Hamiltonian system to be simulated. - rng (RandomState): Numpy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. integrator (mici.integrators.Integrator): Symplectic integrator to use to simulate dynamics in integration transition. n_step_range (Tuple[int, int]): Tuple `(lower, upper)` with two @@ -3297,7 +5516,7 @@

    Instance variables

    Expand source code -Browse git +Browse git
    @property
     def n_step_range(self):
    @@ -3309,7 +5528,7 @@ 

    Instance variables

    Methods

    -def sample_chain(self, n_sample, init_state, **kwargs) +def sample_chain(self, n_iter, init_state, **kwargs)

    Sample a Markov chain from a given initial state.

    @@ -3318,8 +5537,8 @@

    Methods

    outputs of functions of the sampled chain state after each iteration.

    Args

    -
    n_sample : int
    -
    Number of samples (iterations) to draw per chain.
    +
    n_iter : int
    +
    Number of iterations (samples to draw) per chain.
    init_state : ChainState or array
    Initial chain state. The state can be either an array specifying the state position @@ -3339,7 +5558,10 @@

    Kwargs

    in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace -function to return that key will be stored.

    +function to return that key will be stored. Default is to use a +single function which recordes the position component of the +state under the key pos and the Hamiltonian at the state +under the key hamiltonian.

    memmap_enabled : bool
    Whether to memory-map arrays used to store @@ -3348,8 +5570,8 @@

    Kwargs

    is written to .npy files in the directory specified by memmap_path (or a temporary directory if not provided). These files persist after the termination of the function so should -be manually deleted when no longer required. Default is to -for memory mapping to be disabled.
    +be manually deleted when no longer required. Default is for +memory mapping to be disabled.
    memmap_path : str
    Path to directory to write memory-mapped chain data to. If not provided, a temporary directory will be created @@ -3358,7 +5580,7 @@

    Kwargs

    List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default -is to print only the mean accept_prob statistic.
    +is to print only the mean accept_stat statistic.
    display_progress : bool
    Whether to display a progress bar to track the completed chain sampling iterations. Default value @@ -3368,6 +5590,17 @@

    Kwargs

    factory function for progress bar to use to show chain progress if enabled (display_progress=True). Defaults to ProgressBar.
    +
    adapters : Iterable[Adapter]
    +
    Sequence of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the step size while sampling a +chain. Note that the adapter updates are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Adaptation +based on the chain state history breaks the Markov property and +so any chain samples while adaptation is active should not be +used in estimates of expectations. Default is to use no +adapters.

    Returns

    @@ -3392,19 +5625,19 @@

    Returns

    -def sample_chains(self, n_sample, init_states, **kwargs) +def sample_chains(self, n_iter, init_states, **kwargs)

    Sample one or more Markov chains from given initial states.

    -

    Performs a specified number of chain iterations (each of consists of a -momentum transition and integration transition), recording the outputs -of functions of the sampled chain state after each iteration. The -chains may be run in parallel across multiple independent processes or -sequentially. In all cases all chains use independent random draws.

    +

    Performs a specified number of chain iterations, each of consisting of a +momentum transition followed by an integration transition, recording the +outputs of functions of the sampled chain state after each iteration. +The chains may be run in parallel across multiple independent processes +or sequentially. In all cases all chains use independent random draws.

    Args

    -
    n_sample : int
    -
    Number of samples (iterations) to draw per chain.
    +
    n_iter : int
    +
    Number of iterations (samples to draw) per chain.
    init_states : Iterable[ChainState] or Iterable[array]
    Initial chain states. Each state can be either an array specifying the @@ -3418,7 +5651,7 @@

    Kwargs

    n_process : int or None
    Number of parallel processes to run chains -over. If set to one then chains will be run sequentially in +over. If n_process=1 then chains will be run sequentially otherwise a multiprocessing.Pool object will be used to dynamically assign the chains across multiple processes. If set to None then the number of processes will be set to the @@ -3432,7 +5665,11 @@

    Kwargs

    in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace -function to return that key will be stored.

    +function to return that key will be stored. +Default is to use a +single function which recordes the position component of the +state under the key pos and the Hamiltonian at the state +under the key hamiltonian.

    memmap_enabled : bool
    Whether to memory-map arrays used to store @@ -3441,17 +5678,17 @@

    Kwargs

    is written to .npy files in the directory specified by memmap_path (or a temporary directory if not provided). These files persist after the termination of the function so should -be manually deleted when no longer required. Default is to -for memory mapping to be disabled.
    +be manually deleted when no longer required. Default is for +memory mapping to be disabled.
    memmap_path : str
    Path to directory to write memory-mapped chain -data to. If not provided, a temporary directory will be created -and the chain data written to files there.
    +data to. If not provided (the default), a temporary directory +will be created and the chain data written to files there.
    monitor_stats : Iterable[str]
    List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default -is to print only the mean accept_prob statistic.
    +is to print only the mean accept_stat statistic.
    display_progress : bool
    Whether to display a progress bar to track the completed chain sampling iterations. Default value @@ -3461,6 +5698,17 @@

    Kwargs

    factory function for progress bar to use to show chain progress if enabled (display_progress=True). Defaults to ProgressBar.
    +
    adapters : Iterable[Adapter]
    +
    Sequence of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the step size while sampling a +chain. Note that the adapter updates are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Adaptation +based on the chain state history breaks the Markov property and +so any chain samples while adaptation is active should not be +used in estimates of expectations. Default is to use no +adapters.

    Returns

    @@ -3473,7 +5721,7 @@

    Returns

    Values in dictionary are list of arrays of variables outputted by trace functions in trace_funcs with each array in the list corresponding to a single chain and the leading dimension of -each array corresponding to the sampling (draw) index. The key +each array corresponding to the iteration (draw) index. The key for each value is the corresponding key in the dictionary returned by the trace function which computed the traced value.
    chain_stats : Dict[str, List[array]]
    @@ -3481,11 +5729,207 @@

    Returns

    integration transition statistics. Values in dictionary are lists of arrays of chain statistic values with each array in the list corresponding to a single chain and the leading -dimension of each array corresponding to the sampling (draw) +dimension of each array corresponding to the iteration (draw) index. The key for each value is a string description of the corresponding integration transition statistic.
    +
    +def sample_chains_with_adaptive_warm_up(self, n_warm_up_iter, n_main_iter, init_states, **kwargs) +
    +
    +

    Sample Markov chains from given initial states with adaptive warm up.

    +

    One or more Markov chains are sampled, with each chain iteration +consisting of a momentum transition followed by an integration +transition. The chains are split into multiple stages with one or more +adaptive warm up stages followed by the main non-adaptive sampling +stage. During the adaptive stage(s) parameters of the integration +transition such as the integrator step size are adaptively tuned based +on the chain state and/or transition statistics.

    +

    Following the approach of Stan the adaptive +stages are split in to two types - 'fast' adaptation stages which adjust +only transition parameters which can be adapted quickly using local +information (such as the integrator step size) and 'slow' adaptation +stages which addtionally adjust transition parameters which require +more global information (such as the metric matrix representation for +Euclidean metric systems which requires estimates of the (co)variances +of the target distribution). The adapters to be used in both the fast +and slow adaptation stages will be referred to as the fast adapters +and the adapters to use in only the slow adaptation stages the slow +adapters.

    +

    If only fast adapters are specified the adaptive warm up iterations will +form a single fast adaptive stage. If both slow and fast adapters are +specified the adaptive warm up iterations will be split into three +stages:

    +
      +
    1. An initial fast adaptive stage with only fast adapters active.
    2. +
    3. A slow adaptive stage with both slow and fast adapters active.
    4. +
    5. A final adaptive stage with only fast adapters active.
    6. +
    +

    The slow sampling stage (2) is further split in to a sequence of +growing, memoryless windows with the adapter stages reset at the +beginning of each window, and the number of iterations in each window +increasing (by default doubling). The split of the iterations in each of +these stages can be controlled using the keyword arguments +n_init_fast_stage_iter, n_init_slow_window_iter, +n_final_fast_stage_iter and slow_window_multiplier (see descriptions +below).

    +

    In both cases after the initial adaptive warm up stage(s) a subsequent +main sampling stage with no further adaptation is performed. Only in +this main sampling stage are traces of the chain state recorded by +storing the outputs of functions of the sampled chain state after each +iteration.

    +

    The default settings use a single (fast) DualAveragingStepSizeAdapter +adapter instance which adapts the integrator step-size using a +dual-averaging algorithm in a single adaptive stage.

    +

    The chains (including both adaptive and non-adaptive stages) may be run +in parallel across multiple independent processes or sequentially. In +all cases all chains use independent random draws.

    +

    Args

    +
    +
    n_warm_up_iter : int
    +
    Number of adaptive warm up iterations per +chain. Depending on the adapters specified by the +fast_adapters and slow_adapters arguments the warm up +iterations may be split between one or more adaptive stages. +The keyword arguments n_init_fast_stage_iter, +n_init_slow_window_iter, n_final_fast_stage_iter and +slow_window_multiplier can be used to control the split of +the warm up iterations into these different stages - for details +see descriptions of the individual keyword arguments below.
    +
    n_main_iter : int
    +
    Number of iterations (samples to draw) per chain +during main (non-adaptive) sampling stage.
    +
    init_states : Iterable[ChainState] or Iterable[array]
    +
    Initial +chain states. Each state can be either an array specifying the +state position component or a ChainState +instance. If an array is passed or the mom attribute of the +state is not set, a momentum component will be independently +sampled from its conditional distribution. One chain will be +run for each state in the iterable sequence.
    +
    +

    Kwargs

    +
    +
    n_process : int or None
    +
    Number of parallel processes to run chains +over. If n_process=1 then chains will be run sequentially +otherwise a multiprocessing.Pool object will be used to +dynamically assign the chains across multiple processes. If set +to None then the number of processes will be set to the +output of os.cpu_count(). Default is n_process=1.
    +
    trace_funcs : Iterable[Callable[[ChainState], Dict[str, array]]]
    +
    +

    List of functions which compute the variables to be recorded at +each chain iteration during the main non-adaptive sampling +stage, with each trace function being passed the current state +and returning a dictionary of scalar or array values +corresponding to the variable(s) to be stored. The keys in the +returned dictionaries are used to index the trace arrays in the +returned traces dictionary. If a key appears in multiple +dictionaries only the the value corresponding to the last trace +function to return that key will be stored. +Default is to use a +single function which recordes the position component of the +state under the key pos and the Hamiltonian at the state under +the key hamiltonian.

    +
    +
    fast_adapters : Iterable[Adapter]
    +
    List of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the step size during the adaptive +(both fast and slow) stages of the chains. Note that the adapter +updates are applied in the order the adapters appear in the +iterable and so if multiple adapters change the same +parameter(s) the order will matter. Default is to use a single +instance of DualAveragingStepSizeAdapter with +its default parameters.
    +
    slow_adapters : Iterable[Adapter]
    +
    List of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the metric of Euclidean +Hamiltonian systems during the slow adaptive stage of the +chains. Note that the adapter updates are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Default is +to use no slow adapters.
    +
    n_init_slow_window_iter : int
    +
    Number of iterations in the initial +(smallest) window in the slow adaptation stage. Defaults to 25. +If the sum of n_init_slow_window_iter, +n_init_fast_stage_iter and n_final_fast_stage_iter is more +than n_warm_up_iter then n_init_slow_window_iter is set to +approximately 75% of n_warm_up_iter (with a single window +being used in the slow adaptation stage in this case).
    +
    n_init_fast_stage_iter : int
    +
    Number of iterations in the initial +fast adaptation stage. Defaults to 75. If the sum of +n_init_slow_window_iter, n_init_fast_stage_iterandn_final_fast_stage_iteris more thann_warm_up_iterthenn_init_fast_stage_iteris set to approximately 15% ofn_warm_up_iter`.
    +
    n_final_fast_stage_iter : int
    +
    Number of iterations in the final +fast adaptation stage. Defaults to 50. If the sum of +n_init_slow_window_iter, n_init_fast_stage_iter and +n_final_fast_stage_iter is more than n_warm_up_iter then +n_init_fast_stage_iter is set to approximately 10% of +n_warm_up_iter.
    +
    slow_window_multiplier : float
    +
    Multiplier by which to increase the +number of iterations of each subsequent slow adaptation window +by. Defaults to 2 such that each window doubles in size.
    +
    memmap_enabled : bool
    +
    Whether to memory-map arrays used to store +chain data to files on disk to avoid excessive system memory +usage for long chains and/or large chain states. The chain data +is written to .npy files in the directory specified by +memmap_path (or a temporary directory if not provided). These +files persist after the termination of the function so should +be manually deleted when no longer required. Default is for +memory mapping to be disabled.
    +
    memmap_path : str
    +
    Path to directory to write memory-mapped chain +data to. If not provided (the default), a temporary directory +will be created and the chain data written to files there.
    +
    monitor_stats : Iterable[str]
    +
    List of string keys of chain +statistics to monitor mean of over samples computed so far +during sampling by printing as postfix to progress bar. Default +is to print only the mean accept_stat statistic.
    +
    display_progress : bool
    +
    Whether to display a progress bar to +track the completed chain sampling iterations. Default value +is True, i.e. to display progress bar.
    +
    progress_bar_class : BaseProgressBar
    +
    Class or +factory function for progress bar to use to show chain +progress if enabled (display_progress=True). Defaults to +ProgressBar.
    +
    +

    Returns

    +
    +
    final_states : List[ChainState]
    +
    States of chains after final +iteration. May be used to resume sampling a chain by passing as +the initial states to a new sample_chains call.
    +
    traces : Dict[str, List[array]]
    +
    Dictionary of chain trace arrays. +Values in dictionary are list of arrays of variables outputted +by trace functions in trace_funcs with each array in the list +corresponding to a single chain and the leading dimension of +each array corresponding to the iteration (draw) index within +the main non-adaptive sampling stage. The key for each value is +the corresponding key in the dictionary returned by the trace +function which computed the traced value.
    +
    chain_stats : Dict[str, List[array]]
    +
    Dictionary of chain +integration transition statistics. Values in dictionary are +lists of arrays of chain statistic values with each array in the +list corresponding to a single chain and the leading dimension +of each array corresponding to the iteration (draw) index within +the main non-adaptive sampling stage. The key for each value is +a string description of the corresponding integration transition +statistic.
    +
    +
    @@ -3504,7 +5948,7 @@

    Returns

    When used with the default settings of riemannian_no_u_turn_criterion termination criterion and extra subtree checks enabled, this sampler is equivalent to the default 'NUTS' MCMC algorithm (minus adaptation) used in -Stan as of version v2.23.

    +Stan as of version v2.23.

    References

    1. Hoffman, M.D. and Gelman, A., 2014. The No-U-turn sampler: @@ -3517,8 +5961,8 @@

      Args

      system : System
      Hamiltonian system to be simulated.
      -
      rng : RandomState
      -
      Numpy RandomState random number generator.
      +
      rng : Generator or RandomState
      +
      Numpy random number generator.
      integrator : Integrator
      Symplectic integrator to use to simulate dynamics in integration transition.
      @@ -3552,8 +5996,8 @@

      Args

      behaviour is seen by which the termination criterion fails to detect that the trajectory has expanded past a half-period i.e. has 'U-turned' resulting in trajectories continuing to expand, -potentially up until the max_tree_depth limit is hit. For -more details see the Stan Discourse discussion at kutt.it/yAkIES +potentially up until the max_tree_depth limit is hit. For more +details see this Stan Discourse discussion. If do_extra_subtree_checks is set to True additional termination criterion checks are performed on overlapping subtrees which help to reduce this resonant behaviour at the @@ -3573,7 +6017,7 @@

      Args

      Expand source code -Browse git +Browse git
      class DynamicMultinomialHMC(HamiltonianMCMC):
           """Dynamic integration time H-MCMC with multinomial sampling of new state.
      @@ -3589,7 +6033,7 @@ 

      Args

      When used with the default settings of `riemannian_no_u_turn_criterion` termination criterion and extra subtree checks enabled, this sampler is equivalent to the default 'NUTS' MCMC algorithm (minus adaptation) used in - Stan as of version v2.23. + [Stan](https://mc-stan.org/) as of version v2.23. References: @@ -3607,7 +6051,7 @@

      Args

      """ Args: system (mici.systems.System): Hamiltonian system to be simulated. - rng (RandomState): Numpy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. integrator (mici.integrators.Integrator): Symplectic integrator to use to simulate dynamics in integration transition. max_tree_depth (int): Maximum depth to expand trajectory binary @@ -3635,8 +6079,8 @@

      Args

      behaviour is seen by which the termination criterion fails to detect that the trajectory has expanded past a half-period i.e. has 'U-turned' resulting in trajectories continuing to expand, - potentially up until the `max_tree_depth` limit is hit. For - more details see the Stan Discourse discussion at kutt.it/yAkIES + potentially up until the `max_tree_depth` limit is hit. For more + details see [this Stan Discourse discussion](kutt.it/yAkIES). If `do_extra_subtree_checks` is set to `True` additional termination criterion checks are performed on overlapping subtrees which help to reduce this resonant behaviour at the @@ -3689,7 +6133,7 @@

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def max_tree_depth(self):
      @@ -3703,7 +6147,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def max_delta_h(self):
      @@ -3715,7 +6159,7 @@ 

      Instance variables

      Methods

      -def sample_chain(self, n_sample, init_state, **kwargs) +def sample_chain(self, n_iter, init_state, **kwargs)

      Sample a Markov chain from a given initial state.

      @@ -3724,8 +6168,8 @@

      Methods

      outputs of functions of the sampled chain state after each iteration.

      Args

      -
      n_sample : int
      -
      Number of samples (iterations) to draw per chain.
      +
      n_iter : int
      +
      Number of iterations (samples to draw) per chain.
      init_state : ChainState or array
      Initial chain state. The state can be either an array specifying the state position @@ -3745,7 +6189,10 @@

      Kwargs

      in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace -function to return that key will be stored.

      +function to return that key will be stored. Default is to use a +single function which recordes the position component of the +state under the key pos and the Hamiltonian at the state +under the key hamiltonian.

      memmap_enabled : bool
      Whether to memory-map arrays used to store @@ -3754,8 +6201,8 @@

      Kwargs

      is written to .npy files in the directory specified by memmap_path (or a temporary directory if not provided). These files persist after the termination of the function so should -be manually deleted when no longer required. Default is to -for memory mapping to be disabled.
      +be manually deleted when no longer required. Default is for +memory mapping to be disabled.
      memmap_path : str
      Path to directory to write memory-mapped chain data to. If not provided, a temporary directory will be created @@ -3764,7 +6211,7 @@

      Kwargs

      List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default -is to print only the mean accept_prob statistic.
      +is to print only the mean accept_stat statistic.
      display_progress : bool
      Whether to display a progress bar to track the completed chain sampling iterations. Default value @@ -3774,6 +6221,17 @@

      Kwargs

      factory function for progress bar to use to show chain progress if enabled (display_progress=True). Defaults to ProgressBar.
      +
      adapters : Iterable[Adapter]
      +
      Sequence of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the step size while sampling a +chain. Note that the adapter updates are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Adaptation +based on the chain state history breaks the Markov property and +so any chain samples while adaptation is active should not be +used in estimates of expectations. Default is to use no +adapters.

      Returns

      @@ -3798,19 +6256,19 @@

      Returns

      -def sample_chains(self, n_sample, init_states, **kwargs) +def sample_chains(self, n_iter, init_states, **kwargs)

      Sample one or more Markov chains from given initial states.

      -

      Performs a specified number of chain iterations (each of consists of a -momentum transition and integration transition), recording the outputs -of functions of the sampled chain state after each iteration. The -chains may be run in parallel across multiple independent processes or -sequentially. In all cases all chains use independent random draws.

      +

      Performs a specified number of chain iterations, each of consisting of a +momentum transition followed by an integration transition, recording the +outputs of functions of the sampled chain state after each iteration. +The chains may be run in parallel across multiple independent processes +or sequentially. In all cases all chains use independent random draws.

      Args

      -
      n_sample : int
      -
      Number of samples (iterations) to draw per chain.
      +
      n_iter : int
      +
      Number of iterations (samples to draw) per chain.
      init_states : Iterable[ChainState] or Iterable[array]
      Initial chain states. Each state can be either an array specifying the @@ -3824,7 +6282,7 @@

      Kwargs

      n_process : int or None
      Number of parallel processes to run chains -over. If set to one then chains will be run sequentially in +over. If n_process=1 then chains will be run sequentially otherwise a multiprocessing.Pool object will be used to dynamically assign the chains across multiple processes. If set to None then the number of processes will be set to the @@ -3838,7 +6296,11 @@

      Kwargs

      in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace -function to return that key will be stored.

      +function to return that key will be stored. +Default is to use a +single function which recordes the position component of the +state under the key pos and the Hamiltonian at the state +under the key hamiltonian.

      memmap_enabled : bool
      Whether to memory-map arrays used to store @@ -3847,17 +6309,17 @@

      Kwargs

      is written to .npy files in the directory specified by memmap_path (or a temporary directory if not provided). These files persist after the termination of the function so should -be manually deleted when no longer required. Default is to -for memory mapping to be disabled.
      +be manually deleted when no longer required. Default is for +memory mapping to be disabled.
      memmap_path : str
      Path to directory to write memory-mapped chain -data to. If not provided, a temporary directory will be created -and the chain data written to files there.
      +data to. If not provided (the default), a temporary directory +will be created and the chain data written to files there.
      monitor_stats : Iterable[str]
      List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default -is to print only the mean accept_prob statistic.
      +is to print only the mean accept_stat statistic.
      display_progress : bool
      Whether to display a progress bar to track the completed chain sampling iterations. Default value @@ -3867,6 +6329,17 @@

      Kwargs

      factory function for progress bar to use to show chain progress if enabled (display_progress=True). Defaults to ProgressBar.
      +
      adapters : Iterable[Adapter]
      +
      Sequence of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the step size while sampling a +chain. Note that the adapter updates are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Adaptation +based on the chain state history breaks the Markov property and +so any chain samples while adaptation is active should not be +used in estimates of expectations. Default is to use no +adapters.

      Returns

      @@ -3879,7 +6352,7 @@

      Returns

      Values in dictionary are list of arrays of variables outputted by trace functions in trace_funcs with each array in the list corresponding to a single chain and the leading dimension of -each array corresponding to the sampling (draw) index. The key +each array corresponding to the iteration (draw) index. The key for each value is the corresponding key in the dictionary returned by the trace function which computed the traced value.
      chain_stats : Dict[str, List[array]]
      @@ -3887,11 +6360,207 @@

      Returns

      integration transition statistics. Values in dictionary are lists of arrays of chain statistic values with each array in the list corresponding to a single chain and the leading -dimension of each array corresponding to the sampling (draw) +dimension of each array corresponding to the iteration (draw) index. The key for each value is a string description of the corresponding integration transition statistic.
      +
      +def sample_chains_with_adaptive_warm_up(self, n_warm_up_iter, n_main_iter, init_states, **kwargs) +
      +
      +

      Sample Markov chains from given initial states with adaptive warm up.

      +

      One or more Markov chains are sampled, with each chain iteration +consisting of a momentum transition followed by an integration +transition. The chains are split into multiple stages with one or more +adaptive warm up stages followed by the main non-adaptive sampling +stage. During the adaptive stage(s) parameters of the integration +transition such as the integrator step size are adaptively tuned based +on the chain state and/or transition statistics.

      +

      Following the approach of Stan the adaptive +stages are split in to two types - 'fast' adaptation stages which adjust +only transition parameters which can be adapted quickly using local +information (such as the integrator step size) and 'slow' adaptation +stages which addtionally adjust transition parameters which require +more global information (such as the metric matrix representation for +Euclidean metric systems which requires estimates of the (co)variances +of the target distribution). The adapters to be used in both the fast +and slow adaptation stages will be referred to as the fast adapters +and the adapters to use in only the slow adaptation stages the slow +adapters.

      +

      If only fast adapters are specified the adaptive warm up iterations will +form a single fast adaptive stage. If both slow and fast adapters are +specified the adaptive warm up iterations will be split into three +stages:

      +
        +
      1. An initial fast adaptive stage with only fast adapters active.
      2. +
      3. A slow adaptive stage with both slow and fast adapters active.
      4. +
      5. A final adaptive stage with only fast adapters active.
      6. +
      +

      The slow sampling stage (2) is further split in to a sequence of +growing, memoryless windows with the adapter stages reset at the +beginning of each window, and the number of iterations in each window +increasing (by default doubling). The split of the iterations in each of +these stages can be controlled using the keyword arguments +n_init_fast_stage_iter, n_init_slow_window_iter, +n_final_fast_stage_iter and slow_window_multiplier (see descriptions +below).

      +

      In both cases after the initial adaptive warm up stage(s) a subsequent +main sampling stage with no further adaptation is performed. Only in +this main sampling stage are traces of the chain state recorded by +storing the outputs of functions of the sampled chain state after each +iteration.

      +

      The default settings use a single (fast) DualAveragingStepSizeAdapter +adapter instance which adapts the integrator step-size using a +dual-averaging algorithm in a single adaptive stage.

      +

      The chains (including both adaptive and non-adaptive stages) may be run +in parallel across multiple independent processes or sequentially. In +all cases all chains use independent random draws.

      +

      Args

      +
      +
      n_warm_up_iter : int
      +
      Number of adaptive warm up iterations per +chain. Depending on the adapters specified by the +fast_adapters and slow_adapters arguments the warm up +iterations may be split between one or more adaptive stages. +The keyword arguments n_init_fast_stage_iter, +n_init_slow_window_iter, n_final_fast_stage_iter and +slow_window_multiplier can be used to control the split of +the warm up iterations into these different stages - for details +see descriptions of the individual keyword arguments below.
      +
      n_main_iter : int
      +
      Number of iterations (samples to draw) per chain +during main (non-adaptive) sampling stage.
      +
      init_states : Iterable[ChainState] or Iterable[array]
      +
      Initial +chain states. Each state can be either an array specifying the +state position component or a ChainState +instance. If an array is passed or the mom attribute of the +state is not set, a momentum component will be independently +sampled from its conditional distribution. One chain will be +run for each state in the iterable sequence.
      +
      +

      Kwargs

      +
      +
      n_process : int or None
      +
      Number of parallel processes to run chains +over. If n_process=1 then chains will be run sequentially +otherwise a multiprocessing.Pool object will be used to +dynamically assign the chains across multiple processes. If set +to None then the number of processes will be set to the +output of os.cpu_count(). Default is n_process=1.
      +
      trace_funcs : Iterable[Callable[[ChainState], Dict[str, array]]]
      +
      +

      List of functions which compute the variables to be recorded at +each chain iteration during the main non-adaptive sampling +stage, with each trace function being passed the current state +and returning a dictionary of scalar or array values +corresponding to the variable(s) to be stored. The keys in the +returned dictionaries are used to index the trace arrays in the +returned traces dictionary. If a key appears in multiple +dictionaries only the the value corresponding to the last trace +function to return that key will be stored. +Default is to use a +single function which recordes the position component of the +state under the key pos and the Hamiltonian at the state under +the key hamiltonian.

      +
      +
      fast_adapters : Iterable[Adapter]
      +
      List of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the step size during the adaptive +(both fast and slow) stages of the chains. Note that the adapter +updates are applied in the order the adapters appear in the +iterable and so if multiple adapters change the same +parameter(s) the order will matter. Default is to use a single +instance of DualAveragingStepSizeAdapter with +its default parameters.
      +
      slow_adapters : Iterable[Adapter]
      +
      List of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the metric of Euclidean +Hamiltonian systems during the slow adaptive stage of the +chains. Note that the adapter updates are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Default is +to use no slow adapters.
      +
      n_init_slow_window_iter : int
      +
      Number of iterations in the initial +(smallest) window in the slow adaptation stage. Defaults to 25. +If the sum of n_init_slow_window_iter, +n_init_fast_stage_iter and n_final_fast_stage_iter is more +than n_warm_up_iter then n_init_slow_window_iter is set to +approximately 75% of n_warm_up_iter (with a single window +being used in the slow adaptation stage in this case).
      +
      n_init_fast_stage_iter : int
      +
      Number of iterations in the initial +fast adaptation stage. Defaults to 75. If the sum of +n_init_slow_window_iter, n_init_fast_stage_iterandn_final_fast_stage_iteris more thann_warm_up_iterthenn_init_fast_stage_iteris set to approximately 15% ofn_warm_up_iter`.
      +
      n_final_fast_stage_iter : int
      +
      Number of iterations in the final +fast adaptation stage. Defaults to 50. If the sum of +n_init_slow_window_iter, n_init_fast_stage_iter and +n_final_fast_stage_iter is more than n_warm_up_iter then +n_init_fast_stage_iter is set to approximately 10% of +n_warm_up_iter.
      +
      slow_window_multiplier : float
      +
      Multiplier by which to increase the +number of iterations of each subsequent slow adaptation window +by. Defaults to 2 such that each window doubles in size.
      +
      memmap_enabled : bool
      +
      Whether to memory-map arrays used to store +chain data to files on disk to avoid excessive system memory +usage for long chains and/or large chain states. The chain data +is written to .npy files in the directory specified by +memmap_path (or a temporary directory if not provided). These +files persist after the termination of the function so should +be manually deleted when no longer required. Default is for +memory mapping to be disabled.
      +
      memmap_path : str
      +
      Path to directory to write memory-mapped chain +data to. If not provided (the default), a temporary directory +will be created and the chain data written to files there.
      +
      monitor_stats : Iterable[str]
      +
      List of string keys of chain +statistics to monitor mean of over samples computed so far +during sampling by printing as postfix to progress bar. Default +is to print only the mean accept_stat statistic.
      +
      display_progress : bool
      +
      Whether to display a progress bar to +track the completed chain sampling iterations. Default value +is True, i.e. to display progress bar.
      +
      progress_bar_class : BaseProgressBar
      +
      Class or +factory function for progress bar to use to show chain +progress if enabled (display_progress=True). Defaults to +ProgressBar.
      +
      +

      Returns

      +
      +
      final_states : List[ChainState]
      +
      States of chains after final +iteration. May be used to resume sampling a chain by passing as +the initial states to a new sample_chains call.
      +
      traces : Dict[str, List[array]]
      +
      Dictionary of chain trace arrays. +Values in dictionary are list of arrays of variables outputted +by trace functions in trace_funcs with each array in the list +corresponding to a single chain and the leading dimension of +each array corresponding to the iteration (draw) index within +the main non-adaptive sampling stage. The key for each value is +the corresponding key in the dictionary returned by the trace +function which computed the traced value.
      +
      chain_stats : Dict[str, List[array]]
      +
      Dictionary of chain +integration transition statistics. Values in dictionary are +lists of arrays of chain statistic values with each array in the +list corresponding to a single chain and the leading dimension +of each array corresponding to the iteration (draw) index within +the main non-adaptive sampling stage. The key for each value is +a string description of the corresponding integration transition +statistic.
      +
      +
      @@ -3921,8 +6590,8 @@

      Args

      system : System
      Hamiltonian system to be simulated.
      -
      rng : RandomState
      -
      Numpy RandomState random number generator.
      +
      rng : Generator or RandomState
      +
      Numpy random number generator.
      integrator : Integrator
      Symplectic integrator to use to simulate dynamics in integration transition.
      @@ -3956,8 +6625,8 @@

      Args

      behaviour is seen by which the termination criterion fails to detect that the trajectory has expanded past a half-period i.e. has 'U-turned' resulting in trajectories continuing to expand, -potentially up until the max_tree_depth limit is hit. For -more details see the Stan Discourse discussion at kutt.it/yAkIES +potentially up until the max_tree_depth limit is hit. For more +details see this Stan Discourse discussion. If do_extra_subtree_checks is set to True additional termination criterion checks are performed on overlapping subtrees which help to reduce this resonant behaviour at the @@ -3977,7 +6646,7 @@

      Args

      Expand source code -Browse git +Browse git
      class DynamicSliceHMC(HamiltonianMCMC):
           """Dynamic integration time H-MCMC with slice sampling of new state.
      @@ -4009,7 +6678,7 @@ 

      Args

      """ Args: system (mici.systems.System): Hamiltonian system to be simulated. - rng (RandomState): Numpy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. integrator (mici.integrators.Integrator): Symplectic integrator to use to simulate dynamics in integration transition. max_tree_depth (int): Maximum depth to expand trajectory binary @@ -4037,8 +6706,8 @@

      Args

      behaviour is seen by which the termination criterion fails to detect that the trajectory has expanded past a half-period i.e. has 'U-turned' resulting in trajectories continuing to expand, - potentially up until the `max_tree_depth` limit is hit. For - more details see the Stan Discourse discussion at kutt.it/yAkIES + potentially up until the `max_tree_depth` limit is hit. For more + details see [this Stan Discourse discussion](kutt.it/yAkIES). If `do_extra_subtree_checks` is set to `True` additional termination criterion checks are performed on overlapping subtrees which help to reduce this resonant behaviour at the @@ -4091,7 +6760,7 @@

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def max_tree_depth(self):
      @@ -4105,7 +6774,7 @@ 

      Instance variables

      Expand source code -Browse git +Browse git
      @property
       def max_delta_h(self):
      @@ -4117,7 +6786,7 @@ 

      Instance variables

      Methods

      -def sample_chain(self, n_sample, init_state, **kwargs) +def sample_chain(self, n_iter, init_state, **kwargs)

      Sample a Markov chain from a given initial state.

      @@ -4126,8 +6795,8 @@

      Methods

      outputs of functions of the sampled chain state after each iteration.

      Args

      -
      n_sample : int
      -
      Number of samples (iterations) to draw per chain.
      +
      n_iter : int
      +
      Number of iterations (samples to draw) per chain.
      init_state : ChainState or array
      Initial chain state. The state can be either an array specifying the state position @@ -4147,7 +6816,10 @@

      Kwargs

      in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace -function to return that key will be stored.

      +function to return that key will be stored. Default is to use a +single function which recordes the position component of the +state under the key pos and the Hamiltonian at the state +under the key hamiltonian.

      memmap_enabled : bool
      Whether to memory-map arrays used to store @@ -4156,8 +6828,8 @@

      Kwargs

      is written to .npy files in the directory specified by memmap_path (or a temporary directory if not provided). These files persist after the termination of the function so should -be manually deleted when no longer required. Default is to -for memory mapping to be disabled.
      +be manually deleted when no longer required. Default is for +memory mapping to be disabled.
      memmap_path : str
      Path to directory to write memory-mapped chain data to. If not provided, a temporary directory will be created @@ -4166,7 +6838,7 @@

      Kwargs

      List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default -is to print only the mean accept_prob statistic.
      +is to print only the mean accept_stat statistic.
      display_progress : bool
      Whether to display a progress bar to track the completed chain sampling iterations. Default value @@ -4176,6 +6848,17 @@

      Kwargs

      factory function for progress bar to use to show chain progress if enabled (display_progress=True). Defaults to ProgressBar.
      +
      adapters : Iterable[Adapter]
      +
      Sequence of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the step size while sampling a +chain. Note that the adapter updates are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Adaptation +based on the chain state history breaks the Markov property and +so any chain samples while adaptation is active should not be +used in estimates of expectations. Default is to use no +adapters.

      Returns

      @@ -4200,19 +6883,19 @@

      Returns

      -def sample_chains(self, n_sample, init_states, **kwargs) +def sample_chains(self, n_iter, init_states, **kwargs)

      Sample one or more Markov chains from given initial states.

      -

      Performs a specified number of chain iterations (each of consists of a -momentum transition and integration transition), recording the outputs -of functions of the sampled chain state after each iteration. The -chains may be run in parallel across multiple independent processes or -sequentially. In all cases all chains use independent random draws.

      +

      Performs a specified number of chain iterations, each of consisting of a +momentum transition followed by an integration transition, recording the +outputs of functions of the sampled chain state after each iteration. +The chains may be run in parallel across multiple independent processes +or sequentially. In all cases all chains use independent random draws.

      Args

      -
      n_sample : int
      -
      Number of samples (iterations) to draw per chain.
      +
      n_iter : int
      +
      Number of iterations (samples to draw) per chain.
      init_states : Iterable[ChainState] or Iterable[array]
      Initial chain states. Each state can be either an array specifying the @@ -4226,7 +6909,7 @@

      Kwargs

      n_process : int or None
      Number of parallel processes to run chains -over. If set to one then chains will be run sequentially in +over. If n_process=1 then chains will be run sequentially otherwise a multiprocessing.Pool object will be used to dynamically assign the chains across multiple processes. If set to None then the number of processes will be set to the @@ -4240,7 +6923,11 @@

      Kwargs

      in the returned dictionaries are used to index the trace arrays in the returned traces dictionary. If a key appears in multiple dictionaries only the the value corresponding to the last trace -function to return that key will be stored.

      +function to return that key will be stored. +Default is to use a +single function which recordes the position component of the +state under the key pos and the Hamiltonian at the state +under the key hamiltonian.

      memmap_enabled : bool
      Whether to memory-map arrays used to store @@ -4249,17 +6936,17 @@

      Kwargs

      is written to .npy files in the directory specified by memmap_path (or a temporary directory if not provided). These files persist after the termination of the function so should -be manually deleted when no longer required. Default is to -for memory mapping to be disabled.
      +be manually deleted when no longer required. Default is for +memory mapping to be disabled.
      memmap_path : str
      Path to directory to write memory-mapped chain -data to. If not provided, a temporary directory will be created -and the chain data written to files there.
      +data to. If not provided (the default), a temporary directory +will be created and the chain data written to files there.
      monitor_stats : Iterable[str]
      List of string keys of chain statistics to monitor mean of over samples computed so far during sampling by printing as postfix to progress bar. Default -is to print only the mean accept_prob statistic.
      +is to print only the mean accept_stat statistic.
      display_progress : bool
      Whether to display a progress bar to track the completed chain sampling iterations. Default value @@ -4269,6 +6956,17 @@

      Kwargs

      factory function for progress bar to use to show chain progress if enabled (display_progress=True). Defaults to ProgressBar.
      +
      adapters : Iterable[Adapter]
      +
      Sequence of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the step size while sampling a +chain. Note that the adapter updates are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Adaptation +based on the chain state history breaks the Markov property and +so any chain samples while adaptation is active should not be +used in estimates of expectations. Default is to use no +adapters.

      Returns

      @@ -4281,7 +6979,7 @@

      Returns

      Values in dictionary are list of arrays of variables outputted by trace functions in trace_funcs with each array in the list corresponding to a single chain and the leading dimension of -each array corresponding to the sampling (draw) index. The key +each array corresponding to the iteration (draw) index. The key for each value is the corresponding key in the dictionary returned by the trace function which computed the traced value.
      chain_stats : Dict[str, List[array]]
      @@ -4289,11 +6987,207 @@

      Returns

      integration transition statistics. Values in dictionary are lists of arrays of chain statistic values with each array in the list corresponding to a single chain and the leading -dimension of each array corresponding to the sampling (draw) +dimension of each array corresponding to the iteration (draw) index. The key for each value is a string description of the corresponding integration transition statistic.
      +
      +def sample_chains_with_adaptive_warm_up(self, n_warm_up_iter, n_main_iter, init_states, **kwargs) +
      +
      +

      Sample Markov chains from given initial states with adaptive warm up.

      +

      One or more Markov chains are sampled, with each chain iteration +consisting of a momentum transition followed by an integration +transition. The chains are split into multiple stages with one or more +adaptive warm up stages followed by the main non-adaptive sampling +stage. During the adaptive stage(s) parameters of the integration +transition such as the integrator step size are adaptively tuned based +on the chain state and/or transition statistics.

      +

      Following the approach of Stan the adaptive +stages are split in to two types - 'fast' adaptation stages which adjust +only transition parameters which can be adapted quickly using local +information (such as the integrator step size) and 'slow' adaptation +stages which addtionally adjust transition parameters which require +more global information (such as the metric matrix representation for +Euclidean metric systems which requires estimates of the (co)variances +of the target distribution). The adapters to be used in both the fast +and slow adaptation stages will be referred to as the fast adapters +and the adapters to use in only the slow adaptation stages the slow +adapters.

      +

      If only fast adapters are specified the adaptive warm up iterations will +form a single fast adaptive stage. If both slow and fast adapters are +specified the adaptive warm up iterations will be split into three +stages:

      +
        +
      1. An initial fast adaptive stage with only fast adapters active.
      2. +
      3. A slow adaptive stage with both slow and fast adapters active.
      4. +
      5. A final adaptive stage with only fast adapters active.
      6. +
      +

      The slow sampling stage (2) is further split in to a sequence of +growing, memoryless windows with the adapter stages reset at the +beginning of each window, and the number of iterations in each window +increasing (by default doubling). The split of the iterations in each of +these stages can be controlled using the keyword arguments +n_init_fast_stage_iter, n_init_slow_window_iter, +n_final_fast_stage_iter and slow_window_multiplier (see descriptions +below).

      +

      In both cases after the initial adaptive warm up stage(s) a subsequent +main sampling stage with no further adaptation is performed. Only in +this main sampling stage are traces of the chain state recorded by +storing the outputs of functions of the sampled chain state after each +iteration.

      +

      The default settings use a single (fast) DualAveragingStepSizeAdapter +adapter instance which adapts the integrator step-size using a +dual-averaging algorithm in a single adaptive stage.

      +

      The chains (including both adaptive and non-adaptive stages) may be run +in parallel across multiple independent processes or sequentially. In +all cases all chains use independent random draws.

      +

      Args

      +
      +
      n_warm_up_iter : int
      +
      Number of adaptive warm up iterations per +chain. Depending on the adapters specified by the +fast_adapters and slow_adapters arguments the warm up +iterations may be split between one or more adaptive stages. +The keyword arguments n_init_fast_stage_iter, +n_init_slow_window_iter, n_final_fast_stage_iter and +slow_window_multiplier can be used to control the split of +the warm up iterations into these different stages - for details +see descriptions of the individual keyword arguments below.
      +
      n_main_iter : int
      +
      Number of iterations (samples to draw) per chain +during main (non-adaptive) sampling stage.
      +
      init_states : Iterable[ChainState] or Iterable[array]
      +
      Initial +chain states. Each state can be either an array specifying the +state position component or a ChainState +instance. If an array is passed or the mom attribute of the +state is not set, a momentum component will be independently +sampled from its conditional distribution. One chain will be +run for each state in the iterable sequence.
      +
      +

      Kwargs

      +
      +
      n_process : int or None
      +
      Number of parallel processes to run chains +over. If n_process=1 then chains will be run sequentially +otherwise a multiprocessing.Pool object will be used to +dynamically assign the chains across multiple processes. If set +to None then the number of processes will be set to the +output of os.cpu_count(). Default is n_process=1.
      +
      trace_funcs : Iterable[Callable[[ChainState], Dict[str, array]]]
      +
      +

      List of functions which compute the variables to be recorded at +each chain iteration during the main non-adaptive sampling +stage, with each trace function being passed the current state +and returning a dictionary of scalar or array values +corresponding to the variable(s) to be stored. The keys in the +returned dictionaries are used to index the trace arrays in the +returned traces dictionary. If a key appears in multiple +dictionaries only the the value corresponding to the last trace +function to return that key will be stored. +Default is to use a +single function which recordes the position component of the +state under the key pos and the Hamiltonian at the state under +the key hamiltonian.

      +
      +
      fast_adapters : Iterable[Adapter]
      +
      List of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the step size during the adaptive +(both fast and slow) stages of the chains. Note that the adapter +updates are applied in the order the adapters appear in the +iterable and so if multiple adapters change the same +parameter(s) the order will matter. Default is to use a single +instance of DualAveragingStepSizeAdapter with +its default parameters.
      +
      slow_adapters : Iterable[Adapter]
      +
      List of Adapter +instances to use to adaptatively set parameters of the +integration transition such as the metric of Euclidean +Hamiltonian systems during the slow adaptive stage of the +chains. Note that the adapter updates are applied in the order +the adapters appear in the iterable and so if multiple adapters +change the same parameter(s) the order will matter. Default is +to use no slow adapters.
      +
      n_init_slow_window_iter : int
      +
      Number of iterations in the initial +(smallest) window in the slow adaptation stage. Defaults to 25. +If the sum of n_init_slow_window_iter, +n_init_fast_stage_iter and n_final_fast_stage_iter is more +than n_warm_up_iter then n_init_slow_window_iter is set to +approximately 75% of n_warm_up_iter (with a single window +being used in the slow adaptation stage in this case).
      +
      n_init_fast_stage_iter : int
      +
      Number of iterations in the initial +fast adaptation stage. Defaults to 75. If the sum of +n_init_slow_window_iter, n_init_fast_stage_iterandn_final_fast_stage_iteris more thann_warm_up_iterthenn_init_fast_stage_iteris set to approximately 15% ofn_warm_up_iter`.
      +
      n_final_fast_stage_iter : int
      +
      Number of iterations in the final +fast adaptation stage. Defaults to 50. If the sum of +n_init_slow_window_iter, n_init_fast_stage_iter and +n_final_fast_stage_iter is more than n_warm_up_iter then +n_init_fast_stage_iter is set to approximately 10% of +n_warm_up_iter.
      +
      slow_window_multiplier : float
      +
      Multiplier by which to increase the +number of iterations of each subsequent slow adaptation window +by. Defaults to 2 such that each window doubles in size.
      +
      memmap_enabled : bool
      +
      Whether to memory-map arrays used to store +chain data to files on disk to avoid excessive system memory +usage for long chains and/or large chain states. The chain data +is written to .npy files in the directory specified by +memmap_path (or a temporary directory if not provided). These +files persist after the termination of the function so should +be manually deleted when no longer required. Default is for +memory mapping to be disabled.
      +
      memmap_path : str
      +
      Path to directory to write memory-mapped chain +data to. If not provided (the default), a temporary directory +will be created and the chain data written to files there.
      +
      monitor_stats : Iterable[str]
      +
      List of string keys of chain +statistics to monitor mean of over samples computed so far +during sampling by printing as postfix to progress bar. Default +is to print only the mean accept_stat statistic.
      +
      display_progress : bool
      +
      Whether to display a progress bar to +track the completed chain sampling iterations. Default value +is True, i.e. to display progress bar.
      +
      progress_bar_class : BaseProgressBar
      +
      Class or +factory function for progress bar to use to show chain +progress if enabled (display_progress=True). Defaults to +ProgressBar.
      +
      +

      Returns

      +
      +
      final_states : List[ChainState]
      +
      States of chains after final +iteration. May be used to resume sampling a chain by passing as +the initial states to a new sample_chains call.
      +
      traces : Dict[str, List[array]]
      +
      Dictionary of chain trace arrays. +Values in dictionary are list of arrays of variables outputted +by trace functions in trace_funcs with each array in the list +corresponding to a single chain and the leading dimension of +each array corresponding to the iteration (draw) index within +the main non-adaptive sampling stage. The key for each value is +the corresponding key in the dictionary returned by the trace +function which computed the traced value.
      +
      chain_stats : Dict[str, List[array]]
      +
      Dictionary of chain +integration transition statistics. Values in dictionary are +lists of arrays of chain statistic values with each array in the +list corresponding to a single chain and the leading dimension +of each array corresponding to the iteration (draw) index within +the main non-adaptive sampling stage. The key for each value is +a string description of the corresponding integration transition +statistic.
      +
      +
      @@ -4302,7 +7196,7 @@

      Returns

      diff --git a/docs/docs/solvers.html b/docs/docs/solvers.html index 668918d..3a2b366 100644 --- a/docs/docs/solvers.html +++ b/docs/docs/solvers.html @@ -3,14 +3,14 @@ - + mici.solvers API documentation - + @@ -45,18 +45,18 @@
      -

      Package mici.solvers

      +

      Module mici.solvers

      Solvers for non-linear systems of equations for implicit integrators.

      Expand source code -Browse git +Browse git
      """Solvers for non-linear systems of equations for implicit integrators."""
       
      -from mici.errors import ConvergenceError
      +from mici.errors import ConvergenceError, LinAlgError
       import numpy as np
       
       
      @@ -105,10 +105,10 @@ 

      Package mici.solvers

      if error < convergence_tol: return x x0 = x - except ValueError as e: - # Make robust to inf/nan values in intermediate linear algebra ops + except (ValueError, LinAlgError) as e: + # Make robust to errors in intermediate linear algebra ops raise ConvergenceError( - f'ValueError at iteration {i} of fixed point solver ({e}).') + f'{type(e)} at iteration {i} of fixed point solver ({e}).') raise ConvergenceError( f'Fixed point iteration did not converge. Last error={error:.1e}.') @@ -161,10 +161,10 @@

      Package mici.solvers

      if error < convergence_tol: return x x0 = x - except ValueError as e: - # Make robust to inf/nan values in intermediate linear algebra ops + except (ValueError, LinAlgError) as e: + # Make robust to errors in intermediate linear algebra ops raise ConvergenceError( - f'ValueError at iteration {i} of fixed point solver ({e}).') + f'{type(e)} at iteration {i} of fixed point solver ({e}).') raise ConvergenceError( f'Fixed point iteration did not converge. Last error={error:.1e}.') @@ -249,10 +249,10 @@

      Package mici.solvers

      return state mu += delta_mu state.pos -= delta_pos - except ValueError as e: - # Make robust to inf/nan values in intermediate linear algebra ops + except (ValueError, LinAlgError) as e: + # Make robust to errors in intermediate linear algebra ops raise ConvergenceError( - f'ValueError at iteration {i} of Quasi-Newton solver ({e}).') + f'{type(e)} at iteration {i} of quasi-Newton solver ({e}).') raise ConvergenceError( f'Quasi-Newton solver did not converge with {max_iters} iterations. ' f'Last |constr|={error:.1e}, |delta_pos|={norm(delta_pos)}.') @@ -339,10 +339,10 @@

      Package mici.solvers

      return state mu += delta_mu state.pos -= delta_pos - except ValueError as e: - # Make robust to inf/nan values in intermediate linear algebra ops + except (ValueError, LinAlgError) as e: + # Make robust to errors in intermediate linear algebra ops raise ConvergenceError( - f'ValueError at iteration {i} of Newton solver ({e}).') + f'{type(e)} at iteration {i} of Newton solver ({e}).') raise ConvergenceError( f'Newton solver did not converge in {max_iters} iterations. ' f'Last |constr|={error:.1e}, |delta_pos|={norm(delta_pos)}.')
      @@ -363,7 +363,7 @@

      Functions

      Expand source code -Browse git +Browse git
      def euclidean_norm(vct):
           """Calculate the Euclidean (L-2) norm of a vector."""
      @@ -378,7 +378,7 @@ 

      Functions

      Expand source code -Browse git +Browse git
      def maximum_norm(vct):
           """Calculate the maximum (L-infinity) norm of a vector."""
      @@ -420,7 +420,7 @@ 

      Raises

      Expand source code -Browse git +Browse git
      def solve_fixed_point_direct(
               func, x0, convergence_tol=1e-9, divergence_tol=1e10, max_iters=100,
      @@ -457,10 +457,10 @@ 

      Raises

      if error < convergence_tol: return x x0 = x - except ValueError as e: - # Make robust to inf/nan values in intermediate linear algebra ops + except (ValueError, LinAlgError) as e: + # Make robust to errors in intermediate linear algebra ops raise ConvergenceError( - f'ValueError at iteration {i} of fixed point solver ({e}).') + f'{type(e)} at iteration {i} of fixed point solver ({e}).') raise ConvergenceError( f'Fixed point iteration did not converge. Last error={error:.1e}.')
      @@ -505,7 +505,7 @@

      Raises

      Expand source code -Browse git +Browse git
      def solve_fixed_point_steffensen(
               func, x0, convergence_tol=1e-9, divergence_tol=1e10, max_iters=100,
      @@ -555,10 +555,10 @@ 

      Raises

      if error < convergence_tol: return x x0 = x - except ValueError as e: - # Make robust to inf/nan values in intermediate linear algebra ops + except (ValueError, LinAlgError) as e: + # Make robust to errors in intermediate linear algebra ops raise ConvergenceError( - f'ValueError at iteration {i} of fixed point solver ({e}).') + f'{type(e)} at iteration {i} of fixed point solver ({e}).') raise ConvergenceError( f'Fixed point iteration did not converge. Last error={error:.1e}.')
      @@ -628,7 +628,7 @@

      Raises

      Expand source code -Browse git +Browse git
      def solve_projection_onto_manifold_quasi_newton(
               state, state_prev, dt, system, constraint_tol=1e-9, position_tol=1e-8,
      @@ -710,10 +710,10 @@ 

      Raises

      return state mu += delta_mu state.pos -= delta_pos - except ValueError as e: - # Make robust to inf/nan values in intermediate linear algebra ops + except (ValueError, LinAlgError) as e: + # Make robust to errors in intermediate linear algebra ops raise ConvergenceError( - f'ValueError at iteration {i} of Quasi-Newton solver ({e}).') + f'{type(e)} at iteration {i} of quasi-Newton solver ({e}).') raise ConvergenceError( f'Quasi-Newton solver did not converge with {max_iters} iterations. ' f'Last |constr|={error:.1e}, |delta_pos|={norm(delta_pos)}.')
      @@ -784,7 +784,7 @@

      Raises

      Expand source code -Browse git +Browse git
      def solve_projection_onto_manifold_newton(
               state, state_prev, dt, system, constraint_tol=1e-9, position_tol=1e-8,
      @@ -867,10 +867,10 @@ 

      Raises

      return state mu += delta_mu state.pos -= delta_pos - except ValueError as e: - # Make robust to inf/nan values in intermediate linear algebra ops + except (ValueError, LinAlgError) as e: + # Make robust to errors in intermediate linear algebra ops raise ConvergenceError( - f'ValueError at iteration {i} of Newton solver ({e}).') + f'{type(e)} at iteration {i} of Newton solver ({e}).') raise ConvergenceError( f'Newton solver did not converge in {max_iters} iterations. ' f'Last |constr|={error:.1e}, |delta_pos|={norm(delta_pos)}.')
      @@ -884,7 +884,7 @@

      Raises

      diff --git a/docs/docs/states.html b/docs/docs/states.html index d274f5c..60785a5 100644 --- a/docs/docs/states.html +++ b/docs/docs/states.html @@ -3,14 +3,14 @@ - + mici.states API documentation - + @@ -40,7 +40,7 @@
    2. Classes

      • -

        ChainState

        +ChainState @@ -51,19 +51,20 @@

        Chain
        -

        Package mici.states

        +

        Module mici.states

        Objects for recording state of a Markov chain.

        Expand source code -Browse git +Browse git
        """Objects for recording state of a Markov chain."""
         
         import copy
         from functools import wraps
        +from mici.errors import ReadOnlyStateError
         
         
         def cache_in_state(*depends_on):
        @@ -155,7 +156,7 @@ 

        Package mici.states

        """ def __init__(self, _dependencies=None, _cache=None, _call_counts=None, - **variables): + _read_only=False, **variables): """Create a new `ChainState` instance. Any keyword arguments passed to the constructor will be used to set @@ -166,20 +167,22 @@

        Package mici.states

        will return a `ChainState` instance `state` with variable attributes `state.pos`, `state.mom` and `state.dir` with initial values set to `pos_val`, `mom_val` and `dir_val` respectively. The keyword arguments - `_dependencies`, `_cache` and `_call_counts` are reserved respectively - for the dependency set, cache dictionary and call count dictionary, and - cannot be used as state variable names. + `_dependencies`, `_cache`, `_call_counts` and `_read_only` are reserved + respectively for the dependency set, cache dictionary, call count + dictionary and a flag to make the state read-only and cannot be used as + state variable names. """ - # Set _variables attribute by directly writing to __dict__ to ensure - # set before any cally to __setattr__ + # Set attributes by directly writing to __dict__ to ensure set before + # any call to __setattr__ self.__dict__['_variables'] = variables if _dependencies is None: _dependencies = {name: set() for name in variables} - self._dependencies = _dependencies + self.__dict__['_dependencies'] = _dependencies if _cache is None: _cache = {} - self._cache = _cache - self._call_counts = _call_counts + self.__dict__['_cache'] = _cache + self.__dict__['_call_counts'] = _call_counts + self.__dict__['_read_only'] = _read_only def __getattr__(self, name): if name in self._variables: @@ -189,6 +192,8 @@

        Package mici.states

        f"'{type(self).__name__}' object has no attribute '{name}'") def __setattr__(self, name, value): + if self._read_only: + raise ReadOnlyStateError('ChainState instance is read-only.') if name in self._variables: self._variables[name] = value # clear any dependent cached values @@ -200,16 +205,20 @@

        Package mici.states

        def __contains__(self, name): return name in self._variables - def copy(self): + def copy(self, read_only=False): """Create a deep copy of the state object. + Args: + read_only (bool): Whether the state copy should be read-only. + Returns: - state_copy (ChainState): A copy of the state object which can be - updated without affecting the original object's variables. + state_copy (ChainState): A copy of the state object with variable + attributes that are independent copies of the original state + object's variables. """ return type(self)( _dependencies=self._dependencies, _cache=self._cache.copy(), - _call_counts=self._call_counts, + _call_counts=self._call_counts, _read_only=read_only, **{name: copy.copy(val) for name, val in self._variables.items()}) def __str__(self): @@ -229,13 +238,15 @@

        Package mici.states

        # Don't pickle callable cached 'variables' such as derivative # functions 'cache': {k: v for k, v in self._cache.items() if not callable(v)}, - 'call_counts': self._call_counts} + 'call_counts': self._call_counts, + 'read_only': self._read_only} def __setstate__(self, state): self.__dict__['_variables'] = state['variables'] - self._dependencies = state['dependencies'] - self._cache = state['cache'] - self._call_counts = state['call_counts']
        + self.__dict__['_dependencies'] = state['dependencies'] + self.__dict__['_cache'] = state['cache'] + self.__dict__['_call_counts'] = state['call_counts'] + self.__dict__['_read_only'] = state['read_only']

    3. @@ -263,7 +274,7 @@

      Args

      Expand source code -Browse git +Browse git
      def cache_in_state(*depends_on):
           """Decorator to memoize / cache output of a function of state variable(s).
      @@ -325,7 +336,7 @@ 

      Args

      Expand source code -Browse git +Browse git
      def multi_cache_in_state(depends_on, variables, primary_index=0):
           """Decorator to cache multiple outputs of a function of state variable(s).
      @@ -398,13 +409,14 @@ 

      Classes

      will return a ChainState instance state with variable attributes state.pos, state.mom and state.dir with initial values set to pos_val, mom_val and dir_val respectively. The keyword arguments -_dependencies, _cache and _call_counts are reserved respectively -for the dependency set, cache dictionary and call count dictionary, and -cannot be used as state variable names.

      +_dependencies, _cache, _call_counts and _read_only are reserved +respectively for the dependency set, cache dictionary, call count +dictionary and a flag to make the state read-only and cannot be used as +state variable names.

      Expand source code -Browse git +Browse git
      class ChainState(object):
           """Markov chain state.
      @@ -415,7 +427,7 @@ 

      Classes

      """ def __init__(self, _dependencies=None, _cache=None, _call_counts=None, - **variables): + _read_only=False, **variables): """Create a new `ChainState` instance. Any keyword arguments passed to the constructor will be used to set @@ -426,20 +438,22 @@

      Classes

      will return a `ChainState` instance `state` with variable attributes `state.pos`, `state.mom` and `state.dir` with initial values set to `pos_val`, `mom_val` and `dir_val` respectively. The keyword arguments - `_dependencies`, `_cache` and `_call_counts` are reserved respectively - for the dependency set, cache dictionary and call count dictionary, and - cannot be used as state variable names. + `_dependencies`, `_cache`, `_call_counts` and `_read_only` are reserved + respectively for the dependency set, cache dictionary, call count + dictionary and a flag to make the state read-only and cannot be used as + state variable names. """ - # Set _variables attribute by directly writing to __dict__ to ensure - # set before any cally to __setattr__ + # Set attributes by directly writing to __dict__ to ensure set before + # any call to __setattr__ self.__dict__['_variables'] = variables if _dependencies is None: _dependencies = {name: set() for name in variables} - self._dependencies = _dependencies + self.__dict__['_dependencies'] = _dependencies if _cache is None: _cache = {} - self._cache = _cache - self._call_counts = _call_counts + self.__dict__['_cache'] = _cache + self.__dict__['_call_counts'] = _call_counts + self.__dict__['_read_only'] = _read_only def __getattr__(self, name): if name in self._variables: @@ -449,6 +463,8 @@

      Classes

      f"'{type(self).__name__}' object has no attribute '{name}'") def __setattr__(self, name, value): + if self._read_only: + raise ReadOnlyStateError('ChainState instance is read-only.') if name in self._variables: self._variables[name] = value # clear any dependent cached values @@ -460,16 +476,20 @@

      Classes

      def __contains__(self, name): return name in self._variables - def copy(self): + def copy(self, read_only=False): """Create a deep copy of the state object. + Args: + read_only (bool): Whether the state copy should be read-only. + Returns: - state_copy (ChainState): A copy of the state object which can be - updated without affecting the original object's variables. + state_copy (ChainState): A copy of the state object with variable + attributes that are independent copies of the original state + object's variables. """ return type(self)( _dependencies=self._dependencies, _cache=self._cache.copy(), - _call_counts=self._call_counts, + _call_counts=self._call_counts, _read_only=read_only, **{name: copy.copy(val) for name, val in self._variables.items()}) def __str__(self): @@ -489,42 +509,54 @@

      Classes

      # Don't pickle callable cached 'variables' such as derivative # functions 'cache': {k: v for k, v in self._cache.items() if not callable(v)}, - 'call_counts': self._call_counts} + 'call_counts': self._call_counts, + 'read_only': self._read_only} def __setstate__(self, state): self.__dict__['_variables'] = state['variables'] - self._dependencies = state['dependencies'] - self._cache = state['cache'] - self._call_counts = state['call_counts']
      + self.__dict__['_dependencies'] = state['dependencies'] + self.__dict__['_cache'] = state['cache'] + self.__dict__['_call_counts'] = state['call_counts'] + self.__dict__['_read_only'] = state['read_only']

      Methods

      -def copy(self) +def copy(self, read_only=False)

      Create a deep copy of the state object.

      +

      Args

      +
      +
      read_only : bool
      +
      Whether the state copy should be read-only.
      +

      Returns

      state_copy : ChainState
      -
      A copy of the state object which can be -updated without affecting the original object's variables.
      +
      A copy of the state object with variable +attributes that are independent copies of the original state +object's variables.
      Expand source code -Browse git +Browse git -
      def copy(self):
      +
      def copy(self, read_only=False):
           """Create a deep copy of the state object.
       
      +    Args:
      +        read_only (bool): Whether the state copy should be read-only.
      +
           Returns:
      -        state_copy (ChainState): A copy of the state object which can be
      -            updated without affecting the original object's variables.
      +        state_copy (ChainState): A copy of the state object with variable
      +            attributes that are independent copies of the original state
      +            object's variables.
           """
           return type(self)(
               _dependencies=self._dependencies, _cache=self._cache.copy(),
      -        _call_counts=self._call_counts,
      +        _call_counts=self._call_counts, _read_only=read_only,
               **{name: copy.copy(val) for name, val in self._variables.items()})
      @@ -536,7 +568,7 @@

      Returns

      diff --git a/docs/docs/systems.html b/docs/docs/systems.html index b974105..7cbc7ff 100644 --- a/docs/docs/systems.html +++ b/docs/docs/systems.html @@ -3,14 +3,14 @@ - + mici.systems API documentation - + @@ -34,7 +34,11 @@
    4. Classes

    5. @@ -288,14 +348,14 @@

      -

      Package mici.systems

      +

      Module mici.systems

      Hamiltonian systems encapsulating energy functions and their derivatives.

      Expand source code -Browse git +Browse git
      """Hamiltonian systems encapsulating energy functions and their derivatives."""
       
      @@ -307,7 +367,7 @@ 

      Package mici.systems

      IdentityMatrix, PositiveScaledIdentityMatrix, PositiveDiagonalMatrix, DenseSquareMatrix, TriangularFactoredPositiveDefiniteMatrix, DenseDefiniteMatrix, DensePositiveDefiniteMatrix, DenseSymmetricMatrix, - EigendecomposedSymmetricMatrix, SoftAbsRegularisedPositiveDefiniteMatrix) + EigendecomposedSymmetricMatrix, SoftAbsRegularizedPositiveDefiniteMatrix) from mici.autodiff import autodiff_fallback @@ -326,7 +386,7 @@

      Package mici.systems

      simulable. By default \(h_1\) is assumed to correspond to the negative logarithm of an - unnormalised density on the position variables with respect to the Lebesgue + unnormalized density on the position variables with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. """ @@ -336,7 +396,7 @@

      Package mici.systems

      Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -358,7 +418,7 @@

      Package mici.systems

      @cache_in_state('pos') def neg_log_dens(self, state): - """Negative logarithm of unnormalised density of target distribution. + """Negative logarithm of unnormalized density of target distribution. Args: state (mici.states.ChainState): State to compute value at. @@ -503,7 +563,7 @@

      Package mici.systems

      \[ h_1(q) = \ell(q) \] - where \(\ell(q)\) is the negative log (unnormalised) density of + where \(\ell(q)\) is the negative log (unnormalized) density of the target distribution with respect to the Lebesgue measure. """ @@ -512,7 +572,7 @@

      Package mici.systems

      Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -556,7 +616,7 @@

      Package mici.systems

      @cache_in_state('mom') def h2(self, state): - return 0.5 * state.mom @ (self.metric.inv @ state.mom) + return 0.5 * state.mom @ self.dh2_dmom(state) @cache_in_state('mom') def dh2_dmom(self, state): @@ -602,7 +662,7 @@

      Package mici.systems

      marginal distribution with covariance specified by \(M\). Additionally the target distribution on the position variables is assumed - to be defined by an unnormalised density with respect to the standard + to be defined by an unnormalized density with respect to the standard Gaussian measure on the position space (with identity covariance and zero mean), with the Hamiltonian component \(h_1\) corresponding to the negative logarithm of this density rather than the density with respect to the @@ -611,7 +671,7 @@

      Package mici.systems

      \[ h_1(q) = \ell(q) - \frac{1}{2} q^T q \] where \(q\) is the position and \(\ell(q)\) is the negative log - (unnormalised) density of the target distribution with respect to the + (unnormalized) density of the target distribution with respect to the Lebesgue measure at \(q\). The Hamiltonian component function \(h_2\) is then assumed to have the form @@ -633,7 +693,7 @@

      Package mici.systems

      Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the standard Gaussian measure on the position space, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate @@ -720,7 +780,7 @@

      Package mici.systems

      co-tangent space (tangent space) to the manifold. The target distribution is either assumed to be directly specified with - unnormalised density \(\exp(-\ell(q))\) with respect to the Hausdorff + unnormalized density \(\exp(-\ell(q))\) with respect to the Hausdorff measure on the manifold (under the metric induced from the ambient metric) with in this case the \(h_1\) Hamiltonian component then simply @@ -763,10 +823,10 @@

      Package mici.systems

      Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the constrained position + unnormalized probability density on the constrained position space with respect to the Hausdorff measure on the constraint manifold (if `dens_wrt_hausdorff == True`) or alternatively the - negative logarithm of an unnormalised probability density on + negative logarithm of an unnormalized probability density on the unconstrained (ambient) position space with respect to the Lebesgue measure. In the former case the target distribution it is wished to draw approximate samples from is assumed to be @@ -999,10 +1059,10 @@

      Package mici.systems

      Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the constrained position + unnormalized probability density on the constrained position space with respect to the Hausdorff measure on the constraint manifold (if `dens_wrt_hausdorff == True`) or alternatively the - negative logarithm of an unnormalised probability density on + negative logarithm of an unnormalized probability density on the unconstrained (ambient) position space with respect to the Lebesgue measure. In the former case the target distribution it is wished to draw approximate samples from is assumed to be @@ -1154,7 +1214,7 @@

      Package mici.systems

      Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the unconstrained (ambient) + unnormalized probability density on the unconstrained (ambient) position space with respect to the standard Gaussian measure. The density function is taken to specify a prior distribution on the ambient space with the target distribution then @@ -1263,7 +1323,7 @@

      Package mici.systems

      r"""Riemannian Hamiltonian system with a position-dependent metric. This class allows for metric matrix representations of any generic type. - In most cases a specialised subclass such as `DenseRiemannianMetricSystem`, + In most cases a specialized subclass such as `DenseRiemannianMetricSystem`, `CholeskyFactoredRiemannianMetricSystem`, `DiagonalRiemannianMetricSystem`, `ScalarRiemannianMetricSystem` or `SoftAbsRiemannianMetricSystem` will provide a simpler method of constructng a system with a metric matrix @@ -1279,7 +1339,7 @@

      Package mici.systems

      \[ h_1(q) = \ell(q) + \frac{1}{2}\log\left|M(q)\right| \] - where \(\ell(q)\) is the negative log (unnormalised) density of the target + where \(\ell(q)\) is the negative log (unnormalized) density of the target distribution with respect to the Lebesgue measure at \(q\). The \(h_2\) Hamiltonian component is @@ -1305,7 +1365,7 @@

      Package mici.systems

      Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -1483,7 +1543,7 @@

      Package mici.systems

      Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -1535,7 +1595,7 @@

      Package mici.systems

      @cache_in_state('pos') def metric(self, state): return self._metric_matrix_class( - self.metric_func(state), size=pos.shape[0]) + self.metric_func(state), size=state.pos.shape[0]) class DiagonalRiemannianMetricSystem(RiemannianMetricSystem): @@ -1557,7 +1617,7 @@

      Package mici.systems

      Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -1625,7 +1685,7 @@

      Package mici.systems

      Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -1694,7 +1754,7 @@

      Package mici.systems

      Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -1753,7 +1813,7 @@

      Package mici.systems

      with `M = metric_func(q)` then the metric matrix representation. Hamiltonian system with a position dependent metric matrix representation - which is specified to be an eigenvalue-regularised transformation of the + which is specified to be an eigenvalue-regularized transformation of the Hessian of the negative log density function (the symmetric matrix of second derivatives the negative log density function with respect to the position array components. Specifically if `hess_neg_log_dens` is a @@ -1791,7 +1851,7 @@

      Package mici.systems

      Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -1845,7 +1905,7 @@

      Package mici.systems

      construct a function which calculates the MTP (and Hesisan and gradient and value) of `neg_log_dens` automatically. softabs_coeff (float): Positive regularisation coefficient for - smooth approximation to absolute value used to regularise + smooth approximation to absolute value used to regularize Hessian eigenvalues in metric matrix representation. As the value tends to infinity the approximation becomes increasingly close to the absolute function. @@ -1857,7 +1917,7 @@

      Package mici.systems

      mtp_neg_log_dens, neg_log_dens, 'mtp_hessian_grad_and_value', 'mtp_neg_log_dens') super().__init__(neg_log_dens, - SoftAbsRegularisedPositiveDefiniteMatrix, + SoftAbsRegularizedPositiveDefiniteMatrix, self._hess_neg_log_dens, self._mtp_neg_log_dens, grad_neg_log_dens, metric_kwargs={'softabs_coeff': softabs_coeff}) @@ -1937,7 +1997,7 @@

      Classes

      h_2 the corresponding exact Hamiltonian flow may or may not be simulable.

      By default h_1 is assumed to correspond to the negative logarithm of an -unnormalised density on the position variables with respect to the Lebesgue +unnormalized density on the position variables with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from.

      Args

      @@ -1945,7 +2005,7 @@

      Args

      neg_log_dens : Callable[[array], float]
      Function which given a position array returns the negative logarithm of an -unnormalised probability density on the position space with +unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from.
      @@ -1965,7 +2025,7 @@

      Args

      Expand source code -Browse git +Browse git
      class System(ABC):
           r"""Base class for Hamiltonian systems.
      @@ -1982,7 +2042,7 @@ 

      Args

      simulable. By default \(h_1\) is assumed to correspond to the negative logarithm of an - unnormalised density on the position variables with respect to the Lebesgue + unnormalized density on the position variables with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. """ @@ -1992,7 +2052,7 @@

      Args

      Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -2014,7 +2074,7 @@

      Args

      @cache_in_state('pos') def neg_log_dens(self, state): - """Negative logarithm of unnormalised density of target distribution. + """Negative logarithm of unnormalized density of target distribution. Args: state (mici.states.ChainState): State to compute value at. @@ -2156,7 +2216,7 @@

      Methods

      def neg_log_dens(self, state)

    -

    Negative logarithm of unnormalised density of target distribution.

    +

    Negative logarithm of unnormalized density of target distribution.

    Args

    state : ChainState
    @@ -2170,11 +2230,11 @@

    Returns

    Expand source code -Browse git +Browse git
    @cache_in_state('pos')
     def neg_log_dens(self, state):
    -    """Negative logarithm of unnormalised density of target distribution.
    +    """Negative logarithm of unnormalized density of target distribution.
     
         Args:
             state (mici.states.ChainState): State to compute value at.
    @@ -2204,7 +2264,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    @multi_cache_in_state(['pos'], ['grad_neg_log_dens', 'neg_log_dens'])
     def grad_neg_log_dens(self, state):
    @@ -2238,7 +2298,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def h1(self, state):
         """Hamiltonian component depending only on position.
    @@ -2270,7 +2330,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def dh1_dpos(self, state):
         """Derivative of `h1` Hamiltonian component with respect to position.
    @@ -2300,7 +2360,7 @@ 

    Args

    Expand source code -Browse git +Browse git
    def h1_flow(self, state, dt):
         """Apply exact flow map corresponding to `h1` Hamiltonian component.
    @@ -2332,7 +2392,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    @abstractmethod
     def h2(self, state):
    @@ -2364,7 +2424,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    @abstractmethod
     def dh2_dmom(self, state):
    @@ -2396,7 +2456,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def h(self, state):
         """Hamiltonian function for system.
    @@ -2428,7 +2488,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def dh_dpos(self, state):
         """Derivative of Hamiltonian with respect to position.
    @@ -2463,7 +2523,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def dh_dmom(self, state):
         """Derivative of Hamiltonian with respect to momentum.
    @@ -2496,7 +2556,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    @abstractmethod
     def sample_momentum(self, state, rng):
    @@ -2529,14 +2589,14 @@ 

    Returns

    where q and p are the position and momentum variables respectively.

    The h_1 Hamiltonian component function is

    h_1(q) = \ell(q)

    -

    where \ell(q) is the negative log (unnormalised) density of +

    where \ell(q) is the negative log (unnormalized) density of the target distribution with respect to the Lebesgue measure.

    Args

    neg_log_dens : Callable[[array], float]
    Function which given a position array returns the negative logarithm of an -unnormalised probability density on the position space with +unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from.
    @@ -2569,7 +2629,7 @@

    Args

    Expand source code -Browse git +Browse git
    class EuclideanMetricSystem(System):
         r"""Hamiltonian system with a Euclidean metric on the position space.
    @@ -2588,7 +2648,7 @@ 

    Args

    \[ h_1(q) = \ell(q) \] - where \(\ell(q)\) is the negative log (unnormalised) density of + where \(\ell(q)\) is the negative log (unnormalized) density of the target distribution with respect to the Lebesgue measure. """ @@ -2597,7 +2657,7 @@

    Args

    Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -2641,7 +2701,7 @@

    Args

    @cache_in_state('mom') def h2(self, state): - return 0.5 * state.mom @ (self.metric.inv @ state.mom) + return 0.5 * state.mom @ self.dh2_dmom(state) @cache_in_state('mom') def dh2_dmom(self, state): @@ -2707,11 +2767,11 @@

    Returns

    Expand source code -Browse git +Browse git
    @cache_in_state('mom')
     def h2(self, state):
    -    return 0.5 * state.mom @ (self.metric.inv @ state.mom)
    + return 0.5 * state.mom @ self.dh2_dmom(state)
    @@ -2732,7 +2792,7 @@

    Returns

    Expand source code -Browse git +Browse git
    @cache_in_state('mom')
     def dh2_dmom(self, state):
    @@ -2755,7 +2815,7 @@ 

    Args

    Expand source code -Browse git +Browse git
    def h2_flow(self, state, dt):
         """Apply exact flow map corresponding to `h2` Hamiltonian component.
    @@ -2793,7 +2853,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def dh2_flow_dmom(self, dt):
         """Derivatives of `h2_flow` flow map with respect to input momentum.
    @@ -2831,7 +2891,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def sample_momentum(self, state, rng):
         return self.metric.sqrt @ rng.standard_normal(state.pos.shape)
    @@ -2841,7 +2901,7 @@

    Returns

    def neg_log_dens(self, state)
    -

    Negative logarithm of unnormalised density of target distribution.

    +

    Negative logarithm of unnormalized density of target distribution.

    Args

    state : ChainState
    @@ -2977,14 +3037,14 @@

    Returns

    be independent of the position variables and with a zero-mean Gaussian marginal distribution with covariance specified by M.

    Additionally the target distribution on the position variables is assumed -to be defined by an unnormalised density with respect to the standard +to be defined by an unnormalized density with respect to the standard Gaussian measure on the position space (with identity covariance and zero mean), with the Hamiltonian component h_1 corresponding to the negative logarithm of this density rather than the density with respect to the Lebesgue measure on the position space, i.e.

    h_1(q) = \ell(q) - \frac{1}{2} q^T q

    where q is the position and \ell(q) is the negative log -(unnormalised) density of the target distribution with respect to the +(unnormalized) density of the target distribution with respect to the Lebesgue measure at q. The Hamiltonian component function h_2 is then assumed to have the form

    @@ -3003,7 +3063,7 @@

    Args

    neg_log_dens : Callable[[array], float]
    Function which given a position array returns the negative logarithm of an -unnormalised probability density on the position space with +unnormalized probability density on the position space with respect to the standard Gaussian measure on the position space, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate @@ -3037,7 +3097,7 @@

    Args

    Expand source code -Browse git +Browse git
    class GaussianEuclideanMetricSystem(EuclideanMetricSystem):
         r"""Euclidean Hamiltonian system with a tractable Gaussian component.
    @@ -3048,7 +3108,7 @@ 

    Args

    marginal distribution with covariance specified by \(M\). Additionally the target distribution on the position variables is assumed - to be defined by an unnormalised density with respect to the standard + to be defined by an unnormalized density with respect to the standard Gaussian measure on the position space (with identity covariance and zero mean), with the Hamiltonian component \(h_1\) corresponding to the negative logarithm of this density rather than the density with respect to the @@ -3057,7 +3117,7 @@

    Args

    \[ h_1(q) = \ell(q) - \frac{1}{2} q^T q \] where \(q\) is the position and \(\ell(q)\) is the negative log - (unnormalised) density of the target distribution with respect to the + (unnormalized) density of the target distribution with respect to the Lebesgue measure at \(q\). The Hamiltonian component function \(h_2\) is then assumed to have the form @@ -3079,7 +3139,7 @@

    Args

    Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the standard Gaussian measure on the position space, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate @@ -3172,7 +3232,7 @@

    Returns

    Expand source code -Browse git +Browse git
    def h2(self, state):
         return (0.5 * state.pos @ state.pos +
    @@ -3197,7 +3257,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    @cache_in_state('mom')
     def dh2_dmom(self, state):
    @@ -3212,7 +3272,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    @cache_in_state('mom')
     def dh2_dpos(self, state):
    @@ -3235,7 +3295,7 @@ 

    Args

    Expand source code -Browse git +Browse git
    def h2_flow(self, state, dt):
         omega = 1. / self.metric.eigval**0.5
    @@ -3274,7 +3334,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def dh2_flow_dmom(self, dt):
         omega = 1. / self.metric.eigval**0.5
    @@ -3307,7 +3367,7 @@ 

    Returns

    def neg_log_dens(self, state)
    -

    Negative logarithm of unnormalised density of target distribution.

    +

    Negative logarithm of unnormalized density of target distribution.

    Args

    state : ChainState
    @@ -3454,7 +3514,7 @@

    Returns

    at all time points, corresponding to the momentum (velocity) being in the co-tangent space (tangent space) to the manifold.

    The target distribution is either assumed to be directly specified with -unnormalised density \exp(-\ell(q)) with respect to the Hausdorff +unnormalized density \exp(-\ell(q)) with respect to the Hausdorff measure on the manifold (under the metric induced from the ambient metric) with in this case the h_1 Hamiltonian component then simply

    h_1(q) = \ell(q),

    @@ -3492,10 +3552,10 @@

    Args

    Function which given a position array returns the negative logarithm of an -unnormalised probability density on the constrained position +unnormalized probability density on the constrained position space with respect to the Hausdorff measure on the constraint manifold (if dens_wrt_hausdorff == True) or alternatively the -negative logarithm of an unnormalised probability density on +negative logarithm of an unnormalized probability density on the unconstrained (ambient) position space with respect to the Lebesgue measure. In the former case the target distribution it is wished to draw approximate samples from is assumed to be @@ -3584,7 +3644,7 @@

    Args

    Expand source code -Browse git +Browse git
    class ConstrainedEuclideanMetricSystem(EuclideanMetricSystem):
         r"""Base class for Euclidean Hamiltonian systems subject to constraints.
    @@ -3609,7 +3669,7 @@ 

    Args

    co-tangent space (tangent space) to the manifold. The target distribution is either assumed to be directly specified with - unnormalised density \(\exp(-\ell(q))\) with respect to the Hausdorff + unnormalized density \(\exp(-\ell(q))\) with respect to the Hausdorff measure on the manifold (under the metric induced from the ambient metric) with in this case the \(h_1\) Hamiltonian component then simply @@ -3652,10 +3712,10 @@

    Args

    Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the constrained position + unnormalized probability density on the constrained position space with respect to the Hausdorff measure on the constraint manifold (if `dens_wrt_hausdorff == True`) or alternatively the - negative logarithm of an unnormalised probability density on + negative logarithm of an unnormalized probability density on the unconstrained (ambient) position space with respect to the Lebesgue measure. In the former case the target distribution it is wished to draw approximate samples from is assumed to be @@ -3903,7 +3963,7 @@

    Returns

    Expand source code -Browse git +Browse git
    @cache_in_state('pos')
     def constr(self, state):
    @@ -3936,7 +3996,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    @multi_cache_in_state(['pos'], ['jacob_constr', 'constr'])
     def jacob_constr(self, state):
    @@ -3976,7 +4036,7 @@ 

    Args

    Expand source code -Browse git +Browse git
    @abstractmethod
     def jacob_constr_inner_product(
    @@ -4021,7 +4081,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    @cache_in_state('pos')
     def gram(self, state):
    @@ -4063,7 +4123,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def inv_gram(self, state):
         """Inverse of Gram matrix at current position.
    @@ -4086,7 +4146,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def log_det_sqrt_gram(self, state):
         """Value of (half of) log-determinant of Gram matrix."""
    @@ -4112,7 +4172,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    @abstractmethod
     def grad_log_det_sqrt_gram(self, state):
    @@ -4145,7 +4205,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def h1(self, state):
         if self.dens_wrt_hausdorff:
    @@ -4172,7 +4232,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def dh1_dpos(self, state):
         if self.dens_wrt_hausdorff:
    @@ -4204,7 +4264,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def project_onto_cotangent_space(self, mom, state):
         """Project a momentum on to the co-tangent space at a position.
    @@ -4245,7 +4305,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def sample_momentum(self, state, rng):
         mom = super().sample_momentum(state, rng)
    @@ -4293,7 +4353,7 @@ 

    Returns

    def neg_log_dens(self, state)
    -

    Negative logarithm of unnormalised density of target distribution.

    +

    Negative logarithm of unnormalized density of target distribution.

    Args

    state : ChainState
    @@ -4432,10 +4492,10 @@

    Args

    Function which given a position array returns the negative logarithm of an -unnormalised probability density on the constrained position +unnormalized probability density on the constrained position space with respect to the Hausdorff measure on the constraint manifold (if dens_wrt_hausdorff == True) or alternatively the -negative logarithm of an unnormalised probability density on +negative logarithm of an unnormalized probability density on the unconstrained (ambient) position space with respect to the Lebesgue measure. In the former case the target distribution it is wished to draw approximate samples from is assumed to be @@ -4550,7 +4610,7 @@

    Args

    Expand source code -Browse git +Browse git
    class DenseConstrainedEuclideanMetricSystem(ConstrainedEuclideanMetricSystem):
         r"""Euclidean Hamiltonian system subject to a dense set of constraints.
    @@ -4566,10 +4626,10 @@ 

    Args

    Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the constrained position + unnormalized probability density on the constrained position space with respect to the Hausdorff measure on the constraint manifold (if `dens_wrt_hausdorff == True`) or alternatively the - negative logarithm of an unnormalised probability density on + negative logarithm of an unnormalized probability density on the unconstrained (ambient) position space with respect to the Lebesgue measure. In the former case the target distribution it is wished to draw approximate samples from is assumed to be @@ -4726,7 +4786,7 @@

    Methods

    Expand source code -Browse git +Browse git
    @multi_cache_in_state(
         ['pos'], ['mhp_constr', 'jacob_constr', 'constr'])
    @@ -4759,7 +4819,7 @@ 

    Args

    Expand source code -Browse git +Browse git
    def jacob_constr_inner_product(
             self, jacob_constr_1, inner_product_matrix, jacob_constr_2=None):
    @@ -4790,7 +4850,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    @cache_in_state('pos')
     def grad_log_det_sqrt_gram(self, state):
    @@ -4983,7 +5043,7 @@ 

    Returns

    def neg_log_dens(self, state)
    -

    Negative logarithm of unnormalised density of target distribution.

    +

    Negative logarithm of unnormalized density of target distribution.

    Args

    state : ChainState
    @@ -5123,7 +5183,7 @@

    Args

    Function which given a position array returns the negative logarithm of an -unnormalised probability density on the unconstrained (ambient) +unnormalized probability density on the unconstrained (ambient) position space with respect to the standard Gaussian measure. The density function is taken to specify a prior distribution on the ambient space with the target distribution then @@ -5220,7 +5280,7 @@

    Args

    Expand source code -Browse git +Browse git
    class GaussianDenseConstrainedEuclideanMetricSystem(
             GaussianEuclideanMetricSystem, DenseConstrainedEuclideanMetricSystem):
    @@ -5237,7 +5297,7 @@ 

    Args

    Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the unconstrained (ambient) + unnormalized probability density on the unconstrained (ambient) position space with respect to the standard Gaussian measure. The density function is taken to specify a prior distribution on the ambient space with the target distribution then @@ -5377,7 +5437,7 @@

    Args

    Expand source code -Browse git +Browse git
    def jacob_constr_inner_product(
             self, jacob_constr_1, inner_product_matrix, jacob_constr_2=None):
    @@ -5462,7 +5522,7 @@ 

    Returns

    def neg_log_dens(self, state)
    -

    Negative logarithm of unnormalised density of target distribution.

    +

    Negative logarithm of unnormalized density of target distribution.

    Args

    state : ChainState
    @@ -5720,7 +5780,7 @@

    Returns

    Riemannian Hamiltonian system with a position-dependent metric.

    This class allows for metric matrix representations of any generic type. -In most cases a specialised subclass such as DenseRiemannianMetricSystem, +In most cases a specialized subclass such as DenseRiemannianMetricSystem, CholeskyFactoredRiemannianMetricSystem, DiagonalRiemannianMetricSystem, ScalarRiemannianMetricSystem or SoftAbsRiemannianMetricSystem will provide a simpler method of constructng a system with a metric matrix @@ -5732,7 +5792,7 @@

    Returns

    with covariance M(q), i.e. p \sim \mathcal{N}(0, M(q)) [1].

    The h_1 Hamiltonian component is then

    h_1(q) = \ell(q) + \frac{1}{2}\log\left|M(q)\right|

    -

    where \ell(q) is the negative log (unnormalised) density of the target +

    where \ell(q) is the negative log (unnormalized) density of the target distribution with respect to the Lebesgue measure at q. The h_2 Hamiltonian component is

    h_2(q, p) = \frac{1}{2} p^T (M(q))^{-1} p.

    @@ -5752,7 +5812,7 @@

    Args

    neg_log_dens : Callable[[array], float]
    Function which given a position array returns the negative logarithm of an -unnormalised probability density on the position space with +unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from.
    @@ -5830,13 +5890,13 @@

    Args

    Expand source code -Browse git +Browse git
    class RiemannianMetricSystem(System):
         r"""Riemannian Hamiltonian system with a position-dependent metric.
     
         This class allows for metric matrix representations of any generic type.
    -    In most cases a specialised subclass such as `DenseRiemannianMetricSystem`,
    +    In most cases a specialized subclass such as `DenseRiemannianMetricSystem`,
         `CholeskyFactoredRiemannianMetricSystem`, `DiagonalRiemannianMetricSystem`,
         `ScalarRiemannianMetricSystem` or `SoftAbsRiemannianMetricSystem` will
         provide a simpler method of constructng a system with a metric matrix
    @@ -5852,7 +5912,7 @@ 

    Args

    \[ h_1(q) = \ell(q) + \frac{1}{2}\log\left|M(q)\right| \] - where \(\ell(q)\) is the negative log (unnormalised) density of the target + where \(\ell(q)\) is the negative log (unnormalized) density of the target distribution with respect to the Lebesgue measure at \(q\). The \(h_2\) Hamiltonian component is @@ -5878,7 +5938,7 @@

    Args

    Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -6069,7 +6129,7 @@

    Returns

    Expand source code -Browse git +Browse git
    @cache_in_state('pos')
     def metric_func(self, state):
    @@ -6108,7 +6168,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    @multi_cache_in_state(['pos'], ['vjp_metric_func', 'metric_func'])
     def vjp_metric_func(self, state):
    @@ -6151,7 +6211,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    @cache_in_state('pos')
     def metric(self, state):
    @@ -6189,7 +6249,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def h(self, state):
         return self.h1(state) + self.h2(state)
    @@ -6213,7 +6273,7 @@

    Returns

    Expand source code -Browse git +Browse git
    def h1(self, state):
         return self.neg_log_dens(state) + 0.5 * self.metric(state).log_abs_det
    @@ -6237,7 +6297,7 @@

    Returns

    Expand source code -Browse git +Browse git
    def dh1_dpos(self, state):
         # Evaluate VJP of metric function before metric as metric value will
    @@ -6265,7 +6325,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def h2(self, state):
         return 0.5 * state.mom @ self.metric(state).inv @ state.mom
    @@ -6279,7 +6339,7 @@

    Returns

    Expand source code -Browse git +Browse git
    def dh2_dpos(self, state):
         # Evaluate VJP of metric function before metric as metric value will
    @@ -6307,7 +6367,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def dh2_dmom(self, state):
         return self.metric(state).inv @ state.mom
    @@ -6332,7 +6392,7 @@

    Returns

    Expand source code -Browse git +Browse git
    def sample_momentum(self, state, rng):
         return self.metric(state).sqrt @ rng.normal(size=state.pos.shape)
    @@ -6342,7 +6402,7 @@

    Returns

    def neg_log_dens(self, state)
    -

    Negative logarithm of unnormalised density of target distribution.

    +

    Negative logarithm of unnormalized density of target distribution.

    Args

    state : ChainState
    @@ -6437,7 +6497,7 @@

    Args

    neg_log_dens : Callable[[array], float]
    Function which given a position array returns the negative logarithm of an -unnormalised probability density on the position space with +unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from.
    @@ -6487,7 +6547,7 @@

    Args

    Expand source code -Browse git +Browse git
    class ScalarRiemannianMetricSystem(RiemannianMetricSystem):
         """Riemannian-metric system with scaled identity matrix representation.
    @@ -6508,7 +6568,7 @@ 

    Args

    Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -6560,7 +6620,7 @@

    Args

    @cache_in_state('pos') def metric(self, state): return self._metric_matrix_class( - self.metric_func(state), size=pos.shape[0])
    + self.metric_func(state), size=state.pos.shape[0])

    Ancestors

      @@ -6587,12 +6647,12 @@

      Returns

      Expand source code -Browse git +Browse git
      @cache_in_state('pos')
       def metric(self, state):
           return self._metric_matrix_class(
      -        self.metric_func(state), size=pos.shape[0])
      + self.metric_func(state), size=state.pos.shape[0])
    @@ -6733,7 +6793,7 @@

    Returns

    def neg_log_dens(self, state)
    -

    Negative logarithm of unnormalised density of target distribution.

    +

    Negative logarithm of unnormalized density of target distribution.

    Args

    state : ChainState
    @@ -6828,7 +6888,7 @@

    Args

    neg_log_dens : Callable[[array], float]
    Function which given a position array returns the negative logarithm of an -unnormalised probability density on the position space with +unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from.
    @@ -6878,7 +6938,7 @@

    Args

    Expand source code -Browse git +Browse git
    class DiagonalRiemannianMetricSystem(RiemannianMetricSystem):
         """Riemannian-metric system with diagonal matrix representation.
    @@ -6899,7 +6959,7 @@ 

    Args

    Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -7108,7 +7168,7 @@

    Returns

    def neg_log_dens(self, state)
    -

    Negative logarithm of unnormalised density of target distribution.

    +

    Negative logarithm of unnormalized density of target distribution.

    Args

    state : ChainState
    @@ -7203,7 +7263,7 @@

    Args

    neg_log_dens : Callable[[array], float]
    Function which given a position array returns the negative logarithm of an -unnormalised probability density on the position space with +unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from.
    @@ -7254,7 +7314,7 @@

    Args

    Expand source code -Browse git +Browse git
    class CholeskyFactoredRiemannianMetricSystem(RiemannianMetricSystem):
         """Riemannian-metric system with Cholesky-factored matrix representation.
    @@ -7275,7 +7335,7 @@ 

    Args

    Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -7486,7 +7546,7 @@

    Returns

    def neg_log_dens(self, state)
    -

    Negative logarithm of unnormalised density of target distribution.

    +

    Negative logarithm of unnormalized density of target distribution.

    Args

    state : ChainState
    @@ -7580,7 +7640,7 @@

    Args

    neg_log_dens : Callable[[array], float]
    Function which given a position array returns the negative logarithm of an -unnormalised probability density on the position space with +unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from.
    @@ -7631,7 +7691,7 @@

    Args

    Expand source code -Browse git +Browse git
    class DenseRiemannianMetricSystem(RiemannianMetricSystem):
         """Riemannian-metric system with dense matrix representation.
    @@ -7651,7 +7711,7 @@ 

    Args

    Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -7861,7 +7921,7 @@

    Returns

    def neg_log_dens(self, state)
    -

    Negative logarithm of unnormalised density of target distribution.

    +

    Negative logarithm of unnormalized density of target distribution.

    Args

    state : ChainState
    @@ -7949,7 +8009,7 @@

    Returns

    position q which is guaranteed to be positive definite almost-everywhere, with M = metric_func(q) then the metric matrix representation.

    Hamiltonian system with a position dependent metric matrix representation -which is specified to be an eigenvalue-regularised transformation of the +which is specified to be an eigenvalue-regularized transformation of the Hessian of the negative log density function (the symmetric matrix of second derivatives the negative log density function with respect to the position array components. Specifically if hess_neg_log_dens is a @@ -7981,7 +8041,7 @@

    Args

    neg_log_dens : Callable[[array], float]
    Function which given a position array returns the negative logarithm of an -unnormalised probability density on the position space with +unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from.
    @@ -8040,7 +8100,7 @@

    Args

    softabs_coeff : float
    Positive regularisation coefficient for -smooth approximation to absolute value used to regularise +smooth approximation to absolute value used to regularize Hessian eigenvalues in metric matrix representation. As the value tends to infinity the approximation becomes increasingly close to the absolute function.
    @@ -8048,7 +8108,7 @@

    Args

    Expand source code -Browse git +Browse git
    class SoftAbsRiemannianMetricSystem(RiemannianMetricSystem):
         """SoftAbs Riemmanian metric Hamiltonian system.
    @@ -8059,7 +8119,7 @@ 

    Args

    with `M = metric_func(q)` then the metric matrix representation. Hamiltonian system with a position dependent metric matrix representation - which is specified to be an eigenvalue-regularised transformation of the + which is specified to be an eigenvalue-regularized transformation of the Hessian of the negative log density function (the symmetric matrix of second derivatives the negative log density function with respect to the position array components. Specifically if `hess_neg_log_dens` is a @@ -8097,7 +8157,7 @@

    Args

    Args: neg_log_dens (Callable[[array], float]): Function which given a position array returns the negative logarithm of an - unnormalised probability density on the position space with + unnormalized probability density on the position space with respect to the Lebesgue measure, with the corresponding distribution on the position space being the target distribution it is wished to draw approximate samples from. @@ -8151,7 +8211,7 @@

    Args

    construct a function which calculates the MTP (and Hesisan and gradient and value) of `neg_log_dens` automatically. softabs_coeff (float): Positive regularisation coefficient for - smooth approximation to absolute value used to regularise + smooth approximation to absolute value used to regularize Hessian eigenvalues in metric matrix representation. As the value tends to infinity the approximation becomes increasingly close to the absolute function. @@ -8163,7 +8223,7 @@

    Args

    mtp_neg_log_dens, neg_log_dens, 'mtp_hessian_grad_and_value', 'mtp_neg_log_dens') super().__init__(neg_log_dens, - SoftAbsRegularisedPositiveDefiniteMatrix, + SoftAbsRegularizedPositiveDefiniteMatrix, self._hess_neg_log_dens, self._mtp_neg_log_dens, grad_neg_log_dens, metric_kwargs={'softabs_coeff': softabs_coeff}) @@ -8244,7 +8304,7 @@

    Returns

    Expand source code -Browse git +Browse git
    def metric_func(self, state):
         return self.hess_neg_log_dens(state)
    @@ -8273,7 +8333,7 @@

    Returns

    Expand source code -Browse git +Browse git
    def vjp_metric_func(self, state):
         return self.mtp_neg_log_dens(state)
    @@ -8300,7 +8360,7 @@

    Returns

    Expand source code -Browse git +Browse git
    @multi_cache_in_state(
         ['pos'], ['hess_neg_log_dens', 'grad_neg_log_dens', 'neg_log_dens'])
    @@ -8349,7 +8409,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    @multi_cache_in_state(
         ['pos'], ['mtp_neg_log_dens', 'hess_neg_log_dens',
    @@ -8496,7 +8556,7 @@ 

    Returns

    def neg_log_dens(self, state)
    -

    Negative logarithm of unnormalised density of target distribution.

    +

    Negative logarithm of unnormalized density of target distribution.

    Args

    state : ChainState
    @@ -8579,7 +8639,7 @@

    Returns

    diff --git a/docs/docs/transitions.html b/docs/docs/transitions.html index 7369010..0c77a88 100644 --- a/docs/docs/transitions.html +++ b/docs/docs/transitions.html @@ -3,14 +3,14 @@ - + mici.transitions API documentation - + @@ -40,102 +40,147 @@
  • Classes

  • @@ -143,14 +188,14 @@

    -

    Package mici.transitions

    +

    Module mici.transitions

    Markov transition kernels.

    Expand source code -Browse git +Browse git
    """Markov transition kernels."""
     
    @@ -160,8 +205,8 @@ 

    Package mici.transitions

    import logging import numpy as np from mici.utils import LogRepFloat -from mici.errors import ( - Error, NonReversibleStepError, ConvergenceError, HamiltonianDivergenceError) +from mici.errors import (IntegratorError, NonReversibleStepError, + ConvergenceError, HamiltonianDivergenceError) logger = logging.getLogger(__name__) @@ -198,7 +243,7 @@

    Package mici.transitions

    the keys of the statistics returned in the `trans_stats` return value of the `sample` method and the first entry of the value tuples an appropriate NumPy `dtype` for the array used to store the corresponding - statistic values and second entry the default value to initialise this + statistic values and second entry the default value to initialize this array with. """ @@ -209,7 +254,7 @@

    Package mici.transitions

    Args: state (mici.states.ChainState): Current chain state to condition transition kernel on. - rng (RandomState): NumPy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. Returns: state (mici.states.ChainState): Updated state object. @@ -249,7 +294,7 @@

    Package mici.transitions

    Args: state (mici.states.ChainState): Current chain state to sample new momentum (momentum updated in place). - rng (RandomState): NumPy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. Returns: state (mici.states.ChainState): Updated state object. @@ -282,7 +327,7 @@

    Package mici.transitions

    refreshing or updating, and was originally proposed in [1]. If the resampling coefficient is equal to zero then the momentum is not - randomised at all and succesive applications of the coupled integration + randomized at all and succesive applications of the coupled integration transitions will continue along the same simulated Hamiltonian trajectory. When an integration transition is accepted this means the subsequent simulated trajectory will continue evolving in the same direction and so @@ -334,9 +379,8 @@

    Package mici.transitions

    state_variables = {'pos', 'mom', 'dir'} statistic_types = { - 'hamiltonian': (np.float64, np.nan), 'n_step': (np.int64, -1), - 'accept_prob': (np.float64, np.nan), + 'accept_stat': (np.float64, np.nan), 'non_reversible_step': (np.bool, False), 'convergence_error': (np.bool, False) } @@ -361,7 +405,7 @@

    Package mici.transitions

    Args: state (mici.states.ChainState): Current chain state. - rng (RandomState): NumPy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. Returns: state (mici.states.ChainState): Updated state object. @@ -386,26 +430,39 @@

    Package mici.transitions

    the negation of its initial value. """ + def __init__(self, system, integrator): + super().__init__(system, integrator) + self.statistic_types['metrop_accept_prob'] = (np.float64, np.nan) + def _sample_n_step(self, state, n_step, rng): h_init = self.system.h(state) state_p = state + integration_error = False try: for s in range(n_step): state_p = self.integrator.step(state_p) - except Error as e: - stats = {'hamiltonian': h_init, 'accept_prob': 0, 'n_step': s} + except IntegratorError as e: + integration_error = True + stats = {'n_step': s} _process_integrator_error(e, stats) - return state, stats - state_p.dir *= -1 - h_final = self.system.h(state_p) - metrop_ratio = np.exp(h_init - h_final) - accept_prob = 0 if np.isnan(metrop_ratio) else min(1, metrop_ratio) - if rng.uniform() < accept_prob: + else: + stats = {'n_step': n_step} + # Reverse integration direction of proposal to form an involution + state_p.dir *= -1 + if state_p is not state: + h_final = self.system.h(state_p) + metrop_ratio = np.exp(h_init - h_final) + accept_prob = 0 if np.isnan(metrop_ratio) else min(1, metrop_ratio) + else: + accept_prob = 0. + stats['metrop_accept_prob'] = accept_prob + stats['accept_stat'] = accept_prob if not integration_error else 0 + if not integration_error and rng.uniform() < accept_prob: state = state_p + # Reverse integration direction of new state + # As extended target distribution is symmetric in direction indicator + # this always leaves the distribution invariant state.dir *= -1 - stats = {'hamiltonian': self.system.h(state), - 'accept_prob': accept_prob, 'n_step': n_step, - 'non_reversible_step': False, 'convergence_error': False} return state, stats @@ -513,13 +570,13 @@

    Package mici.transitions

    def riemannian_no_u_turn_criterion(system, state_1, state_2, sum_mom): - """Generalised no-U-turn termination criterion on Riemannian manifolds [2]. + """Generalized no-U-turn termination criterion on Riemannian manifolds [2]. Terminates trajectories when the velocities at the terminal states of the trajectory both have negative dot products with the sum of the the momentums across the trajectory from the first to second terminal state of the first terminal state to the position of the second terminal state. - This generalises the no-U-turn criterion of [1] to Riemannian manifolds + This generalizes the no-U-turn criterion of [1] to Riemannian manifolds where due to the intrinsic curvature of the space the geodesic between two points is general no longer a straight line. @@ -545,7 +602,7 @@

    Package mici.transitions

    np.sum(system.dh_dmom(state_2) * sum_mom) < 0) -SubTree = namedtuple('SubTree', [ +_SubTree = namedtuple('_SubTree', [ 'negative', 'positive', 'sum_mom', 'weight', 'depth']) @@ -615,6 +672,8 @@

    Package mici.transitions

    self.max_delta_h = max_delta_h self.termination_criterion = termination_criterion self.do_extra_subtree_checks = do_extra_subtree_checks + self.statistic_types['av_metrop_accept_prob'] = (np.float64, np.nan) + self.statistic_types['reject_prob'] = (np.float64, np.nan) self.statistic_types['tree_depth'] = (np.int64, -1) self.statistic_types['diverging'] = (np.bool, False) @@ -638,14 +697,14 @@

    Package mici.transitions

    return False def _new_leave(self, state, h, aux_info): - return SubTree( + return _SubTree( negative=state, positive=state, sum_mom=np.asarray(state.mom), weight=self._weight_function(h, aux_info), depth=0) def _merge_subtrees(self, neg_subtree, pos_subtree): assert neg_subtree.depth == pos_subtree.depth, ( - 'Cannot merg subtrees of different depths') - return SubTree( + 'Cannot merge subtrees of different depths') + return _SubTree( negative=neg_subtree.negative, positive=pos_subtree.positive, weight=neg_subtree.weight + pos_subtree.weight, sum_mom=neg_subtree.sum_mom + pos_subtree.sum_mom, @@ -654,9 +713,6 @@

    Package mici.transitions

    def _init_aux_vars(self, state, rng): return {'h_init': self.system.h(state)} - def _accept_stat(self, h, aux_vars): - return min(1, np.exp(aux_vars['h_init'] - h)) - @abstractmethod def _weight_function(self, h, aux_vars): pass @@ -680,13 +736,14 @@

    Package mici.transitions

    # create new tree leave tree = self._new_leave(state, h, aux_vars) proposal = state - # accumulate stats to calculate proxy acceptance probability - stats['sum_acc_prob'] += self._accept_stat(h, aux_vars) + # accumulate stats + stats['sum_metrop_accept_prob'] += min( + 1, np.exp(aux_vars['h_init'] - h)) stats['n_step'] += 1 # default to assuming valid and then check for divergence terminate = False self._check_divergence(h, aux_vars) - except Error as e: + except IntegratorError as e: _process_integrator_error(e, stats) terminate, tree, proposal = True, None, None return terminate, tree, proposal @@ -715,7 +772,7 @@

    Package mici.transitions

    return terminate, tree, proposal def sample(self, state, rng): - stats = {'n_step': 0, 'sum_acc_prob': 0.} + stats = {'n_step': 0, 'sum_metrop_accept_prob': 0., 'reject_prob': 1.} aux_vars = self._init_aux_vars(state, rng) tree = self._new_leave(state, aux_vars['h_init'], aux_vars) next_state = state @@ -732,8 +789,14 @@

    Package mici.transitions

    # progressively sample new state by choosing between # current new state and proposal from new subtree, biasing # towards the new subtree proposal - if rng.uniform() < self._weight_ratio(new_tree.weight, tree.weight): + accept_proposal_prob = self._weight_ratio( + new_tree.weight, tree.weight) + if rng.uniform() < accept_proposal_prob: next_state = new_proposal + # each proposal acceptance independent therefore overall probability + # of 'rejecting' - i.e. not accepting all proposals is product of + # probabilties of not accepting each proposal + stats['reject_prob'] *= (1. - accept_proposal_prob) # merge new subtree into current tree accounting for direction neg_subtree = tree if direction == 1 else new_tree pos_subtree = new_tree if direction == 1 else tree @@ -741,12 +804,16 @@

    Package mici.transitions

    # check termination criterion on new tree and subtrees if self._termination_criterion(tree, neg_subtree, pos_subtree): break - sum_acc_prob = stats.pop('sum_acc_prob') + sum_accept_prob = stats.pop('sum_metrop_accept_prob') if stats['n_step'] > 0: - stats['accept_prob'] = sum_acc_prob / stats['n_step'] + stats['av_metrop_accept_prob'] = sum_accept_prob / stats['n_step'] + else: + stats['av_metrop_accept_prob'] = 0. + if any(stats.get(key, False) for key in + ['diverging', 'convergence_error', 'non_reversible_step']): + stats['accept_stat'] = 0. else: - stats['accept_prob'] = 0. - stats['hamiltonian'] = self.system.h(next_state) + stats['accept_stat'] = stats['av_metrop_accept_prob'] stats['tree_depth'] = depth return next_state, stats @@ -866,7 +933,7 @@

    References

    Expand source code -Browse git +Browse git
    def euclidean_no_u_turn_criterion(system, state_1, state_2, sum_mom):
         """No-U-turn termination criterion for Euclidean manifolds [1].
    @@ -901,12 +968,12 @@ 

    References

    def riemannian_no_u_turn_criterion(system, state_1, state_2, sum_mom)
    -

    Generalised no-U-turn termination criterion on Riemannian manifolds [2].

    +

    Generalized no-U-turn termination criterion on Riemannian manifolds [2].

    Terminates trajectories when the velocities at the terminal states of the trajectory both have negative dot products with the sum of the the momentums across the trajectory from the first to second terminal state of the first terminal state to the position of the second terminal state. -This generalises the no-U-turn criterion of [1] to Riemannian manifolds +This generalizes the no-U-turn criterion of [1] to Riemannian manifolds where due to the intrinsic curvature of the space the geodesic between two points is general no longer a straight line.

    Args

    @@ -936,16 +1003,16 @@

    References

    Expand source code -Browse git +Browse git
    def riemannian_no_u_turn_criterion(system, state_1, state_2, sum_mom):
    -    """Generalised no-U-turn termination criterion on Riemannian manifolds [2].
    +    """Generalized no-U-turn termination criterion on Riemannian manifolds [2].
     
         Terminates trajectories when the velocities at the terminal states of
         the trajectory both have negative dot products with the sum of the
         the momentums across the trajectory from the first to second terminal state
         of the first terminal state to the position of the second terminal state.
    -    This generalises the no-U-turn criterion of [1] to Riemannian manifolds
    +    This generalizes the no-U-turn criterion of [1] to Riemannian manifolds
         where due to the intrinsic curvature of the space the geodesic between
         two points is general no longer a straight line.
     
    @@ -986,7 +1053,7 @@ 

    Classes

    Expand source code -Browse git +Browse git
    class Transition(ABC):
         """Base class for Markov transition kernels.
    @@ -1007,7 +1074,7 @@ 

    Classes

    the keys of the statistics returned in the `trans_stats` return value of the `sample` method and the first entry of the value tuples an appropriate NumPy `dtype` for the array used to store the corresponding - statistic values and second entry the default value to initialise this + statistic values and second entry the default value to initialize this array with. """ @@ -1018,7 +1085,7 @@

    Classes

    Args: state (mici.states.ChainState): Current chain state to condition transition kernel on. - rng (RandomState): NumPy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. Returns: state (mici.states.ChainState): Updated state object. @@ -1043,7 +1110,7 @@

    Instance variables

    Expand source code -Browse git +Browse git
    @abstractproperty
     def state_variables(self):
    @@ -1058,12 +1125,12 @@ 

    Instance variables

    the keys of the statistics returned in the trans_stats return value of the sample method and the first entry of the value tuples an appropriate NumPy dtype for the array used to store the corresponding -statistic values and second entry the default value to initialise this +statistic values and second entry the default value to initialize this array with.

    Expand source code -Browse git +Browse git
    @abstractproperty
     def statistic_types(self):
    @@ -1074,7 +1141,7 @@ 

    Instance variables

    the keys of the statistics returned in the `trans_stats` return value of the `sample` method and the first entry of the value tuples an appropriate NumPy `dtype` for the array used to store the corresponding - statistic values and second entry the default value to initialise this + statistic values and second entry the default value to initialize this array with. """
    @@ -1092,8 +1159,8 @@

    Args

    state : ChainState
    Current chain state to condition transition kernel on.
    -
    rng : RandomState
    -
    NumPy RandomState random number generator.
    +
    rng : Generator or RandomState
    +
    Numpy random number generator.

    Returns

    @@ -1106,7 +1173,7 @@

    Returns

    Expand source code -Browse git +Browse git
    @abstractmethod
     def sample(self, state, rng):
    @@ -1115,7 +1182,7 @@ 

    Returns

    Args: state (mici.states.ChainState): Current chain state to condition transition kernel on. - rng (RandomState): NumPy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. Returns: state (mici.states.ChainState): Updated state object. @@ -1145,7 +1212,7 @@

    Args

    Expand source code -Browse git +Browse git
    class MomentumTransition(Transition):
         """Base class for momentum transitions.
    @@ -1178,7 +1245,7 @@ 

    Args

    Args: state (mici.states.ChainState): Current chain state to sample new momentum (momentum updated in place). - rng (RandomState): NumPy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. Returns: state (mici.states.ChainState): Updated state object. @@ -1212,7 +1279,7 @@

    Class variables

    the keys of the statistics returned in the trans_stats return value of the sample method and the first entry of the value tuples an appropriate NumPy dtype for the array used to store the corresponding -statistic values and second entry the default value to initialise this +statistic values and second entry the default value to initialize this array with.

    @@ -1232,8 +1299,8 @@

    Args

    state : ChainState
    Current chain state to sample new momentum (momentum updated in place).
    -
    rng : RandomState
    -
    NumPy RandomState random number generator.
    +
    rng : Generator or RandomState
    +
    Numpy random number generator.

    Returns

    @@ -1246,7 +1313,7 @@

    Returns

    Expand source code -Browse git +Browse git
    @abstractmethod
     def sample(self, state, rng):
    @@ -1260,7 +1327,7 @@ 

    Returns

    Args: state (mici.states.ChainState): Current chain state to sample new momentum (momentum updated in place). - rng (RandomState): NumPy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. Returns: state (mici.states.ChainState): Updated state object. @@ -1288,7 +1355,7 @@

    Args

    Expand source code -Browse git +Browse git
    class IndependentMomentumTransition(MomentumTransition):
         """Independent momentum transition.
    @@ -1326,7 +1393,7 @@ 

    Instance variables

    the keys of the statistics returned in the trans_stats return value of the sample method and the first entry of the value tuples an appropriate NumPy dtype for the array used to store the corresponding -statistic values and second entry the default value to initialise this +statistic values and second entry the default value to initialize this array with.

    @@ -1346,8 +1413,8 @@

    Args

    state : ChainState
    Current chain state to sample new momentum (momentum updated in place).
    -
    rng : RandomState
    -
    NumPy RandomState random number generator.
    +
    rng : Generator or RandomState
    +
    Numpy random number generator.

    Returns

    @@ -1360,7 +1427,7 @@

    Returns

    Expand source code -Browse git +Browse git
    def sample(self, state, rng):
         state.mom = self.system.sample_momentum(state, rng)
    @@ -1383,7 +1450,7 @@ 

    Returns

    exactly invariant. This approach is sometimes known as partial momentum refreshing or updating, and was originally proposed in [1].

    If the resampling coefficient is equal to zero then the momentum is not -randomised at all and succesive applications of the coupled integration +randomized at all and succesive applications of the coupled integration transitions will continue along the same simulated Hamiltonian trajectory. When an integration transition is accepted this means the subsequent simulated trajectory will continue evolving in the same direction and so @@ -1411,7 +1478,7 @@

    Args

    Expand source code -Browse git +Browse git
    class CorrelatedMomentumTransition(MomentumTransition):
         """Correlated (partial) momentum transition.
    @@ -1425,7 +1492,7 @@ 

    Args

    refreshing or updating, and was originally proposed in [1]. If the resampling coefficient is equal to zero then the momentum is not - randomised at all and succesive applications of the coupled integration + randomized at all and succesive applications of the coupled integration transitions will continue along the same simulated Hamiltonian trajectory. When an integration transition is accepted this means the subsequent simulated trajectory will continue evolving in the same direction and so @@ -1490,7 +1557,7 @@

    Instance variables

    the keys of the statistics returned in the trans_stats return value of the sample method and the first entry of the value tuples an appropriate NumPy dtype for the array used to store the corresponding -statistic values and second entry the default value to initialise this +statistic values and second entry the default value to initialize this array with.

    @@ -1510,8 +1577,8 @@

    Args

    state : ChainState
    Current chain state to sample new momentum (momentum updated in place).
    -
    rng : RandomState
    -
    NumPy RandomState random number generator.
    +
    rng : Generator or RandomState
    +
    Numpy random number generator.

    Returns

    @@ -1524,7 +1591,7 @@

    Returns

    Expand source code -Browse git +Browse git
    def sample(self, state, rng):
         if self.mom_resample_coeff == 1:
    @@ -1559,7 +1626,7 @@ 

    Args

    Expand source code -Browse git +Browse git
    class IntegrationTransition(Transition):
         """Base class for integration transtions.
    @@ -1572,9 +1639,8 @@ 

    Args

    state_variables = {'pos', 'mom', 'dir'} statistic_types = { - 'hamiltonian': (np.float64, np.nan), 'n_step': (np.int64, -1), - 'accept_prob': (np.float64, np.nan), + 'accept_stat': (np.float64, np.nan), 'non_reversible_step': (np.bool, False), 'convergence_error': (np.bool, False) } @@ -1599,7 +1665,7 @@

    Args

    Args: state (mici.states.ChainState): Current chain state. - rng (RandomState): NumPy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. Returns: state (mici.states.ChainState): Updated state object. @@ -1654,8 +1720,8 @@

    Args

    state : ChainState
    Current chain state.
    -
    rng : RandomState
    -
    NumPy RandomState random number generator.
    +
    rng : Generator or RandomState
    +
    Numpy random number generator.

    Returns

    @@ -1668,7 +1734,7 @@

    Returns

    Expand source code -Browse git +Browse git
    @abstractmethod
     def sample(self, state, rng):
    @@ -1680,7 +1746,7 @@ 

    Returns

    Args: state (mici.states.ChainState): Current chain state. - rng (RandomState): NumPy RandomState random number generator. + rng (Generator or RandomState): Numpy random number generator. Returns: state (mici.states.ChainState): Updated state object. @@ -1718,7 +1784,7 @@

    Args

    Expand source code -Browse git +Browse git
    class MetropolisIntegrationTransition(IntegrationTransition):
         """Base for HMC methods using a Metropolis accept step to sample new state.
    @@ -1736,26 +1802,39 @@ 

    Args

    the negation of its initial value. """ + def __init__(self, system, integrator): + super().__init__(system, integrator) + self.statistic_types['metrop_accept_prob'] = (np.float64, np.nan) + def _sample_n_step(self, state, n_step, rng): h_init = self.system.h(state) state_p = state + integration_error = False try: for s in range(n_step): state_p = self.integrator.step(state_p) - except Error as e: - stats = {'hamiltonian': h_init, 'accept_prob': 0, 'n_step': s} + except IntegratorError as e: + integration_error = True + stats = {'n_step': s} _process_integrator_error(e, stats) - return state, stats - state_p.dir *= -1 - h_final = self.system.h(state_p) - metrop_ratio = np.exp(h_init - h_final) - accept_prob = 0 if np.isnan(metrop_ratio) else min(1, metrop_ratio) - if rng.uniform() < accept_prob: + else: + stats = {'n_step': n_step} + # Reverse integration direction of proposal to form an involution + state_p.dir *= -1 + if state_p is not state: + h_final = self.system.h(state_p) + metrop_ratio = np.exp(h_init - h_final) + accept_prob = 0 if np.isnan(metrop_ratio) else min(1, metrop_ratio) + else: + accept_prob = 0. + stats['metrop_accept_prob'] = accept_prob + stats['accept_stat'] = accept_prob if not integration_error else 0 + if not integration_error and rng.uniform() < accept_prob: state = state_p + # Reverse integration direction of new state + # As extended target distribution is symmetric in direction indicator + # this always leaves the distribution invariant state.dir *= -1 - stats = {'hamiltonian': self.system.h(state), - 'accept_prob': accept_prob, 'n_step': n_step, - 'non_reversible_step': False, 'convergence_error': False} return state, stats

    Ancestors

    @@ -1806,8 +1885,8 @@

    Args

    state : ChainState
    Current chain state.
    -
    rng : RandomState
    -
    NumPy RandomState random number generator.
    +
    rng : Generator or RandomState
    +
    Numpy random number generator.

    Returns

    @@ -1851,7 +1930,7 @@

    Args

    Expand source code -Browse git +Browse git
    class MetropolisStaticIntegrationTransition(MetropolisIntegrationTransition):
         """Static integration transition with Metropolis sampling of new state.
    @@ -1929,8 +2008,8 @@ 

    Args

    state : ChainState
    Current chain state.
    -
    rng : RandomState
    -
    NumPy RandomState random number generator.
    +
    rng : Generator or RandomState
    +
    Numpy random number generator.

    Returns

    @@ -1943,7 +2022,7 @@

    Returns

    Expand source code -Browse git +Browse git
    def sample(self, state, rng):
         return self._sample_n_step(state, self.n_step, rng)
    @@ -1987,7 +2066,7 @@

    Args

    Expand source code -Browse git +Browse git
    class MetropolisRandomIntegrationTransition(MetropolisIntegrationTransition):
         """Random integration transition with Metropolis sampling of new state.
    @@ -2073,8 +2152,8 @@ 

    Args

    state : ChainState
    Current chain state.
    -
    rng : RandomState
    -
    NumPy RandomState random number generator.
    +
    rng : Generator or RandomState
    +
    Numpy random number generator.

    Returns

    @@ -2087,7 +2166,7 @@

    Returns

    Expand source code -Browse git +Browse git
    def sample(self, state, rng):
         n_step = rng.random_integers(*self.n_step_range)
    @@ -2096,40 +2175,6 @@ 

    Returns

    -
    -class SubTree -(*args, **kwargs) -
    -
    -

    SubTree(negative, positive, sum_mom, weight, depth)

    -

    Ancestors

    -
      -
    • builtins.tuple
    • -
    -

    Instance variables

    -
    -
    var negative
    -
    -

    Alias for field number 0

    -
    -
    var positive
    -
    -

    Alias for field number 1

    -
    -
    var sum_mom
    -
    -

    Alias for field number 2

    -
    -
    var weight
    -
    -

    Alias for field number 3

    -
    -
    var depth
    -
    -

    Alias for field number 4

    -
    -
    -
    class DynamicIntegrationTransition (system, integrator, max_tree_depth=10, max_delta_h=1000, termination_criterion=<function riemannian_no_u_turn_criterion>, do_extra_subtree_checks=True) @@ -2198,7 +2243,7 @@

    Args

    Expand source code -Browse git +Browse git
    class DynamicIntegrationTransition(IntegrationTransition):
         """Base class for dynamic integration transitions.
    @@ -2266,6 +2311,8 @@ 

    Args

    self.max_delta_h = max_delta_h self.termination_criterion = termination_criterion self.do_extra_subtree_checks = do_extra_subtree_checks + self.statistic_types['av_metrop_accept_prob'] = (np.float64, np.nan) + self.statistic_types['reject_prob'] = (np.float64, np.nan) self.statistic_types['tree_depth'] = (np.int64, -1) self.statistic_types['diverging'] = (np.bool, False) @@ -2289,14 +2336,14 @@

    Args

    return False def _new_leave(self, state, h, aux_info): - return SubTree( + return _SubTree( negative=state, positive=state, sum_mom=np.asarray(state.mom), weight=self._weight_function(h, aux_info), depth=0) def _merge_subtrees(self, neg_subtree, pos_subtree): assert neg_subtree.depth == pos_subtree.depth, ( - 'Cannot merg subtrees of different depths') - return SubTree( + 'Cannot merge subtrees of different depths') + return _SubTree( negative=neg_subtree.negative, positive=pos_subtree.positive, weight=neg_subtree.weight + pos_subtree.weight, sum_mom=neg_subtree.sum_mom + pos_subtree.sum_mom, @@ -2305,9 +2352,6 @@

    Args

    def _init_aux_vars(self, state, rng): return {'h_init': self.system.h(state)} - def _accept_stat(self, h, aux_vars): - return min(1, np.exp(aux_vars['h_init'] - h)) - @abstractmethod def _weight_function(self, h, aux_vars): pass @@ -2331,13 +2375,14 @@

    Args

    # create new tree leave tree = self._new_leave(state, h, aux_vars) proposal = state - # accumulate stats to calculate proxy acceptance probability - stats['sum_acc_prob'] += self._accept_stat(h, aux_vars) + # accumulate stats + stats['sum_metrop_accept_prob'] += min( + 1, np.exp(aux_vars['h_init'] - h)) stats['n_step'] += 1 # default to assuming valid and then check for divergence terminate = False self._check_divergence(h, aux_vars) - except Error as e: + except IntegratorError as e: _process_integrator_error(e, stats) terminate, tree, proposal = True, None, None return terminate, tree, proposal @@ -2366,7 +2411,7 @@

    Args

    return terminate, tree, proposal def sample(self, state, rng): - stats = {'n_step': 0, 'sum_acc_prob': 0.} + stats = {'n_step': 0, 'sum_metrop_accept_prob': 0., 'reject_prob': 1.} aux_vars = self._init_aux_vars(state, rng) tree = self._new_leave(state, aux_vars['h_init'], aux_vars) next_state = state @@ -2383,8 +2428,14 @@

    Args

    # progressively sample new state by choosing between # current new state and proposal from new subtree, biasing # towards the new subtree proposal - if rng.uniform() < self._weight_ratio(new_tree.weight, tree.weight): + accept_proposal_prob = self._weight_ratio( + new_tree.weight, tree.weight) + if rng.uniform() < accept_proposal_prob: next_state = new_proposal + # each proposal acceptance independent therefore overall probability + # of 'rejecting' - i.e. not accepting all proposals is product of + # probabilties of not accepting each proposal + stats['reject_prob'] *= (1. - accept_proposal_prob) # merge new subtree into current tree accounting for direction neg_subtree = tree if direction == 1 else new_tree pos_subtree = new_tree if direction == 1 else tree @@ -2392,12 +2443,16 @@

    Args

    # check termination criterion on new tree and subtrees if self._termination_criterion(tree, neg_subtree, pos_subtree): break - sum_acc_prob = stats.pop('sum_acc_prob') + sum_accept_prob = stats.pop('sum_metrop_accept_prob') if stats['n_step'] > 0: - stats['accept_prob'] = sum_acc_prob / stats['n_step'] + stats['av_metrop_accept_prob'] = sum_accept_prob / stats['n_step'] else: - stats['accept_prob'] = 0. - stats['hamiltonian'] = self.system.h(next_state) + stats['av_metrop_accept_prob'] = 0. + if any(stats.get(key, False) for key in + ['diverging', 'convergence_error', 'non_reversible_step']): + stats['accept_stat'] = 0. + else: + stats['accept_stat'] = stats['av_metrop_accept_prob'] stats['tree_depth'] = depth return next_state, stats
    @@ -2449,8 +2504,8 @@

    Args

    state : ChainState
    Current chain state.
    -
    rng : RandomState
    -
    NumPy RandomState random number generator.
    +
    rng : Generator or RandomState
    +
    Numpy random number generator.

    Returns

    @@ -2463,10 +2518,10 @@

    Returns

    Expand source code -Browse git +Browse git
    def sample(self, state, rng):
    -    stats = {'n_step': 0, 'sum_acc_prob': 0.}
    +    stats = {'n_step': 0, 'sum_metrop_accept_prob': 0., 'reject_prob': 1.}
         aux_vars = self._init_aux_vars(state, rng)
         tree = self._new_leave(state, aux_vars['h_init'], aux_vars)
         next_state = state
    @@ -2483,8 +2538,14 @@ 

    Returns

    # progressively sample new state by choosing between # current new state and proposal from new subtree, biasing # towards the new subtree proposal - if rng.uniform() < self._weight_ratio(new_tree.weight, tree.weight): + accept_proposal_prob = self._weight_ratio( + new_tree.weight, tree.weight) + if rng.uniform() < accept_proposal_prob: next_state = new_proposal + # each proposal acceptance independent therefore overall probability + # of 'rejecting' - i.e. not accepting all proposals is product of + # probabilties of not accepting each proposal + stats['reject_prob'] *= (1. - accept_proposal_prob) # merge new subtree into current tree accounting for direction neg_subtree = tree if direction == 1 else new_tree pos_subtree = new_tree if direction == 1 else tree @@ -2492,12 +2553,16 @@

    Returns

    # check termination criterion on new tree and subtrees if self._termination_criterion(tree, neg_subtree, pos_subtree): break - sum_acc_prob = stats.pop('sum_acc_prob') + sum_accept_prob = stats.pop('sum_metrop_accept_prob') if stats['n_step'] > 0: - stats['accept_prob'] = sum_acc_prob / stats['n_step'] + stats['av_metrop_accept_prob'] = sum_accept_prob / stats['n_step'] + else: + stats['av_metrop_accept_prob'] = 0. + if any(stats.get(key, False) for key in + ['diverging', 'convergence_error', 'non_reversible_step']): + stats['accept_stat'] = 0. else: - stats['accept_prob'] = 0. - stats['hamiltonian'] = self.system.h(next_state) + stats['accept_stat'] = stats['av_metrop_accept_prob'] stats['tree_depth'] = depth return next_state, stats
    @@ -2572,7 +2637,7 @@

    Args

    Expand source code -Browse git +Browse git
    class MultinomialDynamicIntegrationTransition(DynamicIntegrationTransition):
         """Dynamic integration transition with multinomial sampling of new state.
    @@ -2649,8 +2714,8 @@ 

    Args

    state : ChainState
    Current chain state.
    -
    rng : RandomState
    -
    NumPy RandomState random number generator.
    +
    rng : Generator or RandomState
    +
    Numpy random number generator.

    Returns

    @@ -2732,7 +2797,7 @@

    Args

    Expand source code -Browse git +Browse git
    class SliceDynamicIntegrationTransition(DynamicIntegrationTransition):
         """Dynamic integration transition with slice sampling of new state.
    @@ -2818,8 +2883,8 @@ 

    Args

    state : ChainState
    Current chain state.
    -
    rng : RandomState
    -
    NumPy RandomState random number generator.
    +
    rng : Generator or RandomState
    +
    Numpy random number generator.

    Returns

    @@ -2838,7 +2903,7 @@

    Returns

    diff --git a/docs/docs/utils.html b/docs/docs/utils.html index 288538b..5dfa3f8 100644 --- a/docs/docs/utils.html +++ b/docs/docs/utils.html @@ -3,14 +3,14 @@ - + mici.utils API documentation - + @@ -32,8 +32,8 @@
  • Functions

    -
      -
    • setup_tqdm_logger
    • +
        +
      • convert_to_arviz_inference_data
      • hash_array
      • log1p_exp
      • log1m_exp
      • @@ -44,13 +44,7 @@
      • Classes

        • -

          TqdmHandler

          - -
        • -
        • -

          LogRepFloat

          +LogRepFloat @@ -61,14 +55,14 @@

          LogRe
          -

          Package mici.utils

          +

          Module mici.utils

          Utility functions and classes.

          Expand source code -Browse git +Browse git
          """Utility functions and classes."""
           
          @@ -218,7 +212,7 @@ 

          Package mici.utils

          elif val > LOG_2: return log(-expm1(val)) else: - return log1p(-exp(a)) + return log1p(-exp(val)) def log_sum_exp(val1, val2): @@ -296,6 +290,9 @@

          Package mici.utils

          else: return self.val - other + def __rsub__(self, other): + return (-self).__radd__(other) + def __mul__(self, other): if isinstance(other, LogRepFloat): return LogRepFloat(log_val=self.log_val + other.log_val) @@ -364,22 +361,109 @@

          Package mici.utils

          Functions

          -
          -def setup_tqdm_logger() +
          +def convert_to_arviz_inference_data(traces, chain_stats, sample_stats_key=None)
          -

          Returns a logger which redirects log output to tqdm.write.

          +

          Wrap chain outputs in an arviz.InferenceData container object.

          +

          The traces and chain_stats arguments should correspond to a +multiple-chain sampler output i.e. the returned values from a +sample_chains call.

          +

          Args

          +
          +
          traces : Dict[str, List[array]]
          +
          Trace arrays, with one entry per +function in trace_funcs passed to sampler method. Each entry +consists of a list of arrays, one per chain, with the first +axes of the arrays corresponding to the sampling (draw) index.
          +
          chain_stats : Dict[str, List[array]]
          +
          Chain integration transition +statistics as a dictionary with string keys describing the +statistics recorded and values corresponding to a list of +arrays with one array per chain and the first axis of the +arrays corresponding to the sampling index.
          +
          sample_stats_key : str
          +
          Optional. Key of transition in +chain_stats to use the recorded statistics of to populate the +sampling_stats group in the returned InferenceData object.
          +
          +

          Returns

          +
          +
          arviz.InferenceData:
          +
          An arviz data container with groups posterior and +'sample_stats', both of instances of xarray.Dataset. The +posterior group corresponds to the chain variable traces +provides in the traces argument and the sample_stats +group corresponds to the chain transitions statistics passed +in the chain_stats argument (if multiple transition +statistics dictionaries are present the sample_stats_key +argument should be specified to indicate which to use).
          +
          Expand source code -Browse git +Browse git -
          def setup_tqdm_logger():
          -    """Returns a logger which redirects log output to `tqdm.write`."""
          -    logger = logging.getLogger()
          -    handler = TqdmHandler()
          -    logger.addHandler(handler)
          -    return logger
          +
          def convert_to_arviz_inference_data(
          +        traces, chain_stats, sample_stats_key=None):
          +    """Wrap chain outputs in an `arviz.InferenceData` container object.
          +
          +    The `traces` and `chain_stats` arguments should correspond to a
          +    multiple-chain sampler output i.e. the returned values from a
          +    `sample_chains` call.
          +
          +    Args:
          +        traces (Dict[str, List[array]]): Trace arrays, with one entry per
          +            function in `trace_funcs` passed to sampler method. Each entry
          +            consists of a list of arrays, one per chain, with the first
          +            axes of the arrays corresponding to the sampling (draw) index.
          +        chain_stats (Dict[str, List[array]]): Chain integration transition
          +            statistics as a dictionary with string keys describing the
          +            statistics recorded and values corresponding to a list of
          +            arrays with one array per chain and the first axis of the
          +            arrays corresponding to the sampling index.
          +        sample_stats_key (str): Optional. Key of transition in
          +            `chain_stats` to use the recorded statistics of to populate the
          +            `sampling_stats` group in the returned `InferenceData` object.
          +
          +    Returns:
          +        arviz.InferenceData:
          +            An arviz data container with groups `posterior` and
          +            'sample_stats', both of instances of `xarray.Dataset`. The
          +            `posterior` group corresponds to the chain variable traces
          +            provides in the `traces` argument and the `sample_stats`
          +            group corresponds to the chain transitions statistics passed
          +            in the `chain_stats` argument (if multiple transition
          +            statistics dictionaries are present the `sample_stats_key`
          +            argument should be specified to indicate which to use).
          +    """
          +    if (sample_stats_key is not None and
          +            sample_stats_key not in chain_stats):
          +        raise ValueError(
          +            f'Specified `sample_stats_key` ({sample_stats_key}) does '
          +            f'not match any transition in `chain_stats`.')
          +    if sample_stats_key is not None:
          +        return arviz.InferenceData(
          +            posterior=arviz.dict_to_dataset(traces, library=mici),
          +            sample_stats=arviz.dict_to_dataset(
          +                chain_stats[sample_stats_key], library=mici))
          +    elif not isinstance(next(iter(chain_stats.values())), dict):
          +        # chain_stats dictionary value not another dictionary therefore
          +        # assume corresponds to statistics for a single transition
          +        return arviz.InferenceData(
          +            posterior=arviz.dict_to_dataset(traces, library=mici),
          +            sample_stats=arviz.dict_to_dataset(chain_stats, library=mici))
          +    elif len(chain_stats) == 1:
          +        # single transtition statistics dictionary in chain_stats therefore
          +        # unambiguous to set sample_stats
          +        return arviz.InferenceData(
          +            posterior=arviz.dict_to_dataset(traces, library=mici),
          +            sample_stats=arviz.dict_to_dataset(
          +                chain_stats.popitem()[1], library=mici))
          +    else:
          +        raise ValueError(
          +            '`sample_stats_key` must be specified as `chain_stats` '
          +            'contains multiple transtitiion statistics dictionaries.')
          @@ -400,7 +484,7 @@

          Returns

          Expand source code -Browse git +Browse git
          def hash_array(array):
               """Compute hash of a NumPy array by hashing data as a byte sequence.
          @@ -434,7 +518,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def log1p_exp(val):
               """Numerically stable implementation of `log(1 + exp(val))`."""
          @@ -452,7 +536,7 @@ 

          Returns

          Expand source code -Browse git +Browse git
          def log1m_exp(val):
               """Numerically stable implementation of `log(1 - exp(val))`."""
          @@ -461,7 +545,7 @@ 

          Returns

          elif val > LOG_2: return log(-expm1(val)) else: - return log1p(-exp(a))
          + return log1p(-exp(val))

  • @@ -472,7 +556,7 @@

    Returns

    Expand source code -Browse git +Browse git
    def log_sum_exp(val1, val2):
         """Numerically stable implementation of `log(exp(val1) + exp(val2))`."""
    @@ -490,7 +574,7 @@ 

    Returns

    Expand source code -Browse git +Browse git
    def log_diff_exp(val1, val2):
         """Numerically stable implementation of `log(exp(val1) - exp(val2))`."""
    @@ -507,61 +591,6 @@ 

    Returns

    Classes

    -
    -class TqdmHandler -
    -
    -

    Simple log handler which uses tqdm write method.

    -

    Initialize the handler.

    -

    If stream is not specified, sys.stderr is used.

    -
    - -Expand source code -Browse git - -
    class TqdmHandler(logging.StreamHandler):
    -    """Simple log handler which uses tqdm write method."""
    -
    -    def __init__(self):
    -        super().__init__()
    -
    -    def emit(self, record):
    -        msg = self.format(record)
    -        tqdm.tqdm.write(msg)
    -
    -

    Ancestors

    -
      -
    • logging.StreamHandler
    • -
    • logging.Handler
    • -
    • logging.Filterer
    • -
    -

    Methods

    -
    -
    -def emit(self, record) -
    -
    -

    Emit a record.

    -

    If a formatter is specified, it is used to format the record. -The record is then written to the stream with a trailing newline. -If -exception information is present, it is formatted using -traceback.print_exception and appended to the stream. -If the stream -has an 'encoding' attribute, it is used to determine how to do the -output to the stream.

    -
    - -Expand source code -Browse git - -
    def emit(self, record):
    -    msg = self.format(record)
    -    tqdm.tqdm.write(msg)
    -
    -
    -
    -
    class LogRepFloat (val=None, log_val=None) @@ -573,7 +602,7 @@

    Methods

    Expand source code -Browse git +Browse git
    class LogRepFloat(object):
         """Numerically stable logarithmic representation of positive float values.
    @@ -632,6 +661,9 @@ 

    Methods

    else: return self.val - other + def __rsub__(self, other): + return (-self).__radd__(other) + def __mul__(self, other): if isinstance(other, LogRepFloat): return LogRepFloat(log_val=self.log_val + other.log_val) @@ -700,7 +732,7 @@

    Instance variables

    Expand source code -Browse git +Browse git
    @property
     def val(self):
    @@ -718,7 +750,7 @@ 

    Instance variables

    diff --git a/docs/index.html b/docs/index.html index d40d0e4..6707574 100644 --- a/docs/index.html +++ b/docs/index.html @@ -5,74 +5,75 @@ Mici - Python implementations of manifold MCMC methods - - - % endif -

    ${'Namespace' if module.is_namespace else 'Package'} ${module.name}

    +

    ${'Package' if module.is_package else 'Module'} ${module.name}

    @@ -315,7 +315,7 @@
      % for c in classes:
    • -

      ${link(c)}

      + ${link(c)} <% members = c.functions(sort=sort_identifiers) + c.methods(sort=sort_identifiers) if list_class_variables_in_index: @@ -326,7 +326,14 @@ if sort_identifiers: members = sorted(members) %> - % if members: + % if members and (len(members) > 3 or len(classes) > 5): +
      + + Expand members + + ${show_column_list(members)} +
      + % elif members: ${show_column_list(members)} % endif