# How to transform and swap columns of this matrix in a simple way? Version 2

So, earlier today I asked the question

How to transform this matrix & swap its columns in a simple way?

and was given useful and elaborated answers. Now, I'm still not used to the "Array", "Reverse", "Map", etc. functions (which were new to me this morning) and this question is in fact a particular case of the other one :

I would like to transform matrix $\mathbf A = \begin{pmatrix} a_{11}&b_{11}&a_{12}&b_{12}&a_{13}&b_{13}\\ a_{21}&b_{21}&a_{22}&b_{22}&a_{23}&b_{23} \\ a_{31}&b_{31}&a_{32}&b_{32}&a_{33}&b_{33} \\ a_{41}&b_{41}&a_{42}&b_{42}&a_{43}&b_{43} \\ a_{51}&b_{51}&a_{52}&b_{52}&a_{53}&b_{54} \\ a_{61}&b_{61}&a_{62}&b_{62}&a_{63}&b_{63} \\ a_{71}&b_{71}&a_{72}&b_{72}&a_{73}&b_{73} \\ a_{81}&b_{81}&a_{82}&b_{82}&a_{83}&b_{83} \end{pmatrix}$ into matrix $\mathbf B = \begin{pmatrix} a_{83}&-b_{83}&a_{82}&-b_{82}&a_{81}&-b_{81} \\ a_{73}&-b_{73}&a_{72}&-b_{72}&a_{71}&-b_{71}\\ a_{63}&-b_{63}&a_{62}&-b_{62}&a_{61}&-b_{61} \\ a_{53}&-b_{53}&a_{52}&-b_{52}&a_{51}&-b_{51} \\ a_{43}&-b_{43}&a_{42}&-b_{42}&a_{41}&-b_{41}\\ a_{33}&-b_{33}&a_{32}&-b_{32}&a_{31}&-b_{31} \\ a_{23}&-b_{23}&a_{22}&-b_{22}&a_{21}&-b_{21} \\ a_{13}&-b_{13}&a_{12}&-b_{12}&a_{11}&-b_{11} \end{pmatrix}$.

In fact, to do this, I can multiply matrix $\mathbf A$ by the anti-diagonal identity matrix on the left : $\begin{pmatrix} 0&0&0&0&0&0&0&1\\ 0&0&0&0&0&0&1&0 \\ 0&0&0&0&0&1&0&0 \\ 0&0&0&0&1&0&0&0 \\ 0&0&0&1&0&0&0&0 \\ 0&0&1&0&0&0&0&0 \\ 0&1&0&0&0&0&0&0 \\ 1&0&0&0&0&0&0&0 \end{pmatrix}$, and multiply on the right by $\begin{pmatrix} 0&0&0&0&0&0&1&0\\ 0&0&0&0&0&0&0&-1 \\ 0&0&0&0&1&0&0&0 \\ 0&0&0&0&0&-1&0&0 \\ 0&0&1&0&0&0&0&0 \\ 0&0&0&-1&0&0&0&0 \\ 1&0&0&0&0&0&0&0 \\ 0&-1&0&0&0&0&0&0\end{pmatrix}$ to obtain matrix $\mathbf B$.

But I can't figure out how to generalize this to $\{n\times m,\ n>8,\ m>6\}$ size matrices, and most importantly how to make it efficient in terms of time consumption... Does anyone have any ideas?

Mathematica expression of A :

    A = Table[Sequence @@ {a[i, j], b[i, j]}, {i, 8}, {j, 3}]


Additional note : What I intend to do is to :

• Turn the matrix upside down

• Treat block matrices by sets of two columns and in each set

