Expanding a matrix by duplicating its elements

Hi!

I am trying to create a “higher resolution” matrix by duplicating, in both dimensions by a factor n, the elements of a “lower resolution” matrix. A naive implementation looks like this:

function lr2hr(
    inarray::AbstractMatrix,
    factor::Integer
    )

    # Determine the type and size of the input argument `inarray`, and define the output array `outarray`:
    in_type = typeof(inarray)
    in_size = size(inarray)
    outarray = Matrix{in_type}(undef, factor * in_size[1], factor * in_size[2])

    for i = 1:in_size[1]
        for j = 1:in_size[2]
            for k = 1 + (i - 1) * factor:(i * factor)
                for l = 1 + (j - 1) * factor:(j * factor)
                    outarray[k, l] = inarray[i, j]
                end
            end
        end
    end

    return outarray

end

This function generates an error message complaining about “Cannot convert an object of type Int64 to an object of type Matrix{Int64}”, although it seems to me that outarray[k, l] and inarray[i, j] are both integers (though each is a matrix element):

julia> inarray = [1 2; 3 4]
2×2 Matrix{Int64}:
 1  2
 3  4

julia> outarray = lr2hr(inarray, 2)
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type Matrix{Int64}
Closest candidates are:
  convert(::Type{T}, ::LinearAlgebra.Factorization) where T<:AbstractArray at ~/.julia/juliaup/julia-1.8.5+0.x64.apple.darwin14/share/julia/stdlib/v1.8/LinearAlgebra/src/factorization.jl:58
  convert(::Type{Array{T, N}}, ::StaticArraysCore.SizedArray{S, T, N, N, Array{T, N}}) where {S, T, N} at ~/.julia/packages/StaticArrays/J9itA/src/SizedArray.jl:88
  convert(::Type{Array{T, N}}, ::StaticArraysCore.SizedArray{S, T, N, M, TData} where {M, TData<:AbstractArray{T, M}}) where {T, S, N} at ~/.julia/packages/StaticArrays/J9itA/src/SizedArray.jl:82
  ...
Stacktrace:
 [1] setindex!
   @ ./array.jl:968 [inlined]
 [2] lr2hr(inarray::Matrix{Int64}, factor::Int64)
   @ JMTools ~/Projects/MISR/MISR_Tools/JMTools/src/lr2hr.jl:81
 [3] top-level scope
   @ REPL[14]:1

where line 81 points to the statement outarray[k, l] = inarray[i, j]. The matrix outarray should look like this:

1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4

Questions:

  1. How should I assign the elements of the small matrix to the larger one?
  2. Is there a more efficient way to construct the larger matrix?

Your problem is here:

in_type = typeof(inarray)
outarray = Matrix{in_type}(undef, factor * in_size[1], factor * in_size[2])

the type of inarray is Matrix, you probably meant eltype here (i.e. the type of the elements of inarray, not of the array itself).

As for efficiency, you probably don’t want to construct this matrix at all, consider expressing it as a Kronecker product with LazyArrays

Thanks a lot, @nilshg. That’s right, and it works well. I did not know about the command eltype.

Regarding the efficiency question, my application is this: the process that generates inarray actually creates a geophysical field, for instance of 512 by 128 pixels. The goal is to create a map of that field at a size more convenient for visualization or printing. In that case, factor would be 4, for instance, to generate a reasonable image on the screen.

I’ll look into the link to Kronecker product with LazyArrays. Thanks again for your help.

By the way, you can use Base.repeat for this:

julia> inarray = [1 2; 3 4]
2×2 Matrix{Int64}:
 1  2
 3  4

julia> repeat(inarray, inner=(2,2))
4×4 Matrix{Int64}:
 1  1  2  2
 1  1  2  2
 3  3  4  4
 3  3  4  4

Even better! Thanks @Jollywatt for this elegant solution.