Writing `broadcast_c` for struct with custom indexing

I have a custom type

struct State{T} <: AbstractArray{T,1}
    fields::Dict{Symbol, UnitRange{Int64}}
    arr::Array{T}
end

Base.size(S::State) = size(S.arr)
Base.IndexStyle(::Type{<:State}) = IndexLinear()
Base.getindex(S::State{T}, inds::Vararg{Int,1}) where {T} = S.arr[inds...]
Base.getindex(S::State{T}, ind::Symbol) where {T} = S.arr[S.fields[ind]]
Base.setindex!(S::State{T}, val, inds::Vararg{Int,1}) where {T} = (S.arr[inds...] = val)

that allows indexing with symbols, e.g.

julia> state0 = State(Dict([(:r, 1:3), (:v, 4:6)]), [10; 11; 12; 13; 14; 15])
6-element Constants.State{Int64}:
 10
 11
 12
 13
 14
 15

julia> state0[:r]
3-element Array{Int64,1}:
 10
 11
 12

I plan on using this with DifferentialEquations.jl, but I’m currently having trouble getting broadcasting to work. For example, I cannot do

julia> dstate = deepcopy(state0)
6-element Constants.State{Int64}:
 10
 11
 12
 13
 14
 15

julia> dstate[:r] .= 5.0
ERROR: ArgumentError: invalid index: r

I found Broadcast for custom type - #3 by fengyang.wang which suggested I do

Base.Broadcast._containertype(::Type{<:State}) = State
Base.Broadcast.promote_containertype(::Type{State}, _) = State
Base.Broadcast.promote_containertype(_, ::Type{State}) = State
Base.Broadcast.promote_containertype(::Type{State}, ::Type{State}) = State

but I’m having trouble implementing the last step, to write a Base.Broadcast.broadcast_c(f, ::Type{State}, _...) = ... that makes use of my symbol indexing. It looks like implementing custom broadcasting will be improved in 0.7, but I’m stuck with 0.6 for now.

I think the nicer way to handle this is to make broadcast just apply to the arr fields. I would make the fields be an OrderedDict so you have a canonical numbers for the array and then let broadcast run down the array directly, by passing the slow dictionary access.

BTW,

arr::Array{T}

that’s not type-stable since arrays need the dimension.

One thing to note too is that we have some proof-of-concept implementations of arrays with naming schemes here:

https://github.com/JuliaDiffEq/LabelledArrays.jl

On v0.7 we want to make that compile away the cost of named access via either a.b overloads or a[:b] literals, but for now it does have a small cost.

But even on v0.6 the StaticArray version should be fast.

I’m looking at LabelledArrays.jl, except I’m getting an error running the example code for constructing LMArrays and LArrays (also, I think the single line constructor macro names are wrong in the README).

Copy pasting

names = @SArray [:a,:b,:c]
values = @MArray [1,2,3]

gives

julia> A = LMArray(names,values)
3-element LArray{Tuple{3},Int64,1,3}:
Error showing value of type LArray{Tuple{3},Int64,1,3}:
ERROR: ArgumentError: invalid index: (1, 1)

Additionally, would this allow indexing by multiple names at once? e.g. A[:a,:b]? I often need access to several elements at once for easy vector math (:r -> :rx, :ry, :rz).

That error is just in the display. It’s being made correctly but it’s not printing correctly. That’s fine though: the library is not released and still being worked on so think of it as a preview.

It doesn’t handle this. That’s a good idea though.

Do I have to do anything special to use LMArray in an in-place function to integrate? Trying to solve an ODEProblem this gives a ‘no method matching’ error that looks related to uType.

Looks like this library still needs work. Now that I know that someone is interested I’ll move it up the priority list. Ping me every once in awhile here or in the chat to force me to do it :stuck_out_tongue:

The friendliest of pings: :ping_pong:

LabelledArrays works and is registered now.

Julia changed its broadcasting implementation. You can now read about it here. Interfaces · The Julia Language