7
$\begingroup$

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}

$\endgroup$
  • 3
    $\begingroup$ 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. $\endgroup$ – David G. Stork Feb 12 '15 at 23:56
  • 1
    $\begingroup$ @DavidG.Stork Yes, but usually inefficient code produces unpacked arrays and decreases the further performance. $\endgroup$ – ybeltukov Feb 13 '15 at 0:32
  • 1
    $\begingroup$ Three answers and no upvote yet?? (+1) $\endgroup$ – Szabolcs Feb 13 '15 at 0:44
12
$\begingroup$

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

enter image description here

It is fast and the result is packed array

mat[1000] // Developer`PackedArrayQ // AbsoluteTiming
(* {0.142522, True} *)
$\endgroup$
  • 1
    $\begingroup$ This gets the first column wrong. But it's close! $\endgroup$ – evanb Feb 13 '15 at 0:17
  • 1
    $\begingroup$ It also puts entries on the main diagonal, rather than one below the main diagonal. $\endgroup$ – evanb Feb 13 '15 at 0:19
  • 1
    $\begingroup$ @evanb I made a mistake in indexing. See my update. $\endgroup$ – ybeltukov Feb 13 '15 at 0:22
  • $\begingroup$ Amazing, thank you! $\endgroup$ – gKirkland Feb 13 '15 at 0:25
8
$\begingroup$

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...):

enter image description here

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]] &;
$\endgroup$
7
$\begingroup$

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]

enter image description here

$\endgroup$
2
$\begingroup$

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.

$\endgroup$
1
$\begingroup$
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}]]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.