Julia: how to optimally declare a vector containing interpolations?

Viewed 228

I'm an economics student slowly switching from MATLAB to Julia.

Currently, my problem is that I don't know how to declare (preallocate) a vector that could store interpolations.

Specifically, when I execute something close to:

function MyFunction(i)
    # x, y vectors are some functions of 'i' defined here 
    f = LinearInterpolation(x,y,extrapolation_bc=Line())
    return f
end    

g = Vector{Function}(undef, N)
    
for i = 1:N
    g[i] = MyFunction(i)
end

I get:

ERROR: LoadError: MethodError: Cannot `convert` an object of type Interpolations.Extrapolation{Float64,1,Interpolations.GriddedInterpolation{Float64,1,Float64,Gridded{Linear},Tuple{Array{Float64,1}}},Gridded{Linear},Line{Nothing}} to an object of type Function

If I, instead of g=Vector{Function}(undef, N), declare g=zeros(N), I get a similar error message (ending with with ...Float64 rather than with ... Function).

When I, instead, declare:

g = Interpolations.Extrapolation{Float64,1,Interpolations.GriddedInterpolation{Float64,1,Float64,Gridded{Linear},Tuple{Array{Float64,1}}},Gridded{Linear},Line{Nothing}}(N)

I get:

LoadError: MethodError: no method matching Interpolations.Extrapolation{Float64,1,Interpolations.GriddedInterpolation{Float64,1,Float64,Gridded{Linear},Tuple{Array{Float64,1}}},Gridded{Linear},Line{Nothing}}(::Int64) Closest candidates are: Interpolations.Extrapolation{Float64,1,Interpolations.GriddedInterpolation{Float64,1,Float64,Gridded{Linear},Tuple{Array{Float64,1}}},Gridded{Linear},Line{Nothing}}(::Any, !Matched::Any) where {T, N, ITPT, IT, ET}

When I don't declare "g" at all, then I get:

ERROR: LoadError: UndefVarError: g not defined

Finally, when I declare:

g = Vector{Any}(undef, N)

the code works, though I'm afraid this might induce some type-change of a variable g, thereby slowing down my performance-sensitive code.

How, ideally then, should I declare g in this case?

EDIT: In reality, my problem is a bit more complex, more like the following:

function MyFunction(i)
# x, y vectors are some functions of 'i' defined here        
f = LinearInterpolation(x,y,extrapolation_bc=Line())
h = is a T-vector of some functions of x,y
A = is some matrix depending on x,y
    return h, A, f
end
 
h = Matrix{Function}(undef, T, N)
A = zeros(T,I,N)
g = Vector{Any}(undef, N)

for i = 1:N
    h[:,i], A[:,:,i], g[i] = MyFunction(i)
end

So, when I use either comprehension or broadcasting (like h, A, g = [MyFunction(i) for i in 1:N] or h, A, g = MyFunction.(1:N)), as users Benoit and DNS suggested below, the outputs of my function are 3 tuples, h, A, g, each containing {h[i], A[i], g[i]} for i=1,2,3. If I use only 1 output variable on the LHS, instead, i.e.: MyOutput = [MyFunction(i) for i in 1:N] or MyOutput[i] = MyFunction.(1:N), then MyOutput becomes a vector with N tuple entries, every tuple consisting of {h[i], A[i], g[i]} i=1,2,3,...,N. I bet there's a way of extracting these elements from the tuples in MyOutput and filling them inside h[:,i], A[:,:,i], g[i], but that seems a bit cumbersome and slow.

2 Answers

You could do

f = MyFunction(1)
g = Vector{typeof(f)}(undef, N)
g[1] = f
    
for i = 2:N
    g[i] = MyFunction(i)
end

I think also map should figure out the type:

map(MyFunction, 1:N)

A simple solution is to use a comprehension:

g = [MyFunction(i) for i in 1:N]

or elegantly use the dot syntax:

g = MyFunction.(1:N)

(Credit to DNF for the dot-syntax solution suggested in the comments.)

Related