I am developing a package for simulating (possibly very heterogeneous) dynamical systems that live on networks:
It’s very early days but usable, we just pushed v0.1. The core of this package is a loop over edges and vertices, and applies a user provided function to views of the appropriate locations in the array of states. I have copy pasted the code below.
I was initially surprised that this code allocates memory, but then I realized that this code creates a whole bunch of views at every iteration, so i assume this is the source of the allocations. It seems that that is the major performance bottleneck for simple network dynamics.
For e_int I control the array and I preallocate the views into memory, this is not possible for x and dx.
So finally, what it seems I would need to do is define a bunch of views into an array, but then be able to switch out the array on the fly. One option for this would be to create a mutable version of SubArray, this would then require mutating the Array indexed in SubArray every iteration. I have tried a bunch of other options but haven’t found anything that works.
Does somebody see a (better) option for this?
Here gs is a struct holding both the internal variable e_int, views into e_int and the index ranges required to get the right views into the state variables x and dx that we get passed from DifferentialEquations.
@with_kw struct nd_ODE_Static vertices! edges! graph graph_stucture end function (d::nd_ODE_Static)(dx, x, p, t) gs = d.graph_stucture @views begin for i in 1:gs.num_e d.edges![i].f!(gs.e_int[gs.e_idx[i]], x[gs.s_idx[i]], x[gs.d_idx[i]], p, t) end for i in 1:gs.num_v d.vertices![i].f!(dx[gs.v_idx[i]], x[gs.v_idx[i]], gs.e_s[i], gs.e_d[i], p, t) end end nothing end
And here is one attempt at getting around the problem that didn’t work:
mutable struct GS internals view function GS(internals) gs = new(internals) gs.view = view(gs.internals, 1:3) gs end end arr1 = ones(5) .+ 1. arr2 = ones(5) .+ 2. gs = GS(arr1) gs.view # 2. gs.internals = arr2 gs.view # still 2.