Skip to content

Commit d115edd

Browse files
author
xiaoming
committed
experimental feature to support delaycoevolve
1 parent ed80ad2 commit d115edd

File tree

6 files changed

+168
-4
lines changed

6 files changed

+168
-4
lines changed

Project.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
1818
UnPack = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
1919

2020
[compat]
21-
Catalyst = "12.0"
21+
Catalyst = "12.0"
2222
DataStructures = "0.17, 0.18"
2323
DiffEqBase = "6.45"
2424
DocStringExtensions = "0.8, 0.9"
@@ -34,6 +34,9 @@ julia = "1.6, 1.7, 1.8"
3434
[extras]
3535
Catalyst = "479239e8-5488-4da2-87a7-35f2df7eef83"
3636
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
37+
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
38+
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
39+
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
3740

3841
[targets]
3942
test = ["Test"]

src/DelaySSAToolkit.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ import JumpProcesses: AbstractJumpAggregator, AbstractJump, JumpProblem, Constan
1414
# Dependency graph functions
1515
import JumpProcesses: make_dependency_graph, add_self_dependencies!, var_to_jumps_map
1616
# other functions
17-
import JumpProcesses: using_params, get_jump_info_fwrappers, isinplace_jump, extend_problem,
18-
build_variable_callback, get_num_majumps, num_crjs, num_bndvrjs, supports_variablerates
17+
import JumpProcesses: using_params, get_jump_info_fwrappers, isinplace_jump, extend_problem, build_variable_callback, get_num_majumps, num_crjs
18+
19+
# VariableRateJump
20+
import JumpProcesses: isbounded, num_bndvrjs, supports_variablerates, haslrate, nullrate
1921

2022
# using Catalyst
2123
using ModelingToolkit

src/delayproblem.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ function DelayJumpProblem(prob, aggregator::AbstractDelayAggregatorAlgorithm,
221221
typeof(jumps.regular_jump), typeof(maj), typeof(delayjumpsets),
222222
typeof(de_chan0), typeof(rng), typeof(solkwargs)}(new_prob, aggregator, disc_agg,
223223
callbacks,
224-
jumps.variable_jumps,
224+
cont_agg,
225225
jumps.regular_jump, maj,
226226
delayjumpsets, de_chan0,
227227
save_delay_channel, rng, solkwargs)

test/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
[deps]
22
Catalyst = "479239e8-5488-4da2-87a7-35f2df7eef83"
33
JumpProcesses = "ccbc3e58-028d-4f4c-8cd5-9ae44345cda5"
4+
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
5+
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
46
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
57
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
68
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

