struct/Matrix/Vector/Assign values (structural model)

I am constructing some structural (economic) model. This requires me to write something (a simple version for illustration) like

using Parameters

@with_kw struct test_model @deftype Float64
  β = 0.98
end

struct test{M}
  A::Array{Float64, 3}
  B::Matrix{Vector{Float64}}
  C::M
end

test(C::test_model) = test(fill(0.0, (131, 51, 21)),
  fill([], (131, 21* 51)),
  C);

model = test_model()
alloc = test(model)

This gives error

ERROR: MethodError: no method matching test(::Array{Float64, 3}, ::Matrix{Vector{Any}}, ::test_model)

I think the error comes from B from test. I did the same exercise without B , and it doesn’t spit error. However, when I do another exercise:

struct test2
  B1::Matrix{Vector{Float64}}
  B2::Matrix{Vector{Float64}}
end

test2() = test2(fill([], (131, 21* 51)),
fill([], (131, 21* 51)))

alloc2 = test2();

This doesn’t give error. What does make this difference? How can I deal with this issue?

This is a vector of elements of Any type. Use Float64[] for an empty vector that will contain Float64 numbers (or Vector{Float64}()). That will solve the initialization error. The second I think does not error because it is performing an implicit conversion of the two empty matrices.

But there is a deeper problem there, which is that fill(Float64[], (2,2)) will put the same array of floats in every position in the matrix:

julia> m = fill(Float64[], (2,2))
2×2 Matrix{Vector{Float64}}:
 []  []
 []  []

julia> push!(m[1], 1.0)
1-element Vector{Float64}:
 1.0

julia> m
2×2 Matrix{Vector{Float64}}:
 [1.0]  [1.0]
 [1.0]  [1.0]

To have independent vectors at each position, you need a comprehension:

julia> m = [ Float64[] for i in 1:2, j in 1:2 ]
2×2 Matrix{Vector{Float64}}:
 []  []
 []  []

julia> push!(m[1], 1.0)
1-element Vector{Float64}:
 1.0

julia> m
2×2 Matrix{Vector{Float64}}:
 [1.0]  []
 []     []
1 Like

A minimal example of what you are seeing there is:

julia> struct test3
         B1::Matrix{Vector{Float64}}
         x::Float64
       end

julia> test3(fill([], (2,2)), 1.0) # converts [] to Float64[] automatically
test3([Float64[] Float64[]; Float64[] Float64[]], 1.0)

julia> struct test4{T}
           B1::Matrix{Vector{Float64}}
           x::T
       end

julia> test4(fill([], (2,2)), 1.0) # does not convert automatically
ERROR: MethodError: no method matching test4(::Matrix{Vector{Any}}, ::Float64)

julia> test4(fill(Float64[], (2,2)), 1.0)
test4{Float64}([Float64[] Float64[]; Float64[] Float64[]], 1.0)

I’m not sure if I like the fact that in test3 the automatic conversion occurs.

2 Likes