Source code for aleatory.processes.analytical.brownian_excursion

"""
Brownian Excursion
"""

import numpy as np

from aleatory.processes import BrownianBridge
from aleatory.utils.utils import check_positive_integer
from scipy.stats import chi


[docs]class BrownianExcursion(BrownianBridge): r""" Brownian Excursion ================== .. image:: ../_static/brownian_excursion_drawn.png Notes _____ A Brownian excursion process, is a Wiener process (or Brownian motion) conditioned to be positive and to take the value 0 at time 1. Alternatively, it can be defined as a Brownian Bridge process conditioned to be positive. Constructor, Methods, and Attributes ------------------------------------ """
[docs] def __init__(self, T=1.0, rng=None): """ :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 """ super().__init__(T=T, rng=rng) if self.T == 1.0: self.name = "Brownian Excursion" else: self.name = f"Brownian Excursion defined on [0,{self.T}]" self.description = "Brownian Excursion" self._brownian_bridge = BrownianBridge(initial=0.0, end=0.0, T=T, rng=rng) self.n = None self.times = None
def __str__(self): return "Brownian Excursion" def __repr__(self): return "BrownianExcursion" def _sample_brownian_excursion(self, n): """Generate a random sample of the Brownian Excursion.""" check_positive_integer(n) self.n = n self.times = np.linspace(0, self.T, n) bridge_path = self._brownian_bridge.sample(n) id_bridge_min = np.argmin(bridge_path) excursion_path = [ bridge_path[(id_bridge_min + idx) % (n - 1)] - bridge_path[id_bridge_min] for idx in range(n) ] return np.asarray(excursion_path) def _sample_brownian_excursion_at(self, times): self.times = times bridge_path = self._brownian_bridge.sample_at(times) id_bridge_min = np.argmin(bridge_path) n = len(times) excursion_path = [ bridge_path[(id_bridge_min + idx) % (n - 1)] - bridge_path[id_bridge_min] for idx in range(n) ] return np.asarray(excursion_path) def sample(self, n): return self._sample_brownian_excursion(n) def sample_at(self, times): return self._sample_brownian_excursion_at(times) def _process_expectation(self, times=None): if times is None: times = self.times return np.sqrt(times * (self.T - times) / self.T) * chi.mean(df=3) def _process_variance(self, times=None): if times is None: times = self.times return times * ((self.T - times) / self.T) * chi.var(df=3) def get_marginal(self, t): scale = np.sqrt(t * (self.T - t) / self.T) marginal = chi(df=3, scale=scale) return marginal
if __name__ == "__main__": import matplotlib.pyplot as plt qs = "https://raw.githubusercontent.com/quantgirluk/matplotlib-stylesheets/main/quant-pastel-light.mplstyle" plt.style.use(qs) for p, cm in [ (BrownianExcursion(), "twilight"), (BrownianExcursion(T=2.0), "viridis"), (BrownianExcursion(T=10.0), "Accent"), ]: # p.draw(n=200, N=100, figsize=(12, 7), style=qs, colormap=cm, envelope=False) p.plot_mean_variance(times=np.linspace(0, 1, 100)) # # p = BrownianExcursion() # p.plot(n=500, N=5, figsize=(12, 7), style=qs)