Source code for probnum.filtsmooth.statespace.discrete.discretegaussianmodel

"""
Discrete Gauss-Markov models of the form
x_{i+1} = N(g(i, x_i), S(i))
"""

from probnum.random_variables import Normal
from probnum.filtsmooth.statespace.discrete import discretemodel


__all__ = [
    "DiscreteGaussianModel",
    "DiscreteGaussianLinearModel",
    "DiscreteGaussianLTIModel",
]


class DiscreteGaussianModel(discretemodel.DiscreteModel):
    """
    Discrete Gauss-Markov models of the form
    x_{i+1} = N(g(t_i, x_i), S(t_i)),

    Notes
    -----------
    g : dynamics
    x : state
    S : diffusion matrix

    See Also
    --------
    DiscreteGaussianLinearModel :
    DiscreteGaussianLTIModel :
    """

    def __init__(self, dynafct, diffmatfct, jacfct=None):
        """
        dynafct and jacfct have sign. (t, x, *)
        diffmatfct has sign. (t, *)
        """
        self._dynafct = dynafct
        self._diffmatfct = diffmatfct
        self._jacfct = jacfct

[docs] def dynamics(self, time, state, **kwargs): """ Evaluate g(t_i, x_i). """ dynas = self._dynafct(time, state, **kwargs) return dynas
[docs] def jacobian(self, time, state, **kwargs): """ Evaluate Jacobian, d_x g(t_i, x_i), of g(t_i, x_i) w.r.t. x_i. """ if self._jacfct is None: raise NotImplementedError("Jacobian not provided") else: return self._jacfct(time, state, **kwargs)
[docs] def diffusionmatrix(self, time, **kwargs): """ Evaluate S(t_i) """ return self._diffmatfct(time, **kwargs)
[docs] def sample(self, time, state, **kwargs): """ Samples x_{t} ~ p(x_{t} | x_{s}) as a function of t and x_s (plus additional parameters). In a discrete system, i.e. t = s + 1, s \\in \\mathbb{N} In an ODE solver setting, one of the additional parameters would be the step size. """ dynavl = self.dynamics(time, state, **kwargs) diffvl = self.diffusionmatrix(time, **kwargs) rv = Normal(dynavl, diffvl) return rv.sample()
[docs] def pdf(self, loc, time, state, **kwargs): """ Evaluates "future" pdf p(x_t | x_s) at loc. """ dynavl = self.dynamics(time, state, **kwargs) diffvl = self.diffusionmatrix(time, **kwargs) normaldist = Normal(dynavl, diffvl) return normaldist.pdf(loc)
@property def ndim(self): return len(self.diffusionmatrix(0.0)) class DiscreteGaussianLinearModel(DiscreteGaussianModel): """ Linear version. g(t, x(t)) = G(t) x(t) + z(t). """ def __init__(self, dynamatfct, forcefct, diffmatfct): def dynafct(t, x, **kwargs): return dynamatfct(t, **kwargs) @ x + forcefct(t, **kwargs) def jacfct(t, x, **kwargs): return dynamatfct(t, **kwargs) super().__init__(dynafct, diffmatfct, jacfct) self.forcefct = forcefct
[docs] def dynamicsmatrix(self, time, **kwargs): """ Convenient access to dynamics matrix (alternative to "jacobian"). """ return self.jacobian(time, None, **kwargs)
[docs] def force(self, time, **kwargs): return self.forcefct(time, **kwargs)
[docs]class DiscreteGaussianLTIModel(DiscreteGaussianLinearModel): """ Discrete Gauss-Markov models of the form x_{i+1} = N(G x_i + z, S), """ def __init__(self, dynamat, forcevec, diffmat): super().__init__( lambda t, **kwargs: dynamat, lambda t, **kwargs: forcevec, lambda t, **kwargs: diffmat, )