Pychastic 0.1 reference¶
SDE problem setting¶
- class pychastic.sde_problem.SDEProblem(a, b, x0, tmax, exact_solution=None)¶
Stores a vector stochastic differential equation of the form: \(d\mathbf{x} = \mathbf{a(x)} dt + \mathbf{B(x)} d\mathbf{w}\), where
aandBare vector of drifts and matrix of noise coefficients.avector andBmatrix should be formatted such thatx = x + a(x)*dt + np.dot(B(x),dw)is a valid code fragment (note
Bhas as many columns as there are noise terms).- Parameters
a (callable) – Function describing drift term of the equation, should return np.array of length
dimension.b (callable) – Function describing noise term of the equation, should return np.array of size
(dimension,noiseterms).dimension (int) – Dimension of the space in which \(d\mathbf{x}\) sits.
noiseterms (int) – Dimension of the space in which \(d\mathbf{w}\) sits.
x0 (np.array) – Initial value of the stochastic process.
tmax (float) – Time at which integration should stop.
Example
>>> import numpy as np >>> problem = pychastic.sde_problem.VectorSDEProblem(lambda x: np.array([1,1]), lambda x: np.array([[1,0.5],[0.5,1]]), 2, 2, np.array([1.5,0.5]), 1)
SDE solvers¶
- class pychastic.sde_solver.SDESolver(scheme='euler', dt=0.01, dt_adapting_factor=10, min_dt=None, max_dt=None, error_terms=1, target_mse_density=0.01, adaptive=False)¶
Produces realisations of stochastic process to
solvemethod. Controls numerical integration features via attributes.- Parameters
scheme ({'euler', 'milstein', 'wagner_platen'}, default: 'euler') – Type of scheme used for integration.
dt (float) – Step size in fixed-step integration.
- solve(problem, seed=0, chunk_size=1, chunks_per_randomization=None, progress_bar=True)¶
Solves SDE problem given by
problem. Integration parameters are controlled by attribues ofSDESolverobject.- Parameters
problem (SDEProblem) – (Vector) SDE problem to be solved.
seed (int, optional) – value of seed for PRNG.
chunk_size (int or None, optional) – Make steps in solver in chunks of chunk_size steps. If chunk_size = n then value at every nth step is returned. If None then maximal size of chunk is used only final value is returned.
chunks_per_randomization (int or None, optional) – Sample wiener trajectories once per chunks_per_randomization chunks. If chunks_per_randomization = n then PRNG runs at every nth chunk. If None, PRNG runs once, at beginning of simulation. Smaller values lead to less memory usage. Larger values increase speed.
progress_bar (True, False) – Display tqdm style progress bar during computation.
- Returns
Under following keys in returned dict you’ll find:
time_values– (steps,) jnp.array containing timestamps coresponding to each trajectory.solution_values– (steps, problem_dimension) jnp.array containing values of integrated SDE.wiener_values– (steps, noise_dimension) jnp.array containing values of Wiener processes driving the SDE.
- Return type
dict
Example
>>> import pychastic >>> import jax.numpy as jnp >>> solver = pychastic.sde_solver.SDESolver() >>> problem = pychastic.sde_problem.SDEProblem( ... lambda x: jnp.array([1/(2*x[0]),0]), # [1/2r,0] ... lambda x: jnp.array([ ... [jnp.cos(x[1]),jnp.sin(x[1])], # cos phi, sin phi ... [-jnp.sin(x[1])/x[0],jnp.cos(x[1])/x[0]] # -sin phi / r, cos phi / r ... ]), ... x0 = jnp.array([1.0,0.0]), # r=1.0, phi=0.0 ... tmax=0.02 ... ) >>> solution = solver.solve(problem) >>> (r,phi) = (solution["solution_values"][-1,:]) >>> compare = {"integrated":(r*jnp.array([jnp.cos(phi),jnp.sin(phi)])).T,"exact":solution["wiener_values"][-1,:]+problem.x0} >>> print(compare["integrated"],compare["exact"])
- solve_many(problem: pychastic.sde_problem.SDEProblem, n_trajectories=1, step_post_processing=None, seed=0, chunk_size=1, chunks_per_randomization=None, progress_bar=True)¶
Solves SDE problem given by
problem. Integration parameters are controlled by attribues ofSDESolverobject.- Parameters
problem (SDEProblem) – (Vector) SDE problem to be solved.
n_trajectories (int, optional) – Number of sample paths to generate
step_post_processing (callable) – (Advanced) Function of with call signature f(x) returning canonical coordinates of x. Usefull when simulating process on a manifold with does not have covering map from \(\mathbb{R}^n\) such as \(SO(3)\). Post processing function has to jit with jax. To deal with branch cuts and such refer to jax.lax.cond.
seed (int, optional) – value of seed for PRNG.
chunk_size (int or None, optional) – Make steps in solver in chunks of chunk_size steps. If chunk_size = n then value at every nth step is returned. If None then maximal size of chunk is used only final value is returned.
chunks_per_randomization (int or None, optional) – Sample wiener trajectories once per chunks_per_randomization chunks. If chunks_per_randomization = n then PRNG runs at every nth chunk. If None, PRNG runs once, at beginning of simulation. Smaller values lead to less memory usage. Larger values increase speed.
progress_bar (True, False) – Display tqdm style progress bar during computation.
- Returns
Under following keys in returned dict you’ll find:
time_values– (n_trajectories, steps) jnp.array containing timestamps coresponding to each trajectory.solution_values– (n_trajectories, steps, problem_dimension) jnp.array containing values of integrated SDE.wiener_values– (n_trajectories, steps, noise_dimension) jnp.array containing values of Wiener processes driving the SDE.
- Return type
dict
Example
>>> import pychastic >>> import jax.numpy as jnp >>> solver = pychastic.sde_solver.SDESolver() >>> problem = pychastic.sde_problem.SDEProblem( ... lambda x: jnp.array([1/(2*x[0]),0]), # [1/2r,0] ... lambda x: jnp.array([ ... [jnp.cos(x[1]),jnp.sin(x[1])], # cos phi, sin phi ... [-jnp.sin(x[1])/x[0],jnp.cos(x[1])/x[0]] # -sin phi / r, cos phi / r ... ]), ... x0 = jnp.array([1.0,0.0]), # r=1.0, phi=0.0 ... tmax=0.02 ... ) >>> solution = solver.solve_many(problem,n_trajectories = 100) >>> solution_principal = solver.solve_many(problem,step_post_processing = lambda x : jnp.fmod(x,2*jnp.pi),n_trajectories = 100) >>> (r,phi) = (solution["solution_values"][:,-1,:]).transpose() >>> compare = {"integrated":(r*jnp.array([jnp.cos(phi),jnp.sin(phi)])).T,"exact":solution["wiener_values"][:,-1,:]+problem.x0} >>> print(compare["integrated"][0],compare["exact"][0])
Expected values of principle integrals¶
- pychastic.wiener_integral_moments.E(alpha) numpy.polynomial.polynomial.Polynomial¶
Calculate expected value of mixed winer integral E(I_alpha). Entries in multindex alpha coresspond to:
0 - time dimension
positive integer - wiener dimension
- Parameters
alpha (array of integers) –
- Returns
polynomial in time
- Return type
numpy.polynomial.Polynomial
Example
Compute expected value of integral of Wiener process with respect to itself.
>>> import pychastic.wiener_integral_moments >>> pychastic.wiener_integral_moments.E([1,1]) # returns 0
- pychastic.wiener_integral_moments.E2(alpha, beta=None) numpy.polynomial.polynomial.Polynomial¶
Calculate expected value of a product of two mixed winer integrals E(I_alpha*I_beta) or E(I_alpha^2) if beta=None. Entries in multindices alpha and beta coresspond to:
0 - time dimension
positive integer - wiener dimension
- Parameters
alpha (array of integers) – multindex of the first integral
beta (array of integers or None) – multindex of the second integral
- Returns
polynomial in time
- Return type
numpy.polynomial.Polynomial
Example
Compute variance of integral of Wiener process with respect to itself on interval [0,1].
>>> import pychastic.wiener_integral_moments >>> mean = pychastic.wiener_integral_moments.E([1,1])(1) >>> mean_square = pychastic.wiener_integral_moments.E2([1,1])(1) >>> print(f'Variance is {mean_square - mean**2}') # prints 0.5