Skip to content

Commit 8cc1b54

Browse files
oameyeDatserisreykboerner
authored
add coupledSDEs type (#212)
* add coupledSDEs type * add CoupledSDEs docs * apply suggested format changes * add idfunc * Fix docs? * change coupled sde example to use trajectory * specify which CoupledODEs docstring * change to SciML default tolerances * classify noise * correct spelling of invertible * make noisetype field a namedtuple * make coupledSDEs an extention * export pretty print add extentention to docs clean up test file * export CoupledODEs * add CoupledODEs <-> CoupledSDEs tests * add extention to modules in makedocs * define dynamics rule sde specific * port docs into the docstring * delete ported documentation * fix small typos in docstring * add CoupledSDEs examples to docs * remove noise strength * update docs with no noise strength * add covariance kwarg and change g to kwarg * update docs * diffusion <-> covariance matrix * add noise_strength kwarg * estimate invertiability with a tolerance * move to SOSRA with non-adaptive timesteps update docs to use LambdaEM when we have covariance remove accidently comitted JuliaFormatter fix tests Set default solver to EM * Reyk's comments * implemented review comments - part 1 * revised CoupledSDEs docstring * remove broken docs link * implemented review comments - part 2 * proofread and revised CoupledSDEs docs * fixed bug that made tests fail * Update CHANGELOG.md * Update Project.toml --------- Co-authored-by: Datseris <datseris.george@gmail.com> Co-authored-by: reykboerner <reyk.boerner@reading.ac.uk>
1 parent 80a35d2 commit 8cc1b54

22 files changed

+1007
-44
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ deps/build.log
66
Manifest.toml
77
*style.jl
88
*.scss
9-
*.css
9+
*.css
10+
.vscode

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# v3.11.0
2+
3+
Brand new dynamical system `CoupledSDEs` that represents stochastic differential equations. It also comes with a dedicated documentation page.
4+
15
# v3.10.0
26

37
- OrdinaryDiffEq.jl dependency reduced to OrdinaryDiffEqTsit5.jl.

Project.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "DynamicalSystemsBase"
22
uuid = "6e36e845-645a-534a-86f2-f5d4aa5a06b4"
33
repo = "https://github.com/JuliaDynamics/DynamicalSystemsBase.jl.git"
4-
version = "3.10.1"
4+
version = "3.11.0"
55

66
[deps]
77
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
@@ -23,5 +23,12 @@ Roots = "1, 2"
2323
SciMLBase = "1.19.5, 2"
2424
StateSpaceSets = "2"
2525
Statistics = "1"
26+
StochasticDiffEq = "6.66.0"
2627
SymbolicIndexingInterface = "0.3.4"
2728
julia = "1.9"
29+
30+
[weakdeps]
31+
StochasticDiffEq = "789caeaf-c7a9-5a7d-9973-96adeb23e2a0"
32+
33+
[extensions]
34+
StochasticSystemsBase = "StochasticDiffEq"

docs/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
[deps]
22
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
3+
DiffEqNoiseProcess = "77a26b50-5914-5dd7-bc55-306e6241c503"
34
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
45
DocumenterTools = "35a29f4d-8980-5a13-9543-d66fff28ecb8"
56
DynamicalSystemsBase = "6e36e845-645a-534a-86f2-f5d4aa5a06b4"
67
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
78
StateSpaceSets = "40b095a5-5852-4c12-98c7-d43bf788e795"
9+
StochasticDiffEq = "789caeaf-c7a9-5a7d-9973-96adeb23e2a0"

docs/juliadynamics-dark.scss

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ $code-background: $codebg; // for inline code
7070
$pre-background: $codebg; // for code blocks
7171
$documenter-docstring-header-background: lighten-color($body-background-color, 0.5);
7272

73+
7374
// Sidebar
7475
$documenter-sidebar-background: darken-color($maincolor, 1.2); //background color for sidebar
7576
$documenter-sidebar-color: $text; //font color for sidebar
@@ -86,22 +87,8 @@ $input-focus-border-color: $mainwhite;
8687

8788
$documenter-docstring-shadow: 3px 3px 4px invert($shadow-color);
8889

89-
90-
91-
// Admonition stuff
92-
$admbg: lighten-color($body-background-color, 0.5);
93-
$admonition-background: (
94-
'default': $admbg, 'info': $admbg, 'success': $admbg, 'warning': $admbg,
95-
'danger': $admbg, 'compat': $admbg
96-
);
97-
$admonition-header-background: (
98-
'default': #ba3f1f, 'warning': #a88b17, 'danger': #c7524c,
99-
'success': #42ac68, 'info': #28c);
100-
101-
// Deprecations
102-
$admonition-body-color: null;
103-
$admonition-body-color: null;
104-
$admonition-header-color: null;
90+
// This line is required after https://github.com/JuliaDocs/Documenter.jl/pull/2499
91+
$admonition-default: $darkbg;
10592

10693
// All secondary themes have to be nested in a theme--$(themename) class. When Documenter
10794
// switches themes, it applies this class to <html> and then disables the primary
@@ -157,4 +144,36 @@ html.theme--#{$themename} {
157144
.hljs-subst {
158145
color: #f8f8f2;
159146
}
147+
148+
149+
150+
// fix for the settings/modal panel
151+
.modal-card-head {
152+
background-color: darken($darkbg,5);
153+
}
154+
.modal-card-body {
155+
background-color: darken($darkbg,5);
156+
}
157+
.modal-card-foot {
158+
background-color: darken($darkbg,5);
159+
}
160+
.select {
161+
> select {
162+
background-color: darken($darkbg,5);
163+
}
164+
}
165+
166+
// fix for the search panel
167+
.input {
168+
background-color: darken($darkbg,5);
169+
}
170+
.search-result-title {
171+
color: white
172+
}
173+
174+
// match the size of the light theme (additional rule
175+
// that is dark-theme specific and messing around
176+
// with the size of elements, making the size be 0,75em
177+
// only for the dark theme, no idea why)
178+
font-size: unset !important;
160179
}

docs/juliadynamics-darkdefs.scss

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ $code-background: $codebg; // for inline code
2424
$pre-background: $codebg; // for code blocks
2525
$documenter-docstring-header-background: lighten-color($body-background-color, 0.5);
2626

27+
2728
// Sidebar
2829
$documenter-sidebar-background: darken-color($maincolor, 1.2); //background color for sidebar
2930
$documenter-sidebar-color: $text; //font color for sidebar
@@ -40,22 +41,8 @@ $input-focus-border-color: $mainwhite;
4041

4142
$documenter-docstring-shadow: 3px 3px 4px invert($shadow-color);
4243

43-
44-
45-
// Admonition stuff
46-
$admbg: lighten-color($body-background-color, 0.5);
47-
$admonition-background: (
48-
'default': $admbg, 'info': $admbg, 'success': $admbg, 'warning': $admbg,
49-
'danger': $admbg, 'compat': $admbg
50-
);
51-
$admonition-header-background: (
52-
'default': #ba3f1f, 'warning': #a88b17, 'danger': #c7524c,
53-
'success': #42ac68, 'info': #28c);
54-
55-
// Deprecations
56-
$admonition-body-color: null;
57-
$admonition-body-color: null;
58-
$admonition-header-color: null;
44+
// This line is required after https://github.com/JuliaDocs/Documenter.jl/pull/2499
45+
$admonition-default: $darkbg;
5946

6047
// All secondary themes have to be nested in a theme--$(themename) class. When Documenter
6148
// switches themes, it applies this class to <html> and then disables the primary
@@ -111,4 +98,36 @@ html.theme--#{$themename} {
11198
.hljs-subst {
11299
color: #f8f8f2;
113100
}
101+
102+
103+
104+
// fix for the settings/modal panel
105+
.modal-card-head {
106+
background-color: darken($darkbg,5);
107+
}
108+
.modal-card-body {
109+
background-color: darken($darkbg,5);
110+
}
111+
.modal-card-foot {
112+
background-color: darken($darkbg,5);
113+
}
114+
.select {
115+
> select {
116+
background-color: darken($darkbg,5);
117+
}
118+
}
119+
120+
// fix for the search panel
121+
.input {
122+
background-color: darken($darkbg,5);
123+
}
124+
.search-result-title {
125+
color: white
126+
}
127+
128+
// match the size of the light theme (additional rule
129+
// that is dark-theme specific and messing around
130+
// with the size of elements, making the size be 0,75em
131+
// only for the dark theme, no idea why)
132+
font-size: unset !important;
114133
}

docs/make.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
cd(@__DIR__)
22

33
using DynamicalSystemsBase
4+
using StochasticDiffEq, DiffEqNoiseProcess # to enable extention
5+
# We need this because Documenter doesn't know where to get the docstring from otherwise
6+
StochasticSystemsBase = Base.get_extension(DynamicalSystemsBase, :StochasticSystemsBase)
47

58
pages = [
69
"index.md",
10+
"CoupledSDEs.md",
711
]
812
using DynamicalSystemsBase.SciMLBase
913

@@ -15,5 +19,5 @@ Downloads.download(
1519
include("build_docs_with_style.jl")
1620

1721
build_docs_with_style(pages,
18-
DynamicalSystemsBase, SciMLBase, StateSpaceSets;
22+
DynamicalSystemsBase, SciMLBase, StateSpaceSets, StochasticSystemsBase;
1923
)

docs/src/CoupledSDEs.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# `CoupledSDEs`
2+
3+
```@docs
4+
CoupledSDEs
5+
```
6+
7+
## [Examples defining stochastic dynamics](@id defining-stochastic-dynamics)
8+
9+
Let's look at some examples of the different types of stochastic systems that can be defined.
10+
11+
For simplicity, we choose a slow exponential growth in 2 dimensions as the deterministic dynamics `f`:
12+
```@example type
13+
using DynamicalSystemsBase, StochasticDiffEq, DiffEqNoiseProcess
14+
using CairoMakie
15+
import Random # hide
16+
Random.seed!(10) # hide
17+
f!(du, u, p, t) = du .= 1.01u # deterministic part
18+
19+
function plot_trajectory(Y, t)
20+
fig = Figure()
21+
ax = Axis(fig[1,1]; xlabel = "time", ylabel = "variable")
22+
for var in columns(Y)
23+
lines!(ax, t, var)
24+
end
25+
fig
26+
end;
27+
```
28+
29+
### Additive noise
30+
When $g(u, p, t)$ is independent of the state $u$, the noise is called additive; otherwise, it is multiplicative.
31+
We can define a simple additive noise system as follows:
32+
```@example type
33+
sde = CoupledSDEs(f!, zeros(2));
34+
```
35+
which is equivalent to
36+
```@example type
37+
t0 = 0.0; W0 = zeros(2);
38+
W = WienerProcess(t0, W0, 0.0)
39+
sde = CoupledSDEs(f!, zeros(2);
40+
noise_process=W, covariance=[1 0; 0 1], noise_strength=1.0
41+
);
42+
```
43+
We defined a Wiener process `W`, whose increments are vectors of normally distributed random numbers of length matching the output of `g`. The noise is applied element-wise, i.e., `g.*dW`. Since the noise processes are uncorrelated, meaning the covariance matrix is diagonal, this type of noise is referred to as diagonal.
44+
45+
We can sample a trajectory from this system using the `trajectory` function also used for the deterministic systems:
46+
```@example type
47+
tr = trajectory(sde, 1.0)
48+
plot_trajectory(tr...)
49+
```
50+
51+
#### Correlated noise
52+
In the case of correlated noise, the random numbers in a vector increment `dW` are correlated. This can be achieved by specifying the covariance matrix $\Sigma$ via the `covariance` keyword:
53+
```@example type
54+
ρ = 0.3
55+
Σ = [1 ρ; ρ 1]
56+
diffeq = (alg = LambaEM(), dt=0.1)
57+
sde = CoupledSDEs(f!, zeros(2); covariance=Σ, diffeq=diffeq)
58+
```
59+
Alternatively, we can parametrise the covariance matrix by defining the diffusion function $g$ ourselves:
60+
```@example type
61+
g!(du, u, p, t) = (du .= [1 p[1]; p[1] 1]; return nothing)
62+
sde = CoupledSDEs(f!, zeros(2), (ρ); g=g!, noise_prototype=zeros(2, 2))
63+
```
64+
Here, we had to provide `noise_prototype` to indicate that the diffusion function `g` will output a 2x2 matrix.
65+
66+
#### Scalar noise
67+
If all state variables are forced by the same single random variable, we have scalar noise.
68+
To define scalar noise, one has to give an one-dimensional noise process to the `noise_process` keyword of the `CoupledSDEs` constructor.
69+
```@example type
70+
t0 = 0.0; W0 = 0.0;
71+
noise = WienerProcess(t0, W0, 0.0)
72+
sde = CoupledSDEs(f!, rand(2)/10; noise_process=noise)
73+
74+
tr = trajectory(sde, 1.0)
75+
plot_trajectory(tr...)
76+
```
77+
We can see that noise applied to each variable is the same.
78+
79+
### Multiplicative and time-dependent noise
80+
In the SciML ecosystem, multiplicative noise is defined through the condition $g_i(t, u)=a_i u$. However, in the literature the name is more broadly used for any situation where the noise is non-additive and depends on the state $u$, possibly also in a non-linear way. When defining a `CoupledSDEs`, we can make the noise term time- and state-dependent by specifying an explicit time- or state-dependence in the noise function `g`, just like we would define `f`. For example, we can define a system with temporally decreasing multiplicative noise as follows:
81+
```@example type
82+
function g!(du, u, p, t)
83+
du .= u ./ (1+t)
84+
return nothing
85+
end
86+
sde = CoupledSDEs(f!, rand(2)./10; g=g!)
87+
```
88+
89+
#### Non-diagonal noise
90+
Non-diagonal noise allows for the terms to be linearly mixed (correlated) via `g` being a matrix. Suppose we have two Wiener processes and two state variables such that the output of `g` is a 2x2 matrix. Therefore, we have
91+
```math
92+
du_1 = f_1(u,p,t)dt + g_{11}(u,p,t)dW_1 + g_{12}(u,p,t)dW_2 \\
93+
du_2 = f_2(u,p,t)dt + g_{21}(u,p,t)dW_1 + g_{22}(u,p,t)dW_2
94+
```
95+
To indicate the structure that `g` should have, we must use the `noise_prototype` keyword. Let us define a special type of non-diagonal noise called commutative noise. For this we can utilize the `RKMilCommute` algorithm which is designed to utilize the structure of commutative noise.
96+
97+
```@example type
98+
σ = 0.25 # noise strength
99+
function g!(du, u, p, t)
100+
du[1,1] = σ*u[1]
101+
du[2,1] = σ*u[2]
102+
du[1,2] = σ*u[1]
103+
du[2,2] = σ*u[2]
104+
return nothing
105+
end
106+
diffeq = (alg = RKMilCommute(), reltol = 1e-3, abstol = 1e-3, dt=0.1)
107+
sde = CoupledSDEs(f!, rand(2)./10; g=g!, noise_prototype = zeros(2, 2), diffeq = diffeq)
108+
```
109+
110+
!!! warning
111+
Non-diagonal problems need specific solvers. See the [SciML recommendations](https://docs.sciml.ai/DiffEqDocs/stable/solvers/sde_solve/#sde_solve).

docs/src/assets/themes/documenter-dark.css

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/src/assets/themes/documenter-light.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/StochasticSystemsBase.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module StochasticSystemsBase
2+
3+
using DynamicalSystemsBase: DynamicalSystemsBase, SciMLBase, correct_state, CoupledODEs,
4+
CoupledSDEs, StateSpaceSets, isinplace, _delete, set_parameter!,
5+
set_state!, dynamic_rule, isdeterministic, current_state,
6+
DynamicalSystemsBase, _set_parameter!, u_modified!,
7+
additional_details, referrenced_sciml_prob, DEFAULT_DIFFEQ,
8+
SVector, SMatrix, current_parameters
9+
using SciMLBase: SDEProblem, AbstractSDEIntegrator, __init, SDEFunction, step!
10+
using StochasticDiffEq: SOSRA
11+
using LinearAlgebra
12+
13+
include("src/CoupledSDEs.jl")
14+
include("src/classification.jl")
15+
16+
export CoupledSDEs, CoupledODEs
17+
18+
end

0 commit comments

Comments
 (0)