I'm looking to generate a tridiagonal 50x50 matrix, ideally without using loops. Suggestions on most efficient code for this?
-
5DiagonalMatrix[list,k] – Grzegorz Rut Sep 14 '14 at 17:15
-
2I think this question is a duplicate of: (13004) -- please review that question and if you feel this is not a duplicate explain why. – Mr.Wizard Sep 15 '14 at 05:18
-
Your question is closed because its a duplicate , probably you should read the policy about that. – rhermans Sep 15 '14 at 16:49
3 Answers
As Gregory Rut mentioned, DiagonalMatrix already has built-in support for generating banded matrices from lists:
Inner[DiagonalMatrix, RandomInteger[{0, 5}, #] & /@ {49, 50, 49}, {-1, 0, 1}]
which yields the following (when ArrayPlot is applied):

- 11,857
- 1
- 29
- 49
-
1I just start writing that
Innerwill be more elegant then explicit sum! :) – ybeltukov Sep 14 '14 at 17:50 -
@ybeltukov I believe a disadvantage of
Inneris that more memory will be used. – Mr.Wizard Sep 15 '14 at 05:24
diag = RandomChoice[CharacterRange["a", "z"], #] & /@ {49, 50, 49};
m = SparseArray[Inner[Rule, {Band[{1, 2}], Band[{1, 1}], Band[{2, 1}]}, diag, List]]
MatrixPlot[m, Mesh -> True]

Timings: for a 50X50 matrix the timings of two methods based on Band and DiagonalMatrix are both 0. For larger matrices, Band is much faster:
ClearAll[f1, f2];
f1 = SparseArray[Inner[Rule, {Band[{1, 2}], Band[{1, 1}], Band[{2, 1}]}, #, List]] &;
f2 = Inner[DiagonalMatrix, #, {1, 0, -1}] &;
functions = {f1, f2};
testdata1 = RandomReal[5, #] & /@ {49, 50, 49};
testdata2 = RandomReal[5, #] & /@ {499, 500, 499};
testdata3 = RandomReal[5, #] & /@ {4999, 5000, 4999};
testdata4 = RandomReal[5, #] & /@ {9999, 10000, 9999};
(Equal @@ (Through@functions@#)) & /@ {testdata1, testdata2, testdata3, testdata4}
(* {True,True,True, True} *)
timings = Outer[N[First[AbsoluteTiming[#@#2;]], 5] &,
functions, {testdata1, testdata2, testdata3, testdata4}, 1];
TableForm[timings, TableHeadings -> {{Band, DiagonalMatrix},
{"n = 50", "n = 500", "n = 5000", "n = 10000"}}]

- 394,356
- 18
- 477
- 896
-
Unfortunately,
Bandis not so efficient. For example,f3 = Inner[DiagonalMatrix[SparseArray@#, #2] &, #, {1, 0, -1}] &is 10 times faster. – ybeltukov Sep 14 '14 at 20:33 -
-
-
@ybeltukov and kguler: I marked this question as a duplicate. Please review my action. If you disagree or feel another action should be taken let me know. – Mr.Wizard Sep 15 '14 at 05:22
-
@Mr.Wizard, i agree. Btw, do you remember if the linked q/a was on the
Relatedlist on the right before you linked to it? – kglr Sep 15 '14 at 05:39 -
Here is my expanded response to kguler.
I noticed that usually Band is less effective then DiagonalMatrix@SparseArray or manual constructing of the resulting SparseArray
f1 = SparseArray[Inner[Rule, {Band[{1, 2}], Band[{1, 1}], Band[{2, 1}]}, #, List]] &;
f2 = Inner[DiagonalMatrix, #, {1, 0, -1}] &;;
f3 = Inner[DiagonalMatrix[SparseArray@#, #2] &, #, {1, 0, -1}] &;
f4 = SparseArray[Join[Transpose@{Most@#, Rest@#}, Transpose@{#, #},
Transpose@{Rest@#, Most@#}] &@Range@Length@#[[2]] -> Join @@ #] &;
f5 = With[{n = Length@#[[2]]}, SparseArray @@ {Automatic, {n, n}, 0.,
{1,
{Join[{0}, Range[2, 3 n - 3, 3], {3 n - 2}],
Transpose@{Flatten[Transpose@Range[{0, 1, 2}, {n - 1, n, n + 1}]][[2 ;; -2]]}},
Flatten[Transpose@{Prepend[#[[3]], 0.], #[[2]], Append[#[[1]], 0.]}][[2 ;; -2]]
}}] &;
functions = {f1, f2, f3, f4, f5};
testdata = RandomReal[5, #] & /@ {# - 1, #, # - 1} & /@ {50, 500, 5000, 10000};
(Equal @@ (Through@functions@#)) & /@ testdata
(* {True, True, True, True} *)
timings = Outer[N[First[AbsoluteTiming[#@#2;]], 5] &, functions, testdata, 1];
TableForm[timings, TableHeadings -> {{"f1", "f2", "f3", "f4", "f5"}, {"n = 50",
"n = 500", "n = 5000", "n = 10000"}}]

Functions:
kguler's solution with
SparseArrayandBandDumpsterDoofus's
DiagonalMatrixwith dense matricesDiagonalMatrixwithSparseArrayManual creating of
Sparse arraywithSparseArray[indexes -> values]Completely manual creating of
SparseArrayasSparseArray[Automatic, dimensions, defaultElement, {1, {splitting, columns}, values}]. You can learn this format by investigatingInputFormof any availableSparseArray.
- 43,673
- 5
- 108
- 212
-
1So the most ridiculously complex and labored solution is the fastest? Just avoid functions that are supposed to be optimized for this? Yikes! – Zibadawa Sep 15 '14 at 04:09