Is it possible to name slices of arrays as functions?

A common use case for me, and lots of people I would think, is to have large systems of DEs such as

dx_i / dt = …
dy_i / dt = …

where i \in [1, n] and x_i, y_i represents the ith class of x, y respectively.

Usually I define the state in these ODEs as one big vector of length 2n, like

const n = 100 #some number of dimensions
system_state = zeros(2*n)
system_state[1:n] #these are the x_i
 
system_state[n+1:2*n] #these are the y_i

Then the ODE function is something like this, with all the operations broadcasted

function f(du,u,p,t)
     x = @view u[1:n]
     y = @view u[n+1:2*n]
     du[1:n] .= -1 .* x
     du[n+1:2*n] .= x .* y
end

This works, but I end up having lots of slices around my code, which can be difficult to read.
I was hoping there was a zero-cost way of writing a shorthand function like

x(state) = @view state[1:n]

which I can then use to modify the state exactly like the original slice. However this doesn’t seem to work, I get the error “invalid assignment location”.

Is there a way to do this in Julia?

Thanks

using LabelledArrays
julia> z = @LArray [1 2; 3 4] (a = (2, :), b = 2:3);
julia> z.a
2-element view(::Array{Int64,2}, 2, :) with eltype Int64:
 3
 4
2 Likes

Cool, thanks!

I have a quick question related to the use of labelledarrays in this way.
My current toy example is


function f(du,u,p,t)
    x = @view u[1:n]
    y = @view u[n+1:2*n]
    du[1:n] .= -1 .* x
    du[n+1:2*n] .= -1 .* y
end
const n = 10
u_0 = @LArray  fill(1.0,2*n) (x = (1:n),y = (n+1:2*n))
prob = ODEProblem(f,u_0,(0,10.0),[])
sol = solve(prob,Tsit5())

Is it possible to define a custom type of labelledarray, like say state_type = LArray{2*n}(x = (1:n),y = (n+1:2*n)), so I can easily specify function signatures that return labelled arrays with the format of u_0? I’ve tried a few different things and none of them worked.

Let me know if this should be asked as a new topic or not as well.

I am not sure of a good way to implement that well.

Thanks for the fast reply.

I was benchmarking this code and found that the LabelledArrays one is actually slightly faster, although I’m not sure why they are allocating so much.

using DifferentialEquations
using LabelledArrays

function f1(du,u,p,t)
    x = @view u[1:n]
    y = @view u[n+1:2*n]
    du[1:n] .= -1 .* x .* u.y
    du[n+1:2*n] .= -1 .* y
end
function f2(du,u,p,t)
    du.x .= -1 .* u.x .* u.y
    du.y .= -1 .* u.y
end
const n = 1000
using BenchmarkTools
u_0 = @LArray  fill(1000.0,2*n) (x = (1:n),y = (n+1:2*n))
prob1 = ODEProblem(f1,u_0,(0,100.0),[])
@btime solve(prob1,Tsit5());

prob2 = ODEProblem(f2,u_0,(0,100.0),[])
@btime solve(prob2,Tsit5());

  31.841 ms (29417 allocations: 43.50 MiB)
  27.728 ms (29417 allocations: 43.50 MiB)