How to initialize array of arrays with specific type?

Hi everyone,

I would like to initialize an array that is later filled with interpolation objects. To be specific, it should store output from interpolate() from Interpolations.jl later on.

Normally, I can initialize any array of arrays like this:

A = fill([], 1, 20)

or if I want to have the inner arrays to be Float64, I can write

A = fill(Float64[], 1, 20)

Julia tells me that an interpolation object is of type Interpolations.BSplineInterpolation{Float64, 2, OffsetArrays.OffsetMatrix{Float64, Matrix{Float64}}, BSpline{Cubic{Line{OnGrid}}}, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}

Therefore, I try to initialize my array like this

A = fill(Interpolations.BSplineInterpolation{Float64, 2, OffsetArrays.OffsetMatrix{Float64, Matrix{Float64}}, BSpline{Cubic{Line{OnGrid}}}, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}, 1, 20)

That looks fine, but when I try to store an interpolation afterwards in one of the arrays like this.

B = rand(10,10)
A[1] = interpolate( B, BSpline(Cubic(Line(OnGrid()))))

I get this error

ERROR: MethodError: Cannot `convert` an object of type Interpolations.BSplineInterpolation{Float64, 2, OffsetMatrix{Float64, Matrix{Float64}}, BSpline{Cubic{Line{OnGrid}}}, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}} to an object of type DataType

What am I doing wrong?

Thanks a lot!

Here is the complete MWE:

using Interpolations

# Initialize array of interpolation objects
A = fill(Interpolations.BSplineInterpolation{Float64, 2, OffsetArrays.OffsetMatrix{Float64, Matrix{Float64}}, BSpline{Cubic{Line{OnGrid}}}, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}, 1, 20)

# Set up some "data" for interpolations
B = rand(10,10)

# Try to store an interpolation in one of the elements of A
A[1] = interpolate( B, BSpline(Cubic(Line(OnGrid()))))

As far as I can tell you’re missing a pair of brackets. Cf

julia> A = fill(Float64, 1, 20)
1×20 Matrix{DataType}:
 Float64  Float64  Float64  Float64  Float64  Float64  …  Float64  Float64  Float64  Float64  Float64

julia> A[1] = [1.0, 2.0]
ERROR: MethodError: Cannot `convert` an object of type Vector{Float64} to an object of type DataType
Closest candidates are:
  convert(::Type{T}, ::T) where T at ~/julia1.7/share/julia/base/essentials.jl:218
Stacktrace:
 [1] setindex!(A::Matrix{DataType}, x::Vector{Float64}, i1::Int64)
   @ Base ./array.jl:903
 [2] top-level scope
   @ REPL[5]:1
1 Like

What you are using to fill the array A is the DataType of the interpolation. To use A[1] = ... you need an array of instances of the interpolation. For example:

julia> b = interpolate( B, BSpline(Cubic(Line(OnGrid()))));

julia> A = fill(copy(b), 10);

julia> A[1] = interpolate( B, BSpline(Cubic(Line(OnGrid()))));

Otherwise you may just want an empty array of interpolations, such as:

julia> A = typeof(b)[]
Interpolations.BSplineInterpolation{Float64, 2, OffsetMatrix{Float64, Matrix{Float64}}, BSpline{Cubic{Line{OnGrid}}}, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}[]

julia> push!(A, interpolate( B, BSpline(Cubic(Line(OnGrid())))))
1-element Vector{Interpolations.BSplineInterpolation{Float64, 2, OffsetMatrix{Float64, Matrix{Float64}}, BSpline{Cubic{Line{OnGrid}}}, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}}:
 [0.6382324838466641 0.15737452960821852 … 0.39607517204553827 0.15889649188608557; 0.13177398720760136 0.6391502891054832 … 0.9749632710156909 0.23570550771235294; … ; 0.26655297042787274 0.3298620168301782 … 0.09981476823205598 0.3372852663412892; 0.4963880643359818 0.10982508349889288 … 0.792355741208348 0.5513251663389037]

but then you need to push! to it.

(of if you really want an array of empty arrays of interpolations, A = fill(typeof(b)[], 10,20), in which case you need push!(A[1], interpolate(...)). )

1 Like

Thanks, that could be one mistake. So, do you mean I should add [] behind the type when using fill()?
I tried this and it returns the same error:

A = fill(Interpolations.BSplineInterpolation{Float64, 2, OffsetArrays.OffsetMatrix{Float64, Matrix{Float64}}, BSpline{Cubic{Line{OnGrid}}}, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}[], 1, 20)

Yes, then the next step is to push! to the first array of the list:

push!(A[1], interpolate( B, BSpline(Cubic(Line(OnGrid())))))

(the array is empty, so you cannot simply assign to one of its elements:

julia> v = Float64[]
Float64[]

julia> x[1] = 0
ERROR: MethodError: no method matching _checklubounds(::Bool, ::Tuple{Int64}, ::Tuple{Int64}, ::Tuple{})
1 Like

Note that this initializes every element to the same empty array. If you want to initialize them to distinct empty arrays you should use a comprehension. See Initialize array of arrays - #2 by GunnarFarneback

1 Like

No, it’s a different error. :slight_smile: It really depends on what you want to do. For example this works now (and avoids the problem that you initialized all elements in the outer array with the same vector):

A[1] = [interpolate( B, BSpline(Cubic(Line(OnGrid()))))]

But it’s quite possible that you want and/or should do something different.

1 Like

Well, that is quite important! I did not know that. Thanks!