# Better code for reversing and joining matrices

I am writing a function to reverse a matrix and join the reversed version to the original one, making a new matrix which I call A. And after doing this, I reverse A and join it with original A to get the result I want.

I have written my code like this:

matJoin[mat_?MatrixQ] :=
Module[{A, W, H},
A = Join[mat, Reverse /@ mat, 2];
{W, H} = Dimensions[mat];
Join[A, ArrayReshape[Reverse @ Flatten[A], {H, 2 W}]]]


For example, for a random matrix mat=RandomInteger[10, {4, 4}]shown as below:

{{10, 0, 3, 6}, {1, 0, 1, 9}, {2, 2, 6, 9}, {4, 5, 7, 4}}

Applying it to the matJoin function I wrote: matJoin[mat]

The output was shown as below and it had served my purpose:

{{10, 0, 3, 6, 6, 3, 0, 10}, {1, 0, 1, 9, 9, 1, 0, 1}, {2, 2, 6, 9, 9, 6, 2, 2}, {4, 5, 7, 4, 4, 7, 5, 4}, {4, 5, 7, 4, 4, 7, 5, 4}, {2,
2, 6, 9, 9, 6, 2, 2}, {1, 0, 1, 9, 9, 1, 0, 1}, {10, 0, 3, 6, 6, 3,
0, 10}}

But my problems are:

1. It only works for matrices with dimensions of even orders. If the W and H have odd values, the code doesn't work properly.
2. I am thinking there is a better way to write the function to make it run faster.

• It would be helpful if you were to edit this question to include an example of data which produces a wrong result and which shows what the right result would be for the data provided. – m_goldberg Nov 9 '18 at 14:43
• Thanks, already updated – leon365 Nov 9 '18 at 15:10

ClearAll[f]
f[m_?MatrixQ] := Module[{d = Dimensions@m,  rows, cols},
rows = Join[#, 1 + d[[1]] - #] &@Range[d[[1]]];
cols = Join[#, 1 + d[[2]] - #] &@Range[d[[2]]];
m[[rows, cols]]];

f @ Array[Subscript[a, Row @ {##}]&, {4, 4}] // MatrixForm


f @ Array[Subscript[a, Row @ {##}]&, {3, 5}] // MatrixForm


Using Henrik's timing setup f is is about twice as fast as matJoin2:

SeedRandom[1]
mat = RandomReal[1, {1000, 1000}];

r = matJoin[mat]; // RepeatedTiming // First


0.022

r2 = matJoin2[mat]; // RepeatedTiming // First


0.014

r3 = f[mat]; // RepeatedTiming // First


0.0064

r == r2 == r3


True

Update: A faster version of Mike Honeychurch's g:

g2[mat_] := With[{a=Join[mat, Reverse[mat, 2], 2] }, Join[a, Reverse @ a]]

r4 = g[mat]; // RepeatedTiming // First


0.090

r5 = g2[mat]; // RepeatedTiming // First


0.046

r == r2 == r3 == r4 == r5


True

Note: Timings on Wolfram Cloud, Version "11.3.0 for Linux x86 (64-bit) (March 7, 2018)"

• Ah, very good idea to boil it down to one single read-and-copy request. – Henrik Schumacher Nov 9 '18 at 16:01

Since you are asking about joining and reversing why not use Join and Reverse and use level specs?

mat = {{10, 0, 3, 6}, {1, 0, 1, 9}, {2, 2, 6, 9}, {4, 5, 7, 4}}

Join[Join[mat, Reverse[mat, 2], 2],Reverse@Join[mat, Reverse[mat, 2], 2]]

(*
{{10, 0, 3, 6, 6, 3, 0, 10}, {1, 0, 1, 9, 9, 1, 0, 1}, {2, 2, 6, 9, 9,
6, 2, 2}, {4, 5, 7, 4, 4, 7, 5, 4}, {4, 5, 7, 4, 4, 7, 5, 4}, {2,
2, 6, 9, 9, 6, 2, 2}, {1, 0, 1, 9, 9, 1, 0, 1}, {10, 0, 3, 6, 6, 3,
0, 10}}
*)


Test 2

mat = Array[Subscript[a, Row@{##}] &, {3, 5}]


g[mat_] :=Join[Join[mat, Reverse[mat, 2], 2],Reverse@Join[mat, Reverse[mat, 2], 2]]


or

h[mat_] := Module[{mat2 = Join[mat, Reverse[mat, 2], 2]},
Join[mat2, Reverse@mat2]
]


Timing on my machine has this solution the fastest as well as the most intuitive

This one appears to be twice as fast:

matJoin2[mat_?MatrixQ] := Module[{m, n, a, b},
{m, n} = Dimensions[mat];
a = mat[[Range[n, 1, -1]]];
b = mat[[All, Range[m, 1, -1]]];
ArrayFlatten[{{mat, b}, {a, b[[Range[m, 1, -1]]]}}]
]


Test:

mat = RandomReal[1, {1000, 1000}];
r = matJoin[mat]; // RepeatedTiming // First
r2 = matJoin2[mat]; // RepeatedTiming // First
r == r2


0.0276

0.014

True