# 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

``````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`.