Source code for stochastic.processes.continuous.brownian_meander

"""Brownian meander."""
import numpy as np

from stochastic.processes.continuous import BrownianBridge
from stochastic.utils.validation import check_nonnegative_number


[docs]class BrownianMeander(BrownianBridge): r"""Brownian meander process. .. image:: _static/brownian_meander.png :scale: 50% A Brownian motion conditioned such that the process is nonnegative. Generated using method by * Williams, David. "Decomposing the Brownian path." Bulletin of the American Mathematical Society 76, no. 4 (1970): 871-873. * Imhof, J-P. "Density factorizations for Brownian motion, meander and the three-dimensional Bessel process, and applications." Journal of Applied Probability 21, no. 3 (1984): 500-510. :param float t: the right hand endpoint of the time interval :math:`[0,t]` for the process :param numpy.random.Generator rng: a custom random number generator """ def __init__(self, t=1, rng=None): super().__init__(t=t, rng=rng) def __str__(self): return "Brownian meander" def __repr__(self): return "BrownianMeander()" def _sample_brownian_meander(self, n, b=None): """Generate a Brownian meander realization. Williams, 1970, or Imhof, 1984. """ if b is None: b = np.sqrt(2 * self.t * self.rng.exponential()) else: check_nonnegative_number(b, "Right endpoint") bridge_1 = self._sample_brownian_bridge(n) bridge_2 = self._sample_brownian_bridge(n) bridge_3 = self._sample_brownian_bridge(n) return np.sqrt( (b * self.times(n) / self.t + bridge_1) ** 2 + bridge_2**2 + bridge_3**2 ) def _sample_brownian_meander_at(self, times, b=None): """Generate a Brownian meander realization. Williams, 1970, or Imhof, 1984. """ if b is None: b = np.sqrt(2 * times[-1] * self.rng.exponential()) else: check_nonnegative_number(b, "Right endpoint") bridge_1 = self._sample_brownian_bridge_at(times) bridge_2 = self._sample_brownian_bridge_at(times) bridge_3 = self._sample_brownian_bridge_at(times) return np.sqrt( (b * times / times[-1] + bridge_1) ** 2 + bridge_2**2 + bridge_3**2 )
[docs] def sample(self, n, b=None): r"""Generate a realization. :param int n: the number of increments to generate :param float b: the nonnegative right hand endpoint of the meander. If not provided, one is randomly selected from a :math:`\sqrt{2E}` random variable where :math:`E` is exponential. """ return self._sample_brownian_meander(n, b)
[docs] def sample_at(self, times, b=None): r"""Generate a realization using specified times. :param times: a vector of increasing time values at which to generate the realization :param float b: the right endpoint value for :py:attr:`times` [-1]. If not provided, one is randomly selected from a :math:`\sqrt{2tE}` random variable where :math:`E` is exponential and :math:`t` is :py:attr:`times` [-1]. """ return self._sample_brownian_meander_at(times, b)