Non-catting version of matrix construction

I want to do the following but obtaining a Matrix{Matrix{Float64}} not a Matrix{Float64}:

julia> A = rand(2,2);

julia> [A A; A A]
4×4 Array{Float64,2}:
 0.636575  0.458969   0.636575  0.458969 
 0.236709  0.0897579  0.236709  0.0897579
 0.636575  0.458969   0.636575  0.458969 
 0.236709  0.0897579  0.236709  0.0897579

The only way to do this in one line that came to mind is the following, which is less than ideal:

julia> reshape([A,A,A,A],2,2)
2×2 Array{Array{Float64,2},2}:
 [0.636575 0.458969; 0.236709 0.0897579]  …  [0.636575 0.458969; 0.236709 0.0897579]
 [0.636575 0.458969; 0.236709 0.0897579]     [0.636575 0.458969; 0.236709 0.0897579]

Any easier way?

1 Like

What about

fill(rand(2,2), 2, 2)

? Though it is unclear whether having identical matrices is part of the spec or just the example.

No I don’t actually want identical matrices ( and also not just 2 x 2)

My actual problem is a type that overrides hvcat a la SparseArray, but I still need to work with matrices of the type.

We don’t currently have a syntax to efficiently do it. One syntax to do it is [[A] [A]; [A] [A]]. In principle, this can be optimized in the parser to be efficient too.

2 Likes

It could possibly be argued that a typed_hvcat

Matrix{Float64}[A A; A A]

should do that but at the moment it doesn’t and I’m not sure whether there are any fundamental problems with the idea.

1 Like

No it shouldn’t since it’s still a concatenation.

Still not pretty, but:

A = rand(2,2)
map(i->A,zeros(2,2))

works. And with little effort some other matrices can be constructed, for example:

B = rand(2,2)
map(i->(A,B)[i],[1 2 ; 2 1])

alternates between two sub-matrices.

It sounds like the answer to my question is “no”. I’m going to try to put together a macro

@nocat [A A ; A A]

That should do what I need

2 Likes

This seems to work:

vnocat(A...) = [A...]
hnocat(A...) = reshape(vnocat(A...),(1,length(A)))
hvnocat(dims,A...) = reshape(vnocat(A...),dims)

macro nocat(x)
    ex = expand(x)
    if ex.args[1] == :vcat
        ex.args[1] = :vnocat
    elseif ex.args[1] == :hcat
        ex.args[1] = :hnocat
    else
        @assert ex.args[1] == :hvcat
        ex.args[1] = :hvnocat
    end
    ex
end

A =rand(2,2)
@assert @nocat([A A; A A]) == reshape([A,A,A,A],(2,2))

This is almost always wrong for a general purpose/expression-like macro. It’ll fail when the expression becomes more complicated (e.g. if you have ?:). Note that if you don’t care about the performance that much, you should just use [[A] [A]; [A] [A]] syntax. It has a high probability of becoming the syntax for this unless someone propose a different one.

1 Like

Ah OK, thanks for the tip. Putting aside whether the macro is a good idea (it turns out I actually just need hvnocat function, not the macro), to implement this macro would you suggest working on the original expression? that is, converting Expr(:vcat,Expr(:row,A,A),Expr(:row,A,A)) to an hvnocat call directly?

Yes, that would be the right way to implement such a macro.

I can give a “bad” different syntax in the hopes someone proposes a good one:

[A A,
 A A]

that is, mimic vcat where ; indicates concatination while , indicates nocat.

I don’t like this proposal because [A A] indicates hcat, so I’d say the natural interpretation of the proposal is to only concatenate in the horizontal direction. So what’s missing is an alternative to a space to indicate hnocat.