• Change the sign of the second column of each set
• Finally flipping the matrix as in a mirror image (but keeping the sets of two columns in order : for the example above $\rightarrow$ columns 1 & 2 become 4 & 6; columns 2 & 3 stay in their place (only in this example); columns 4 & 6 become 1 & 2.

  arrngF1 = MapAt[-1 # &,
#[[Range[Dimensions[#][[1]], 1, -1],
Join @@ Reverse@Partition[Range[Dimensions[#][[2]]], {2}]]],
{;; , 2 ;; ;; 2}] &;
arrngF2 = Module[{temp = #[[Range[Dimensions[#][[1]], 1, -1],
Join @@ Reverse@Partition[Range[Dimensions[#][[2]]], {2}]]]},
temp[[;; , 2 ;; ;; 2]] = (-1) temp[[;; , 2 ;; ;; 2]]; temp] &;


Example:

  mat = make[8, 3] (* from whuber's answer *);
Grid[{{"mat", "arrngF1[mat]", "arrngF2[mat]"},
MatrixForm /@ {mat, arrngF1[mat], arrngF2[mat]}}, Dividers -> All]


Timings:

  ClearSystemCache[];
ClearAll[c, d, d0, d1, d2]
c = make[1000, 1000];
AbsoluteTiming[d = arrange[c];]
(* {2.83919999,Null} *)
AbsoluteTiming[d0 = rM[#, {1, -1}] & /@ Reverse[c];]
(* {9.95279999,Null} *)
AbsoluteTiming[d1 = arrngF1[c];]
(* {1.9812000000,Null} *)
AbsoluteTiming[d2 = arrngF2[c];]
(* {2.2307999999,Null} *)
d == d0 == d1 == d2
(* True *)


Update: Modifying @whuber's method (using Band in the construction of the SparseArrays for pre/post-multiplying the input array):

  ClearAll[arrange2];
arrange2[c_] :=
Module[{m = Dimensions[c][[1]], n = Dimensions[c][[2]]},
SparseArray[Band[{1, m}, Automatic, {1, -1}] -> 1, {m, m}].c.
SparseArray[{Band[{1, n - 1}, Automatic, {2, -2}] -> 1,
Band[{2, n}, Automatic, {2, -2}] -> -1}, {n, n}]];


Timings:

  ClearSystemCache[];
ClearAll[c, d, d0, d1, d2]
c = make[1000, 1000];
AbsoluteTiming[d = arrange[c];]
(* {3.0360000000,Null} *)
AbsoluteTiming[d0 = arrange2[c];]
(* {1.528000,Null}*)
AbsoluteTiming[d1 = arrngF1[c];]
(* {2.08800,Null}*)
AbsoluteTiming[d2 = arrngF2[c];]
(* {2.467000,Null} *)
d == d0 == d1 == d2
(* True *)


(All timings for Intel Core Duo2 T9600 @ 2.8GHz with 8G memory running Mathematica 9.0. on MS Windows Vista 64-bit.)

• +1. ArrngF1 fails on v. 8.0 with an error about an invalid position specification, but ArrngF2 works beautifully. On this machine, for large symbolic matrices it is 20% to 100% faster than arrange and for large numeric matrices it is 100% faster. Nevertheless, I would still favor the OP's approach (based on pre- and post-multiplying by suitable matrices) as being perhaps the best general-purpose strategy for such matrix manipulation, because it will work just as efficiently for much more complicated re-arrangements involving arbitrary row and column permutations. Commented Feb 18, 2013 at 17:18
• Re the edit, The use of Band seems to be your theme for today :-). Thank you for the very nice application. Commented Feb 18, 2013 at 20:26
• @kguler Thanks for your proposition! I'm using elements from your answer and mixing them with some of whuber's... The Band hint is really useful. Seems to accelerate the calculations. Commented Feb 20, 2013 at 13:08

On many platforms, matrix operations are really fast, so using them is a good idea. (You have to get their dimensions correct, though!)

SparseArray objects are likely to be efficient in RAM and time usage. All we have to do is code the rules used to generate the right and left matrices:

arrange[c_] := Block[{m, n, sa},
{m, n} = Dimensions[c];
sa[x__] := SparseArray[Array[x]];
sa[{#, m + 1 - #} -> 1 &, m] . c . sa[{#, n + 1 - # + (-1)^#} -> (-1)^(# - 1) &, n]];


As an example, let's construct arbitrarily large forms of the matrix in the question:

make[m_, n_] := Table[Sequence@@{Subscript[a,i,j], Subscript[b,i,j]},{i,m},{j,n}];


How about operating on a $1000$ by $2000$ symbolic matrix?

c = make[1000, 1000]; AbsoluteTiming[d = arrange[c];]


{1.2210698, Null}

We can store the result and inspect small parts of it to confirm correctness; e.g.,

With[{e = Normal[d]},
Join[Join[e[[1 ;; 3, 1 ;; 3]], ConstantArray["...", {3, 1}],
e[[1 ;; 3, -3 ;; -1]], 2], ConstantArray["...", {1, 7}],
Join[e[[-3 ;; -1, 1 ;; 3]], ConstantArray["...", {3, 1}],
e[[-3 ;; -1, -3 ;; -1]], 2]]] // TraditionalForm


$$\left( \begin{array}{ccccccc} a_{1000,1000} & -b_{1000,1000} & a_{1000,999} & \text{...} & -b_{1000,2} & a_{1000,1} & -b_{1000,1} \\ a_{999,1000} & -b_{999,1000} & a_{999,999} & \text{...} & -b_{999,2} & a_{999,1} & -b_{999,1} \\ a_{998,1000} & -b_{998,1000} & a_{998,999} & \text{...} & -b_{998,2} & a_{998,1} & -b_{998,1} \\ \text{...} & \text{...} & \text{...} & \text{...} & \text{...} & \text{...} & \text{...} \\ a_{3,1000} & -b_{3,1000} & a_{3,999} & \text{...} & -b_{3,2} & a_{3,1} & -b_{3,1} \\ a_{2,1000} & -b_{2,1000} & a_{2,999} & \text{...} & -b_{2,2} & a_{2,1} & -b_{2,1} \\ a_{1,1000} & -b_{1,1000} & a_{1,999} & \text{...} & -b_{1,2} & a_{1,1} & -b_{1,1} \end{array} \right)$$

• What is this one-argument form of Array you are using? Commented Feb 18, 2013 at 8:33
• @Mr.Wizard: It's the old familiar multiple-argument form: although it may be hard to see, sa[x__] has two underscores in the pattern and you can check that both invocations of sa actually use two arguments. I used this abbreviation in order to clarify the ultimate line, which otherwise would be obscured by the two references to SparseArray[Array[..]]. Commented Feb 18, 2013 at 17:09
• @whuber Thanks! It all works great! Although I think I'm mixing your answer with the one kguler (@kguler) provided. I also believe that multiplying on the left and on the right is more intuitive and maybe even more "logical" if I may... Thanks again! Commented Feb 20, 2013 at 13:04

You could use Reverse for the first part and define a helper function to do the rest :

rM[avector_, {m1_, m2_}] :=
Module[{nc, local, rules},
nc = Length[avector]/2;
local = {m1, m2} # & /@ Partition[avector, 2];
Flatten[ReplacePart[local, (# -> local[[ nc + 1 - #]]) & /@  Range[nc]], 1]
]


The argument {m1, m2} will be used to multiply each couple of columns by input factors.

Test :

bigA = (Flatten[#] & /@
Outer[{Subscript[a, #1, #2], Subscript[b, #1, #2]} &, Range[8], Range[3], 1, 1]);
bigA // MatrixForm


$\left( \begin{array}{cccccc} a_{1,1} & b_{1,1} & a_{1,2} & b_{1,2} & a_{1,3} & b_{1,3} \\ a_{2,1} & b_{2,1} & a_{2,2} & b_{2,2} & a_{2,3} & b_{2,3} \\ a_{3,1} & b_{3,1} & a_{3,2} & b_{3,2} & a_{3,3} & b_{3,3} \\ a_{4,1} & b_{4,1} & a_{4,2} & b_{4,2} & a_{4,3} & b_{4,3} \\ a_{5,1} & b_{5,1} & a_{5,2} & b_{5,2} & a_{5,3} & b_{5,3} \\ a_{6,1} & b_{6,1} & a_{6,2} & b_{6,2} & a_{6,3} & b_{6,3} \\ a_{7,1} & b_{7,1} & a_{7,2} & b_{7,2} & a_{7,3} & b_{7,3} \\ a_{8,1} & b_{8,1} & a_{8,2} & b_{8,2} & a_{8,3} & b_{8,3} \\ \end{array} \right)$

(rM[#, {1, -1}] & /@ Reverse[bigA]) // MatrixForm


$\left( \begin{array}{cccccc} a_{8,3} & -b_{8,3} & a_{8,2} & -b_{8,2} & a_{8,1} & -b_{8,1} \\ a_{7,3} & -b_{7,3} & a_{7,2} & -b_{7,2} & a_{7,1} & -b_{7,1} \\ a_{6,3} & -b_{6,3} & a_{6,2} & -b_{6,2} & a_{6,1} & -b_{6,1} \\ a_{5,3} & -b_{5,3} & a_{5,2} & -b_{5,2} & a_{5,1} & -b_{5,1} \\ a_{4,3} & -b_{4,3} & a_{4,2} & -b_{4,2} & a_{4,1} & -b_{4,1} \\ a_{3,3} & -b_{3,3} & a_{3,2} & -b_{3,2} & a_{3,1} & -b_{3,1} \\ a_{2,3} & -b_{2,3} & a_{2,2} & -b_{2,2} & a_{2,1} & -b_{2,1} \\ a_{1,3} & -b_{1,3} & a_{1,2} & -b_{1,2} & a_{1,1} & -b_{1,1} \\ \end{array} \right)$

bigA = (Flatten[#] & /@
Outer[{Subscript[a, #1, #2], Subscript[b, #1, #2]} &, Range[8], Range[4], 1,1]);
bigA // MatrixForm


$\left( \begin{array}{cccccccc} a_{1,1} & b_{1,1} & a_{1,2} & b_{1,2} & a_{1,3} & b_{1,3} & a_{1,4} & b_{1,4} \\ a_{2,1} & b_{2,1} & a_{2,2} & b_{2,2} & a_{2,3} & b_{2,3} & a_{2,4} & b_{2,4} \\ a_{3,1} & b_{3,1} & a_{3,2} & b_{3,2} & a_{3,3} & b_{3,3} & a_{3,4} & b_{3,4} \\ a_{4,1} & b_{4,1} & a_{4,2} & b_{4,2} & a_{4,3} & b_{4,3} & a_{4,4} & b_{4,4} \\ a_{5,1} & b_{5,1} & a_{5,2} & b_{5,2} & a_{5,3} & b_{5,3} & a_{5,4} & b_{5,4} \\ a_{6,1} & b_{6,1} & a_{6,2} & b_{6,2} & a_{6,3} & b_{6,3} & a_{6,4} & b_{6,4} \\ a_{7,1} & b_{7,1} & a_{7,2} & b_{7,2} & a_{7,3} & b_{7,3} & a_{7,4} & b_{7,4} \\ a_{8,1} & b_{8,1} & a_{8,2} & b_{8,2} & a_{8,3} & b_{8,3} & a_{8,4} & b_{8,4} \\ \end{array} \right)$

(rM[#, {1, -1}] & /@ Reverse[bigA]) // MatrixForm


$\left( \begin{array}{cccccccc} a_{8,4} & -b_{8,4} & a_{8,3} & -b_{8,3} & a_{8,2} & -b_{8,2} & a_{8,1} & -b_{8,1} \\ a_{7,4} & -b_{7,4} & a_{7,3} & -b_{7,3} & a_{7,2} & -b_{7,2} & a_{7,1} & -b_{7,1} \\ a_{6,4} & -b_{6,4} & a_{6,3} & -b_{6,3} & a_{6,2} & -b_{6,2} & a_{6,1} & -b_{6,1} \\ a_{5,4} & -b_{5,4} & a_{5,3} & -b_{5,3} & a_{5,2} & -b_{5,2} & a_{5,1} & -b_{5,1} \\ a_{4,4} & -b_{4,4} & a_{4,3} & -b_{4,3} & a_{4,2} & -b_{4,2} & a_{4,1} & -b_{4,1} \\ a_{3,4} & -b_{3,4} & a_{3,3} & -b_{3,3} & a_{3,2} & -b_{3,2} & a_{3,1} & -b_{3,1} \\ a_{2,4} & -b_{2,4} & a_{2,3} & -b_{2,3} & a_{2,2} & -b_{2,2} & a_{2,1} & -b_{2,1} \\ a_{1,4} & -b_{1,4} & a_{1,3} & -b_{1,3} & a_{1,2} & -b_{1,2} & a_{1,1} & -b_{1,1} \\ \end{array} \right)$

• Thanks! This is what I call fancy code! It works just fine, but I'm still trying to understand it... I'm new to the "Slot", Reverse, and Rotate functions... Thanks again! Commented Feb 17, 2013 at 18:13
• Sorry! I made a big mistake, or in fact, I forgot to precise that the matrix A dimension isn't even... Commented Feb 17, 2013 at 19:53
• I really don't mean to be annoying... My problem is that I wasn't clear enough with what I needed. I edited my initial question, and I hope that it is clear enough now... Commented Feb 17, 2013 at 20:58
• Ok, just give me some minutes, I'm editing the question, I think it will be clearer by then! Commented Feb 17, 2013 at 21:46
• There it is, I hope I am now clear enough to be helped! Commented Feb 17, 2013 at 21:58