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

enter image description here

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

enter image description here

Tags:

Matrix