Eltype and dimensions from function definition

I would like to use a matrix function as basis for defining more complex structures. For this, I need to determine cheaply the eltype of the result and the dimensions. To be concrete, I have a matrix function defined as

julia> a(t) = [cos(t) sin(t); 1 -1]
a (generic function with 1 method)

and I would like to find out eltype(a(t)) and size(a(t)) without evaluating a(t) for a certain real value of t. Is this somehow possible?

If t is a subtype of Real and a(t) evaluates a trigonometric function then the resulting matrix will have entries that are a subtype of AbstractFloat, and the specific eltype(a(t)) ought to be the same as typeof(float(t)).
When you are asking about size(a(t)), if you do not know about a(t) then you do not know about it.

1 Like

Thanks. I thought that since a(t) evaluates to a 2x2 matrix, this information is somehow coded in the definition of the function a(t). So, my hope was to have a way to extract this information somehow.

Normal functions don’t have return types in Julia, the return type is just the type of whatever is returned.

Maybe there’s a package that makes something like this, you could even define it yourself:

struct TypedFunction{T} <: Function
    f
end

(f::TypedFunction)(args...) = f.f(args...)

return_type(::TypedFunction{T}) where {T} = T

f = TypedFunction{Float64}(sin)

But I’m not sure how much benefit there is to be extracted from doing this.

2 Likes

I like that (although I’m not sure I’d use it). Examples (showing why there probably is no builtin solution to OP’s question and showing how TypedFunction could increase type stability

a(t) = t < 0 ? [1, 2] : [1 2]
@show a(-1), typeof(a(-1))
@show a(1), typeof(a(1))

struct TypedFunction{T} <: Function
    f
end

(f::TypedFunction{T})(args...) where T = convert(T, f.f(args...))

return_type(::TypedFunction{T}) where {T} = T

ta = TypedFunction{Vector{Float64}}(a)
@show ta(-1)
@show ta(1)

yielding

(a(-1), typeof(a(-1))) = ([1, 2], Vector{Int64})
(a(1), typeof(a(1))) = ([1 2], Matrix{Int64})
ta(-1) = [1.0, 2.0]
ERROR: MethodError: no method matching Vector{Float64}(::Matrix{Int64})
1 Like
julia> Base.return_types(a, (Float64,))
1-element Vector{Any}:
 Matrix{Float64} (alias for Array{Float64, 2})

Note that Base.return_types is an internal function so use at your own risk.

3 Likes

Actually, I could reformulate my question to matrices which have constant dimensions. In my case, they are also periodic of a known period T, i.e.,
a(t) = a(t+T) .