# Elegant method of generating this matrix?

Good evening, I need to determine an elegant (as possible) method of computing an $n\times n$ matrix below (the matrix shown is just a $16\times16$ example). I've been toying with For loops, Tables, Bands, DiagonalMatrix, etc. but due to my lack of Mathematica knowledge, I'm at a complete loss as to which method would be most computationally efficient. Any help would be greatly appreciated! Thanks in advance.

\begin{array}{cccccccccccccccc} 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 2 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 8 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 6 & 0 & 12 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 16 & 0 & 16 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 10 & 0 & 20 & 0 & 20 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 24 & 0 & 24 & 0 & 24 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 14 & 0 & 28 & 0 & 28 & 0 & 28 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 32 & 0 & 32 & 0 & 32 & 0 & 32 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 18 & 0 & 36 & 0 & 36 & 0 & 36 & 0 & 36 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 40 & 0 & 40 & 0 & 40 & 0 & 40 & 0 & 40 & 0 & 0 & 0 & 0 & 0 & 0 \\ 22 & 0 & 44 & 0 & 44 & 0 & 44 & 0 & 44 & 0 & 44 & 0 & 0 & 0 & 0 & 0 \\ 0 & 48 & 0 & 48 & 0 & 48 & 0 & 48 & 0 & 48 & 0 & 48 & 0 & 0 & 0 & 0 \\ 26 & 0 & 52 & 0 & 52 & 0 & 52 & 0 & 52 & 0 & 52 & 0 & 52 & 0 & 0 & 0 \\ 0 & 56 & 0 & 56 & 0 & 56 & 0 & 56 & 0 & 56 & 0 & 56 & 0 & 56 & 0 & 0 \\ 30 & 0 & 60 & 0 & 60 & 0 & 60 & 0 & 60 & 0 & 60 & 0 & 60 & 0 & 60 & 0 \\ \end{array}

• I strongly doubt computational efficiency is relevant here. Even inefficient Mathematica code can generate matrices with millions of entries in less than 0.1 second. – David G. Stork Feb 12 '15 at 23:56
• @DavidG.Stork Yes, but usually inefficient code produces unpacked arrays and decreases the further performance. – ybeltukov Feb 13 '15 at 0:32
• Three answers and no upvote yet?? (+1) – Szabolcs Feb 13 '15 at 0:44

Update: here Table is faster and more user-friendly then Array.

mat[n_] := LowerTriangularize@Table[2 (1 + Boole[j > 1]) (i - 1) Mod[i + j, 2],
{i, n}, {j, n}];

mat[10] // MatrixForm


It is fast and the result is packed array

mat[1000] // DeveloperPackedArrayQ // AbsoluteTiming
(* {0.142522, True} *)

• This gets the first column wrong. But it's close! – evanb Feb 13 '15 at 0:17
• It also puts entries on the main diagonal, rather than one below the main diagonal. – evanb Feb 13 '15 at 0:19
• @evanb I made a mistake in indexing. See my update. – ybeltukov Feb 13 '15 at 0:22
• Amazing, thank you! – gKirkland Feb 13 '15 at 0:25

None of the above are particularly "efficient", if that's your goal. By way of example,

mat = Module[{p1 = Range[0, 2 # - 2, 2], p2},
p2 = p1*2;
p1[[1 ;; ;; 2]] = 0;
p2[[2 ;; ;; 2]] = 0;
LowerTriangularize@Transpose[PadRight[{p1}, #, {2 p1, p2}]]] &;

mat[200];//Timing

(*

{0., Null}

*)


And that's on an old netbook. Compared to fastest of the answers so far (the rest ranged from slower to unusably slow):

Update: A faster method, dispenses with the most expensive operation of above, ~2x speed, averaged ~30X faster than fastest answer so far, 72X faster peak, under the range of tests in updated graph (Again, on an old netbook, I'd expect bigger difference w/ more cores...):

The new method:

newmat = Module[{p1 = Range[0, 2 # - 2, 2], p2},
p2 = p1;
p1[[1 ;; ;; 2]] = 0;
p2[[2 ;; ;; 2]] = 0;
LowerTriangularize@Join[Transpose@{p1},
ArrayPad[Transpose[{2 p2, 2 p1}], {{0, 0}, {0, # - 3}}, "Periodic"], 2]] &;


Here is my version using SparseArray:

mat2[n_]:=SparseArray[{{i_,j_}/;And[i>j,Mod[i+j,2]==1]:> If[j==1,2,4](i-1)},{n,n},0.];
MatrixForm@mat2[10]


I think this meets the spec:

gKirkland[rows_, columns_] := Outer[
Function[{i, j},
If[i <= j, 0,
If[Mod[i + j, 2] == 0, 0, 1] If[j == 1, 1/2, 1] (4 (i - 1))
]
], Range[1, rows], Range[1, columns]]


gKirkland[16,16] gives the matrix as shown. gKirkland[1000,1000] evaluates in 3 seconds.

sparse[n_] :=
Module[{range, column, bands},
range = Range[8, 4 n - 4, 4];
column = Table[{i, 1} -> 2 (i - 1), {i, 2, n, 2}];
bands = Table[Band[{i, 2}] -> Drop[range, (i - 3)], {i, 3, n, 2}];
SparseArray[column~Join~bands, {n, n}]]


Construction of sparse[1000] in 0.35 seconds.

# Update

Drop in Band can be dropped since Band stops putting values into places as soon as the edge of a matrix is reached.

sparse[n_] :=
Module[{range, firstColumn, bands},
range = Range[4 n - 4, 8, -4];
firstColumn = Table[{i, 1} -> 2 (i - 1), {i, 2, n, 2}];
bands = Table[Band[{n, n - j},
Automatic, {-1, -1}] -> range, {j, 1, n - 3, 2}];
SparseArray[firstColumn~Join~bands, {n, n}]]
`