Assigning row of values to a lower triangular matrix
vals = {1, 2, 3, 4};
Reverse /@
ListConvolve[ConstantArray[1, Length@vals], vals, 1, 0, Times, List]
And a couple of special forces functions:
Reverse@HankelMatrix@Reverse@vals
LowerTriangularize@ToeplitzMatrix@vals
(added by J. M.)
The problem with LowerTriangularize @ ToeplitzMatrix @ vals
, altho it is compact, is that one is stuffing a matrix with values that are then set to zero later, which is a waste of effort. It is better to construct the lower triangular Toeplitz matrix outright with specially chosen vectors, like so:
ToeplitzMatrix[#, SparseArray[1 -> First[#], Length[#]]] & @ vals
I propose these:
vals = {1, 2, 3, 4};
n = 4;
SparseArray[Array[Band[{#, 1}] -> vals[[#]] &, n], n] // Normal
Reverse @ PadRight @ NestList[Rest, Reverse @ vals, n-1]
PadLeft @ NestList[Most, vals, n-1] ~Reverse~ {1, 2}
UpperTriangularize[NestList[RotateRight, vals, n-1]] ~Reverse~ {1, 2}
With[{r = Reverse@vals}, PadLeft[r, n, 0, n - #] & ~Array~ n]
#@Partition[#@vals, n, 1, 1, 0] &[Reverse]
PadRight[#, n] & /@ NestList[Rest, Reverse @ vals, n - 1] // Reverse
Table[
v = Prepend[Most@v, vals[[i]]],
{v, {ConstantArray[0, n]}},
{i, n}
] // First
All produce:
{{1, 0, 0, 0}, {2, 1, 0, 0}, {3, 2, 1, 0}, {4, 3, 2, 1}}
Notes:
Something I've known for a while but didn't account for here is that PadLeft
/PadRight
on a ragged array of packed lists unpacks. My second and third methods have this problem. By using PadRight
on each packed vector these can be greatly improved for that specific case.
Timings
Alright, I believe we have enough options for the first timing comparison. Using my flavor of Timo's timeAvg
:
SetAttributes[timeAvg, HoldFirst]
timeAvg[func_] := Do[If[# > 0.3, Return[#/5^i]] & @@ Timing@Do[func, {5^i}], {i, 0, 15}]
And this (packed) data:
n = 1500;
vals = RandomInteger[9999, 1500];
The timings for my proposals:
SparseArray[Array[Band[{#, 1}] -> vals[[#]] &, n], n] // timeAvg
Reverse@PadRight@NestList[Rest, Reverse @ vals, n - 1] // timeAvg
PadLeft@NestList[Most, vals, n - 1] ~Reverse~ {1, 2} // timeAvg
UpperTriangularize[NestList[RotateRight, vals, n - 1]] ~Reverse~ {1, 2} // timeAvg
With[{r = Reverse@vals}, PadLeft[r, n, 0, n - #] & ~Array~ n] // timeAvg
#@Partition[#@vals, n, 1, 1, 0] &[Reverse] // timeAvg
PadRight[#, n] & /@ NestList[Rest, Reverse @ vals, n - 1] // Reverse // timeAvg
Table[
v = Prepend[Most@v, vals[[i]]],
{v, {ConstantArray[0, n]}},
{i, n}
] // First // timeAvg
1.669
0.1342
0.1778
0.0362
0.003744
0.008112
0.004992
0.003992
And other's proposals:
f[i_, j_] /; i < j := 0
f[i_, j_] := vals[[i - j + 1]]
Array[f, {n, n}] // timeAvg
Table[If[i >= j, vals[[i - j + 1]], 0], {i, n}, {j, n}] // timeAvg
NestList[PadLeft[#, n + 1][[ ;; -2]] &, vals, n - 1] // Transpose // timeAvg
NestList[ArrayPad[#, {-1, 1}] &, Reverse@vals, n - 1] // Reverse // timeAvg
Reverse /@ ListConvolve[ConstantArray[1, Length@vals], vals, 1, 0, Times, List] // timeAvg
LowerTriangularize@MapIndexed[RotateRight, ConstantArray[Reverse@vals, n]] // timeAvg
Array[vals[[#1 - #2 + 1]] UnitStep[#1 - #2] &, {n, n}] // timeAvg
1.981
1.576
0.010608
0.006864
0.2246
0.134
3.573
I expected Band
to perform better which is why I led with it, but it actually scales very poorly. Kuba's method is faster than any of my four original ones but it inspired my fifth method which is the fastest so far on this test. I'll update timings as more options come in and with more detailed tests.
panda-34 get's his own special section for these beautiful incantations; the fastest yet!
Reverse @ HankelMatrix @ Reverse @ vals // timeAvg
LowerTriangularize @ ToeplitzMatrix @ vals // timeAvg
0.002872
0.002496
I recommend Array
since it is faster than Table
and UnitStep
(faster than If
)
(m = Array[(#1 - #2 + 1) UnitStep[#1 - #2] &, {4, 4}]) // MatrixForm
If there is an input vector e.g.
v = {3, 5, 7, 11};
we can reformulate existing approach to this form:
Array[ v[[#1 - #2 + 1]] UnitStep[#1 - #2] &, {4, 4}] // MatrixForm