Skip to content

Commit 22ab624

Browse files
author
fchen121
committed
Implement change of variables for sde
1 parent 86411c2 commit 22ab624

File tree

2 files changed

+49
-22
lines changed

2 files changed

+49
-22
lines changed

src/systems/diffeqs/basic_transformations.jl

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,10 @@ function changeofvariables(sys::System, iv, forward_subs, backward_subs; simplif
141141
return new_sys
142142
end
143143

144-
function change_of_variable_SDE(sys::System, iv, nvs, forward_subs, backward_subs; simplify=false, t0=missing)
144+
function change_of_variable_SDE(sys::System, iv, forward_subs, backward_subs; simplify=true, t0=missing)
145+
sys = mtkcompile(sys)
145146
t = iv
147+
@brownian B
146148

147149
old_vars = first.(backward_subs)
148150
new_vars = last.(forward_subs)
@@ -151,13 +153,17 @@ function change_of_variable_SDE(sys::System, iv, nvs, forward_subs, backward_sub
151153
# use: dY = (∂f/∂t + μ∂f/∂x + (1/2)*σ^2*∂2f/∂x2)dt + σ∂f/∂xdW
152154
old_eqs = equations(sys)
153155
old_noise = ModelingToolkit.get_noise_eqs(sys)
156+
157+
# Is there a function to find partial derivative?
154158
∂f∂t = Symbolics.derivative( first.(forward_subs), t )
155-
∂f∂x = [Symbolics.derivative( first(f_sub), old_var )]
156-
∂2f∂x2 = Symbolics.derivative( ∂f∂x, old_vars )
159+
∂f∂t = [substitute(f_t, Differential(t)(old_var) => 0) for (f_t, old_var) in zip(∂f∂t, old_vars)]
160+
161+
∂f∂x = [Symbolics.derivative( first(f_sub), old_var ) for (f_sub, old_var) in zip(forward_subs, old_vars)]
162+
∂2f∂x2 = Symbolics.derivative.( ∂f∂x, old_vars )
157163
new_eqs = Equation[]
158164

159-
for (new_var, eq, noise, nv, first, second, third) in zip(new_vars, old_eqs, old_noise, nvs, ∂f∂t, ∂f∂x, ∂2f∂x2)
160-
ex = first + eq.rhs * second + 1/2 * noise^2 * third + noise*second*nv
165+
for (new_var, eq, noise, first, second, third) in zip(new_vars, old_eqs, old_noise, ∂f∂t, ∂f∂x, ∂2f∂x2)
166+
ex = first + eq.rhs * second + 1/2 * noise^2 * third + noise*second*B
161167
for eqs in old_eqs
162168
ex = substitute(ex, eqs.lhs => eqs.rhs)
163169
end
@@ -169,9 +175,28 @@ function change_of_variable_SDE(sys::System, iv, nvs, forward_subs, backward_sub
169175
push!(new_eqs, Differential(t)(new_var) ~ ex)
170176
end
171177

172-
@named new_sys = System(new_eqs;
178+
defs = get_defaults(sys)
179+
new_defs = Dict()
180+
for f_sub in forward_subs
181+
ex = substitute(first(f_sub), defs)
182+
if !ismissing(t0)
183+
ex = substitute(ex, t => t0)
184+
end
185+
new_defs[last(f_sub)] = ex
186+
end
187+
for para in parameters(sys)
188+
if haskey(defs, para)
189+
new_defs[para] = defs[para]
190+
end
191+
end
192+
193+
@named new_sys = System(new_eqs, t;
194+
defaults=new_defs,
173195
observed=vcat(observed(sys),first.(backward_subs) .~ last.(backward_subs))
174196
)
197+
if simplify
198+
return mtkcompile(new_sys)
199+
end
175200
return new_sys
176201
end
177202

test/changeofvariables.jl

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ using Test, LinearAlgebra
55
# Change of variables: z = log(x)
66
# (this implies that x = exp(z) is automatically non-negative)
77
@independent_variables t
8-
# @variables z(t)[1:2, 1:2]
9-
# D = Differential(t)
10-
# eqs = [D(D(z)) ~ ones(2, 2)]
11-
# @mtkcompile sys = System(eqs, t)
12-
# @test_nowarn ODEProblem(sys, [z => zeros(2, 2), D(z) => ones(2, 2)], (0.0, 10.0))
8+
@variables z(t)[1:2, 1:2]
9+
D = Differential(t)
10+
eqs = [D(D(z)) ~ ones(2, 2)]
11+
@mtkcompile sys = System(eqs, t)
12+
@test_nowarn ODEProblem(sys, [z => zeros(2, 2), D(z) => ones(2, 2)], (0.0, 10.0))
1313

1414
@parameters α
1515
@variables x(t)
@@ -94,17 +94,19 @@ new_sol = solve(new_prob, Tsit5())
9494
# @test isapprox( new_sol[x[1],end], sol[x[1],end], rtol=1e-4)
9595

9696
# Change of variables for sde
97-
# @independent_variables t
98-
# @brownian B
99-
# @parameters μ σ
100-
# @variables x(t) y(t)
101-
# D = Differential(t)
102-
# eqs = [D(x) ~ μ*x + σ*x*B]
97+
@independent_variables t
98+
@brownian B
99+
@parameters μ σ
100+
@variables x(t) y(t)
101+
D = Differential(t)
102+
eqs = [D(x) ~ μ*x + σ*x*B]
103103

104-
# def = [x=>0., μ => 2., σ=>1.]
105-
# @mtkcompile sys = System(eqs, t; defaults=def)
106-
# forward_subs = [log(x) => y]
107-
# backward_subs = [x => exp(y)]
108-
# new_sys = change_of_variable_SDE(sys, t, [B], forward_subs, backward_subs)
104+
def = [x=>0., μ => 2., σ=>1.]
105+
@mtkcompile sys = System(eqs, t; defaults=def)
106+
forward_subs = [log(x) => y]
107+
backward_subs = [x => exp(y)]
108+
new_sys = change_of_variable_SDE(sys, t, forward_subs, backward_subs)
109+
@test equations(new_sys)[1] == (D(y) ~ μ - 1/2*σ^2)
110+
@test ModelingToolkit.get_noise_eqs(new_sys)[1] === ModelingToolkit.value(σ)
109111

110112

0 commit comments

Comments
 (0)