117117function hawkes_problem(
118118 p,
119119 agg;
120+ vr_agg = VR_FRM(),
120121 u = [0.0],
121122 tspan = (0.0, 50.0),
122123 save_positions = (false, true),
@@ -125,7 +126,7 @@ function hawkes_problem(
125126)
126127 oprob = ODEProblem(f!, u, tspan, p)
127128 jumps = hawkes_jump(u, g; use_recursion)
128- jprob = JumpProblem(oprob, agg, jumps...; save_positions = save_positions)
129+ jprob = JumpProblem(oprob, agg, jumps...; vr_aggregator = vr_agg, save_positions = save_positions)
129130 return jprob
130131end
131132```
@@ -840,6 +841,100 @@ let fig = plot(
840841end
841842```
842843
844+ # Benchmarking Variable Rate Aggregators
845+
846+ We benchmark the variable rate aggregators (`VR_Direct`, `VR_DirectFW`, `VR_FRM`) for the Multivariate Hawkes process, using the same setup as above: networks from `1` to `50` nodes, `tspan=(0.0, 25.0)`, `\lambda=0.5`, `\alpha=0.1`, `\beta=5.0`, and 50 trajectories with a 10-second limit per configuration. We test both recursive and brute-force formulations.
847+
848+ ```julia
849+ vr_aggs = [
850+ (VR_Direct(), Tsit5(), false, "VR_Direct (brute-force)"),
851+ (VR_DirectFW(), Tsit5(), false, "VR_DirectFW (brute-force)"),
852+ (VR_FRM(), Tsit5(), false, "VR_FRM (brute-force)"),
853+ (VR_Direct(), Tsit5(), true, "VR_Direct (recursive)"),
854+ (VR_DirectFW(), Tsit5(), true, "VR_DirectFW (recursive)"),
855+ (VR_FRM(), Tsit5(), true, "VR_FRM (recursive)"),
856+ ]
857+
858+ tspan = (0.0, 25.0)
859+ p = (0.5, 0.1, 5.0)
860+ Vs = append!([1], 5:5:95)
861+ Gs = [erdos_renyi(V, 0.2, seed = 6221) for V in Vs]
862+
863+ vr_bs = Vector{Vector{BenchmarkTools.Trial}}()
864+
865+ for (vr_agg, stepper, use_recursion, label) in vr_aggs
866+ @info label
867+ global _stepper = stepper
868+ push!(vr_bs, Vector{BenchmarkTools.Trial}())
869+ _vr_bs = vr_bs[end]
870+ for (i, G) in enumerate(Gs)
871+ local g = [neighbors(G, i) for i in 1:nv(G)]
872+ local u = [0.0 for i in 1:nv(G)]
873+ if use_recursion
874+ global h = zeros(eltype(tspan), nv(G))
875+ global urate = zeros(eltype(u), nv(G))
876+ global ϕ = zeros(eltype(tspan), nv(G))
877+ _p = (p[1], p[2], p[3], h, urate, ϕ)
878+ else
879+ global h = [eltype(tspan)[] for _ in 1:nv(G)]
880+ global urate = zeros(eltype(u), nv(G))
881+ _p = (p[1], p[2], p[3], h, urate)
882+ end
883+ global jump_prob = hawkes_problem(_p, Direct(); vr_agg, u, tspan, g, use_recursion)
884+ trial = try
885+ if use_recursion
886+ @benchmark(
887+ solve(jump_prob, _stepper),
888+ setup = (h .= 0; urate .= 0; ϕ .= 0),
889+ samples = 50,
890+ evals = 1,
891+ seconds = 10,
892+ )
893+ else
894+ @benchmark(
895+ solve(jump_prob, _stepper),
896+ setup = ([empty!(_h) for _h in h]; urate .= 0),
897+ samples = 50,
898+ evals = 1,
899+ seconds = 10,
900+ )
901+ end
902+ catch e
903+ BenchmarkTools.Trial(
904+ BenchmarkTools.Parameters(samples=50, evals=1, seconds=10),
905+ )
906+ end
907+ push!(_vr_bs, trial)
908+ if (nv(G) == 1 || nv(G) % 10 == 0)
909+ median_time =
910+ length(trial) > 0 ? "$(BenchmarkTools.prettytime(median(trial.times)))" : "nan"
911+ println("algo=$label, V=$(nv(G)), length=$(length(trial.times)), median time=$median_time")
912+ end
913+ end
914+ end
915+ ```
916+
917+ ```julia
918+ let fig = plot(
919+ yscale = :log10,
920+ xlabel = "V",
921+ ylabel = "Time (ns)",
922+ legend_position = :outertopright,
923+ )
924+ for (i, (vr_agg, _, use_recursion, label)) in enumerate(vr_aggs)
925+ _bs, _Vs = [], []
926+ for (j, b) in enumerate(vr_bs[i])
927+ if length(b) == 50
928+ push!(_bs, median(b.times))
929+ push!(_Vs, Vs[j])
930+ end
931+ end
932+ plot!(_Vs, _bs, label=label)
933+ end
934+ title!("Variable Rate Simulations, 50 samples: nodes × time")
935+ end
936+ ```
937+
843938# References
844939
845940[1] D. J. Daley and D. Vere-Jones. An Introduction to the Theory of Point Processes: Volume I: Elementary Theory and Methods. Probability and Its Applications, An Introduction to the Theory of Point Processes. Springer-Verlag, 2 edition. doi:10.1007/b97277.
0 commit comments