On s’intéresse ici à l’équation différentielle stochastique:
\[\text{d}X(t) = \alpha X(t)(1 - X(t)^2) \text{d} s + \sigma \sqrt{1 + X(t)^2}\text{d} B(t),~X_0 = x_0.\]
On remarquera que la fonction \(f(x) = \alpha x(1 - x^2)\) satisfait la relation: \[f(x) = \nabla_x u(x)\] où \(u(x)\) est la fonction de potentiel \(u(x) = \alpha(\frac{x^2}{2} - \frac{x^4}{4})\).
Pour \(\alpha = 1\), ce potentiel est le suivant:
tibble(x = seq(-2, 2, length.out = 501)) %>%
ggplot(aes(x = x)) +
stat_function(fun = get_potential) +
labs(y = "u(x)", title = "Double peak potential")
Ainsi, la direction préférentielle de la trajectoire est donnée par le gradient de cette fonction. On peut en déduire que les points \(-1\) et 1 seront deux points attractifs.
library(tidyverse)
# library(ggplot2); library(purrr); library(dplyr)
# are enough if tidyverse doesn't work
Nous allons maintenant coder en R
une fonction qui permet de simuler des trajectoires de cette EDS à paramètres et temps de simulation fixés.
On commence par coder les fonctions de dérive et de diffusion, en explicitant la dépendance en les paramètres:
get_drift <- function(x, alpha){
alpha * x * (1 - x^2)
}
get_diffusion <- function(x, sigma){
sigma * sqrt(1 + x^2)
}
Ensuite on peut créer la fonction de simulation, qui dépendra de \(x_0\), \(\alpha\) et \(\sigma\).
Remarque: Comme sortie de la fonction, on choisit un tibble
qui conserve les positions simulées ainsi que toutes les informations de simulation. Cela permettra de faciliter les représentations graphiques plus tard:
simulate_double_peak_sde <- function(times, # Simulation times
x0, alpha, sigma) # Simulation parameters
{
n_points <- length(times) # Number of points
trajectory <- rep(NA, n_points) # Initialization of output trajectory
trajectory[1] <- x0 # First position
for(k in 2:n_points){ # Iteration
h <- times[k] - times[k - 1] # Time step (must be small)
euler_mean <- trajectory[k - 1] + # x
get_drift(trajectory[k - 1], alpha) * h # drift(x) * h
euler_variance <- get_diffusion(trajectory[k - 1], sigma)^2 * h
trajectory[k] <- rnorm(n = 1, # 1 gaussian sample
mean = euler_mean, # Mean
sd = sqrt(euler_variance) # Standard deviation
)
}
# Return tibble to ease later visualization
tibble(t = times,
x_t = trajectory,
x0 = x0,
alpha = alpha,
sigma = sigma)
}
On peut ainsi simuler une première trajectoire, pour \(x_0 = 0,~\alpha = 1,~\sigma = 0.1\) et la représenter graphiquement:
set.seed(123) # For reproducibility
my_times <- seq(0, 15, by = 0.01) # Vecteur 0, 0.01, 0.02,...., 9.99, 10
simulate_double_peak_sde(times = my_times, # Simulation
x0 = 0, alpha = 1, sigma = 0.1) %>% # Then
ggplot(aes(x = t, y = x_t)) + # plot it
geom_path() +
labs(x = "Time", y = "X(t)")
Bien sûr, cette trajectoire n’est qu’une réalisation du processus, on peut regarder 30 réalisations:
set.seed(123) # For reproducibility
rerun(10, # Rerun 30 times the simulations
simulate_double_peak_sde(times = my_times, # Simulation
x0 = 0, alpha = 1, sigma = 0.1)) %>% # Then
bind_rows(.id = "Replicate") %>% # Aggregate it in a single tibble, keeping
# track of the replicate identity
ggplot(aes(x = t, y = x_t)) + # plot it
geom_path(aes(group = Replicate), alpha = 0.5) + # Do a track per replicate
labs(x = "Time", y = "X(t)",
title = expression("10 realizations for "~x(0)==0~alpha==1~sigma==0.1))
On peut ainsi voir ici clairement apparaître nos deux points d’attractions. On peut se demander si on peut passer de \(-1\) à 1?
On peut regarder les variations des trajectoires selon les paramètres.
Ici les différents paramètres sont \(x_0\), \(\alpha\) et \(\sigma\). On voudrait tester \(x_0 = \lbrace -2, 0, 2\rbrace,~ \alpha = \lbrace 1, 5 \rbrace, \sigma = \lbrace 0.1, 0.5\rbrace\), en testant toutes les combinaisons possibles (ici 12).
Une manière concise et rapide de faire cela en R
est la fonction pmap_dfr
du package purrr
, qui prend en entrée une tibble
dont chaque ligne et renvoie un grand tibble
concaténant tous les résulats.
La première chose à faire est de créer le tableau des combinaisons de paramètres possibles, on utilise pour cela la fonction expand.grid
:
# IMPORTANT: Columns names must be the same as argument names of the
# simulation_double_peak_sde function
parameters_list <- expand.grid(x0 = c(-2, 0, 2), # x0s values
alpha = c(1, 3),
sigma = c(0.1, 0.5)) %>% # Creates the design grid
as_tibble() # Turns it into a tibble
Le tableau obtenu est le suivant:
# A tibble: 12 x 3
x0 alpha sigma
<dbl> <dbl> <dbl>
1 -2 1 0.1
2 0 1 0.1
3 2 1 0.1
4 -2 3 0.1
5 0 3 0.1
6 2 3 0.1
7 -2 1 0.5
8 0 1 0.5
9 2 1 0.5
10 -2 3 0.5
11 0 3 0.5
12 2 3 0.5
Dans le code suivant, on teste les 12 combinaisons possibles. Pour chaque combinaison, on fait une simulation. Moralement, pmap_dfr
fait une boucle sur les 12 lignes du tableau précédent en concaténant le résultat dans un tibble
.
pmap_dfr(.l = parameters_list, # List of parameters
.f = simulate_double_peak_sde, # Function to apply
times = my_times # Additionnal arguments
)
Comme on veut 10 simulations par jeu de paramètres, il suffit de répéter 10 fois ce code grâce à rerun
et d’aggéger les résultats dans un tibble
.
set.seed(123) # For reproducibility
all_simulations <- rerun(10, # rerun 10 times
pmap_dfr(.l = parameters_list, # Same code as above
.f = simulate_double_peak_sde,
times = my_times)
) %>% # Then
bind_rows(.id = "Replicate") # Binds it a tibble, keeping track of replicate
Le résultat est un tibble
de taille conséquente!
# A tibble: 180,120 x 6
Replicate t x_t x0 alpha sigma
<chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 0 -2 -2 1 0.1
2 1 0.01 -1.95 -2 1 0.1
3 1 0.02 -1.90 -2 1 0.1
4 1 0.03 -1.82 -2 1 0.1
5 1 0.04 -1.78 -2 1 0.1
6 1 0.05 -1.73 -2 1 0.1
7 1 0.06 -1.67 -2 1 0.1
8 1 0.07 -1.63 -2 1 0.1
9 1 0.08 -1.62 -2 1 0.1
10 1 0.09 -1.61 -2 1 0.1
# … with 180,110 more rows
On peut maintenant représenter graphiquement les différentes trajectoires simulées:
all_simulations %>% # First we rename alphas and sigmas for nice rendering
mutate(alpha = paste("alpha ==", alpha),
sigma = paste("sigma ==", sigma)) %>%
ggplot(aes(x = t, y = x_t)) + # Usual ggplot
geom_path(aes(group = interaction(Replicate, x0), # Group trajectories
color = factor(x0))) + # Color depending on starting point
facet_wrap(.~ alpha + sigma, # One graph per combination alpha/sigma
labeller = label_parsed) + # Turns names in maths
labs(x = "Time", y = "X(t)", color = "X(0)", # Labelling axis
title = "Double peak potential SDE")
Ainsi, on peut constater que les trajectoires peuvent passer d’un mode à l’autre. La fréquence de ces passages est fortement dépendante du rapport de force entre la dérive et la diffusionc autour des points d’attraction, soit ici:
\[\frac{\alpha x(1 - x^2)}{\sigma\sqrt{1 + x^2}}.\] Ce rapport essentiel dans la théorie des EDS est parfois appelé rapport signal sur bruit.