Initialise array without specific types

I believe he was asking in a specific context (copied below). In this case, he needs to pass an instance.

# function do_something(x::Int, T) where {T<:Real} # fails
function do_something(x::Int, y::T) where {T<:Real} 

  
    intermediate_thing = Array{T}(undef,(3,4))

    intermediate_thing[1,1] = 3.0
    
   return(intermediate_thing[1,1] * x)
end

By signature I only meant the list of arguments, with or without types. I guess the terminology is different in different languages (I’m used to R, where types are never specified).

What I mean is in the case where T is not the type of x, as in my example below, it would seem I should be adding a dummy variable y::T to the function to pass the type, which feels inelegant.

My current solution is as follows:

function update_matrix!(m)

  x = [1.2, 3.4]
  m[1,1] = exp(1im*x[1]) + sin(x[2])
  m[2,1] = exp(1im*x[2]) + sin(x[2])
  m[1,2] = exp(1im*x[1]) + sin(x[1])
  m[2,2] = exp(1im*x[2]) + sin(x[1])

end

function high_level(a, x)

  m = Matrix{Complex{Real}}(undef, 2,2)

  for i in 1:a
    update_matrix!(m)
  end

  return(real(m[1,1])*x)
end

high_level(2, 1.5)

Here thankfully I can probably derive the type of m from the type of x, as m = Matrix{Complex{typeof(x)}}(undef, 2,2) but if I needed to define the type of m in a way that is unrelated to a and x, with a parametric type T, I understood that would require introducing a dummy variable y::T? I guess it’s not a problem in practice, since pretty much always the type of internal objects will depend on the type of the input; unfortunately it can be hard for a newcomer to grasp what kinds of operations can be done on types – here for example I just need to do Complex{typeof(x)}, but part of me wonders what I would do if the relation between both types wasn’t so trivial.

I probably misunderstood that it was suggested I could add an argument y, which I could consider dummy, just for the purpose of using its type within the function,

function high_level(a, x, y::T) where {T<:Real}

  m = Matrix{Complex{T}}(undef, 2,2)

  for i in 1:a
    update_matrix!(m)
  end

  return(real(m[1,1])*x)
end

Yep, I think you hit the nail on its head – I’m worrying (needlessly, because this case is solved) that I just don’t know how to operate on types, to derive one from another etc. The promote examples are great because it shows me the way to think about these kinds of problem in the future.

Ah, interesting, thanks for the clarification. I’m learning a lot in this thread – hard to find these answers by oneself.

You can do this

julia> function update_matrix!(m::Array{Complex{T}}) where {T<:Real}

         x = [1.2 3.4]
         m[1,1] = exp(1im*x[1]) + sin(x[2])
         m[2,1] = exp(1im*x[2]) + sin(x[2])
         m[1,2] = exp(1im*x[1]) + sin(x[1])
         m[2,2] = exp(1im*x[2]) + sin(x[1])

         return m
       end
update_matrix! (generic function with 1 method)

julia> function high_level(a::S, y::Array{T}) where {S<:Int, T<:Real}
         m = Array{Complex{T}}(repeat([0 + 0im], outer = [2, 2]))
         for i in 1:a
           update_matrix!(m)
         end
         return(real(m[1,1])*y[1])
       end
high_level (generic function with 1 method)

julia> ForwardDiff.gradient(x -> high_level(1, x), [1.7])
1-element Array{Float64,1}:
 0.1068166524498424

or this (notice I removed the ``<: where {.....})

julia> function update_matrix_1!(m::Array{Complex{T}}) where {T}

         x = [1.2 3.4]
         m[1,1] = exp(1im*x[1]) + sin(x[2])
         m[2,1] = exp(1im*x[2]) + sin(x[2])
         m[1,2] = exp(1im*x[1]) + sin(x[1])
         m[2,2] = exp(1im*x[2]) + sin(x[1])

         return m
       end
update_matrix_1! (generic function with 1 method)

julia> function high_level_1(a::S, y::Array{T}) where {S, T}
         m = Array{Complex{T}}(repeat([0 + 0im], outer = [2, 2]))
         for i in 1:a
           update_matrix!(m)
         end
         return(real(m[1,1])*y[1])
       end
high_level_1 (generic function with 1 method)

julia> ForwardDiff.gradient(x -> high_level_1(1, x), [1.7])
1-element Array{Float64,1}:
 0.1068166524498424

or even this (no declaration of type signatures in function arguments). This also coincides with your solution :slight_smile:

function update_matrix_2!(m) 
  
  x = [1.2 3.4]
  m[1,1] = exp(1im*x[1]) + sin(x[2])
  m[2,1] = exp(1im*x[2]) + sin(x[2])
  m[1,2] = exp(1im*x[1]) + sin(x[1])
  m[2,2] = exp(1im*x[2]) + sin(x[1])
  
  return m
end

function high_level_2(a, y) 

  m = repeat([0.0 + 0.0im], outer = [2, 2])

  for i in 1:a
    update_matrix!(m)
  end

  return(real(m[1,1])*y[1])
end

julia> ForwardDiff.gradient(x -> high_level_2(1, x), [1.7])
1-element Array{Float64,1}:
 0.1068166524498424

Just for the record,

m[1,1] = exp(1im*x[1]) + sin(x[2])
m[2,1] = exp(1im*x[2]) + sin(x[2])
m[1,2] = exp(1im*x[1]) + sin(x[1])
m[2,2] = exp(1im*x[2]) + sin(x[1])

could be written as
@. m = exp(im*x) + sin(x') (or @. m = cis(x) + sin(x') which will likely be a little faster).

1 Like