I am trying to generate a 2D vector from a 1D vector where the element is shifted along the row by an increment each row.
i would like my input to look like this:
input:
t = [t1, t2, t3, t4, t5]
out =
[t5, 0, 0, 0, 0]
[t4, t5, 0, 0, 0]
[t3, t4, t5, 0, 0]
[t2, t3, t4, t5, 0]
[t1, t2, t3, t4, t5]
[ 0, t1, t2, t3, t4]
[ 0, 0, t1, t2, t3]
[ 0, 0, 0, t1, t2]
[ 0, 0, 0, 0, t1]
im unaware of a way to do this without using a for loop, and computational efficieny is important for the task im using this for. Is there a way to do this without a for loop?
this is my code using a for loop:
import numpy as np
t = np.linspace(-3, 3, 7)
z = np.zeros((2*len(t) - 1, len(t)))
diag = np.arange(len(t))
for index, val in enumerate(np.flip(t, 0)):
z[diag + index, diag] = val
print(z)
What you're asking for here is known as a Toeplitz Matrix, which is:
a matrix in which each descending diagonal from left to right is constant
The one difference is that you want the lower triangle of your matrix.
You happen to be in luck, you can use scipy.linalg.toeplitz
to construct your matrix, and then np.tril
to access the lower triangle.
import numpy as np
from scipy.linalg import toeplitz
v = np.array([1, 2, 3, 4, 5])
t = np.pad(v[::-1], (0, 4), mode='constant')
Solve the matrix and access the lower triangle:
np.tril(toeplitz(t, v))
And our output!
array([[5, 0, 0, 0, 0],
[4, 5, 0, 0, 0],
[3, 4, 5, 0, 0],
[2, 3, 4, 5, 0],
[1, 2, 3, 4, 5],
[0, 1, 2, 3, 4],
[0, 0, 1, 2, 3],
[0, 0, 0, 1, 2],
[0, 0, 0, 0, 1]])
To generalize this method, simply calculate the necessary padding for t
from the shape of v
:
v = # any one dimension array
t = np.pad(v[::-1], (0, v.shape[0]-1), mode='constant')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With