Unexpected behavior of similar

I find this behavior of similar unexpected:

julia> r = [rand(2, 2) for i in 1:3]

julia> x = similar(r)
3-element Vector{Matrix{Float64}}:
 #undef
 #undef
 #undef

julia> x[1]
ERROR: UndefRefError: access to undefined reference
Stacktrace:
 [1] getindex(A::Vector{Matrix{Float64}}, i1::Int64)
   @ Base ./array.jl:801
 [2] top-level scope
   @ REPL[5]:1

That’s fine because x[1] is undef. But if I specify the type of the elements, I still get these undef that I can’t access to overwrite:

julia> x = similar(r, Matrix{Float64})
3-element Vector{Matrix{Float64}}:
 #undef
 #undef
 #undef

How can I fill x? What I am trying to do is something like this:

r = [rand(2, 2) for i in 1:3]
x = similar(r)
for i in 1:3
    x[i] .= rand(2, 2)
end

Just do x[i] = rand(2, 2) (without the dot) instead of x[i] .= rand(2, 2). That way you are making the element x[i] point to the new matrix that is created by rand(2, 2). By using broadcasting, you try to overwrite the values in the matrix x[i], but it fails because the matrix x[i] does not exist.

Maybe I am misunderstanding you, but why do you think that specifying the element type would change things here? Since the original element type is already Matrix{Float64}, specifying it again doesn’t change anything.

1 Like

Maybe just

julia> similar.(r)
3-element Vector{Matrix{Float64}}:
 [0.0 1.37471521e-315; 1.376029345e-315 0.0]
 [0.0 1.37471521e-315; 1.376029345e-315 0.0]
 [0.0 1.37471521e-315; 1.376029345e-315 0.0]
1 Like

What I had in mind was to apply this function to a vector like x:

function claytonsample!(matkk, τ; randmat=randmat)
    matkk .= randmat
    τ == 0 && return matkk

    n = size(matkk, 1)
    for i in 1:n
        v = matkk[i, 2]
        u = matkk[i, 1]
        matkk[i, 2] = (1 - u^(-τ) + u^(-τ)*v^(-(τ/(1 + τ))))^(-1/τ)
    end
    return matkk
end

randmat = rand(10, 2)
matkk = similar(randmat)

#this works:
claytonsample!(matkk, 0.3; randmat=randmat)

#this doesn't:
randmat2 = [rand(10, 2) for i in 1:3]
matkk2 = similar(randmat2)

for i in 1:3
    claytonsample!(matkk2[i], 0.3; randmat=randmat2[i])
end

With @nilshg proposal, it now works:

randmat2 = [rand(10, 2) for i in 1:3]
matkk2 = similar.(randmat2)

for i in 1:3
    claytonsample!(matkk2[i], 0.3; randmat=randmat2[i])
end
1 Like