test/hawkes_delay_test.jl

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
using DelaySSAToolkit, JumpProcesses, OrdinaryDiffEq, Statistics
2+
using Test
3+
using Random
4+
rng = MersenneTwister(12345)
5+
delay = 20.0
6+
function reset_history!(h; start_time = nothing)
7+
@inbounds for i in 1:length(h)
8+
h[i] = eltype(h)[]
9+
end
10+
nothing
11+
end
12+
13+
function empirical_rate(sol, agg)
14+
if typeof(agg) <: DelayCoevolve
15+
return (sol(sol.t[end]) - sol(sol.t[1] + delay)) / (sol.t[end] - sol.t[1] - delay)
16+
else
17+
return (sol(sol.t[end]) - sol(sol.t[1])) / (sol.t[end] - sol.t[1])
18+
end
19+
end
20+
21+
function hawkes_rate(i::Int, g, h)
22+
function rate(u, p, t)
23+
λ, α, β = p
24+
x = zero(typeof(t))
25+
for j in g[i]
26+
for _t in reverse(h[j])
27+
λij = α * exp(-β * (t - _t))
28+
if λij 0
29+
break
30+
end
31+
x += λij
32+
end
33+
end
34+
return λ + x
35+
end
36+
return rate
37+
end
38+
39+
function hawkes_jump(i::Int, g, h, agg; uselrate = true)
40+
rate = hawkes_rate(i, g, h)
41+
urate = rate
42+
if uselrate
43+
lrate(u, p, t) = p[1]
44+
rateinterval = (u, p, t) -> begin
45+
_lrate = lrate(u, p, t)
46+
_urate = urate(u, p, t)
47+
return _urate == _lrate ? typemax(t) : 1 / (2 * _urate)
48+
end
49+
else
50+
lrate = nothing
51+
rateinterval = (u, p, t) -> begin
52+
_urate = urate(u, p, t)
53+
return 1 / (2 * _urate)
54+
end
55+
end
56+
if typeof(agg) <: DelayCoevolve
57+
affect! = (integrator) -> begin
58+
push!(h[i], integrator.t)
59+
integrator.u[i] += 0
60+
end
61+
else
62+
affect! = (integrator) -> begin
63+
push!(h[i], integrator.t)
64+
integrator.u[i] += 1
65+
end
66+
end
67+
return VariableRateJump(rate, affect!; lrate, urate, rateinterval)
68+
end
69+
70+
function hawkes_jump(u, g, h, agg; uselrate = true)
71+
return [hawkes_jump(i, g, h, agg; uselrate) for i in 1:length(u)]
72+
end
73+
74+
function hawkes_problem(p, agg::DelayCoevolve; u = [0.0], tspan = (0.0, 50.0),
75+
save_positions = (false, true),
76+
g = [[1]], h = [[]], uselrate = true)
77+
dprob = DiscreteProblem(u, tspan, p)
78+
jumps = JumpSet(hawkes_jump(u, g, h, agg; uselrate)...)
79+
de_chan0 = [[]]
80+
delay_trigger = Dict(1=>[1=>delay]) # add a delay of 1.0 to the first jump
81+
delay_complete = Dict(1=>[1=>1]) # complete the delay will duplicate 1 product
82+
delay_interrupt = Dict()
83+
delayjumpset = DelayJumpSet(delay_trigger, delay_complete, delay_interrupt)
84+
jprob = DelayJumpProblem(dprob, agg, jumps, delayjumpset, de_chan0; dep_graph = g, save_positions, rng)
85+
return jprob
86+
end
87+
88+
function f!(du, u, p, t)
89+
du .= 0
90+
nothing
91+
end
92+
93+
function hawkes_problem(p, agg; u = [0.0], tspan = (0.0, 50.0),
94+
save_positions = (false, true),
95+
g = [[1]], h = [[]], kwargs...)
96+
oprob = ODEProblem(f!, u, tspan, p)
97+
jumps = hawkes_jump(u, g, h, agg)
98+
jprob = JumpProblem(oprob, agg, jumps...; save_positions, rng)
99+
return jprob
100+
end
101+
102+
function expected_stats_hawkes_problem(p, tspan, agg)
103+
if typeof(agg) <: DelayCoevolve
104+
T = tspan[end] - tspan[1] + delay
105+
# stepper = SSAStepper()
106+
else
107+
T = tspan[end] - tspan[1]
108+
end
109+
λ, α, β = p
110+
γ = β - α
111+
κ = β / γ
112+
= λ * κ
113+
# Equation 21
114+
# J. Da Fonseca and R. Zaatour,
115+
# “Hawkes Process: Fast Calibration, Application to Trade Clustering and Diffusive Limit.”
116+
# Rochester, NY, Aug. 04, 2013. doi: 10.2139/ssrn.2294112.
117+
Varλ = (Eλ * (T * κ^2 + (1 - κ^2) * (1 - exp(-T * γ)) / γ)) / (T^2)
118+
return Eλ, Varλ
119+
end
120+
121+
u0 = [0.0]
122+
p = (0.5, 0.5, 2.0)
123+
tspan = (0.0, 250.0)
124+
g = [[1]]
125+
h = [Float64[]]
126+
127+
128+
129+
aggs = (Direct(), DelayCoevolve(), DelayCoevolve())
130+
uselrate = zeros(Bool, length(aggs))
131+
uselrate[3] = true
132+
Nsims = Int(5e2)
133+
134+
for (i, agg) in enumerate(aggs)
135+
@info "Testing $(typeof(agg))"
136+
jump_prob = hawkes_problem(p, agg; u = u0, tspan, g, h, uselrate = uselrate[i])
137+
if typeof(agg) <: DelayCoevolve
138+
stepper = SSAStepper()
139+
else
140+
stepper = Tsit5()
141+
end
142+
sols = Vector{ODESolution}(undef, Nsims)
143+
for n in 1:Nsims
144+
reset_history!(h)
145+
sols[n] = solve(jump_prob, stepper)
146+
end
147+
if typeof(agg) <: DelayCoevolve
148+
λs = permutedims(mapreduce((sol) -> empirical_rate(sol, agg), hcat, sols))
149+
else
150+
cols = length(sols[1].u[1].u)
151+
λs = permutedims(mapreduce((sol) -> empirical_rate(sol, agg), hcat, sols))[:, 1:cols]
152+
end
153+
Eλ, Varλ = expected_stats_hawkes_problem(p, tspan, agg)
154+
@test isapprox(mean(λs), Eλ; atol = 0.01)
155+
@test isapprox(var(λs), Varλ; atol = 0.001)
156+
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ using Test, SafeTestsets
99
@time @safetestset "delay problem test" begin include("delay_problem_test.jl") end
1010
@time @safetestset "remake problem test" begin include("remake_test.jl") end
1111
@time @safetestset "low level interface test" begin include("low_level_interface.jl") end
12+
@time @safetestset "delay coevolve test" begin include("hawkes_delay_test.jl") end
1213
end

0 commit comments

Comments
 (0)