Return the minimum size of an array needed for a function to work

Hi everyone, I want to create a function that receives another function as an input and returns the size of the array this. As an example, let’s say I have a simple function that takes a vector as an input:

f(x::Vector{Number}) = x[1]+x[2]

and I want a function that would give

g(f) = 2

because f is expecting length(x)>=2

Is there any way to make this?

Automatically? No. Manually? Yes.

julia> f(x::Vector{<:Number}) = x[1]+x[2]
f (generic function with 1 method)

julia> g(::typeof(f)) = 2
g (generic function with 1 method)

julia> g(f)
2

Note that you probably want <:Number, not Vector{Number}.

1 Like

I guess one could also test arrays of all sizes until the function errors. But what exactly do you need this for?

I want my users to input an user-defined function f(x,p,q) where the sizes of x and q are not relevant, but the size of p is, because it is later given to another function as an input.
I can always ask the user to specify the size of p a priori and throw warnings/errors later in the code if the specified size is not correct, but I was wondering if there was a way to prevent these types of user error automatically in Julia.

The only thing that comes to mind is StaticArrays.jl if said arrays are small enough, but honestly I think you should go for the easy way of throwing errors

They don’t need to be small enough. We could used a SizedArray. We just need to move the size into the type domain.

julia> g(f::Function) = only(methods(f)).sig.parameters[2].body.parameters[1].parameters[1]
g (generic function with 1 method)

julia> f(x::StaticVector{2}) = x[1]+x[2]
f (generic function with 1 method)

julia> g(f)
2

julia> h(x::StaticVector{3}) = x[1]+x[2]+x[3]
h (generic function with 1 method)

julia> g(h)
3

julia> x = SizedVector{2}(rand(2))
2-element SizedVector{2, Float64, Vector{Float64}} with indices SOneTo(2):
 0.5036256944197668
 0.3502881692558516

julia> f(x)
0.8539138636756184

julia> y = SizedVector{3}(rand(3))
3-element SizedVector{3, Float64, Vector{Float64}} with indices SOneTo(3):
 0.5070385956063957
 0.8204921722209075
 0.6512150701603181

julia> h(y)
1.9787458379876215

We could then create an accessory function that helps us call the arbitrary functions.

julia> function call_with_sized_view(foo, vec::AbstractVector)
           foo(SizedVector{g(foo)}(@view(vec[firstindex(vec):(firstindex(vec) + g(foo) -1)])))
       end
call_with_sized_view (generic function with 1 method)

julia> call_with_sized_view(f, 1:5)
3

julia> call_with_sized_view(h, 1:5)
6
1 Like

Thank you, that seems to do exactly what I need! It seems that the user would still need to specify the size of the vector though, right?

Yes. Otherwise, we would need to parse the abstract syntax tree.

julia> ci = @code_lowered f(x)
CodeInfo(
1 ─ %1 = Base.getindex(x, 1)
│   %2 = Base.getindex(x, 2)
│   %3 = %1 + %2
└──      return %3
)

julia> ast.code[1].args[3]
1

julia> ast.code[2].args[3]
2