I'm using the following piece of code to create a banded matrix from a generator g
:
def banded(g, N):
"""Creates a `g` generated banded matrix with 'N' rows"""
n=len(g)
T = np.zeros((N,N+n-1))
for x in range(N):
T[x][x:x+n]=g
return T
The usage is simple as:
banded([1,2,3], 3)
and it returns
[1, 2, 3, 0, 0]
[0, 1, 2, 3, 0]
[0, 0, 1, 2, 3]
It will used mostly to solve a finite difference model with a given stencil for example (-1, 1)
Is there a better way to generate that stencil? I could not find any good NumPy Function for that.
By better I mean, faster, using less memory, removing the loop from python and sending to Numpy stack. Any (or all) of those are improvements.
We can create a matrix in Numpy using functions like array(), ndarray() or matrix(). Matrix function by default creates a specialized 2D array from the given input. The input should be in the form of a string or an array object-like.
In mathematics, particularly matrix theory, a band matrix or banded matrix is a sparse matrix whose non-zero entries are confined to a diagonal band, comprising the main diagonal and zero or more diagonals on either side.
To create an array with zero above the main diagonal forming a lower triangular matrix, use the numpy. tri() method in Python Numpy. The 1st parameter is the number of rows in the array. The 2nd parameter is the number of columns in the array.
Here's one with np.lib.stride_tricks.as_strided
to give us a 2D
view into a zeros padded 1D
version of the input and as such pretty memory efficient and hence performant too. This trick had been explored numerous times - 1
,2
.
Thus, the implementation would be -
def sliding_windows(a, W):
a = np.asarray(a)
p = np.zeros(W-1,dtype=a.dtype)
b = np.concatenate((p,a,p))
s = b.strides[0]
strided = np.lib.stride_tricks.as_strided
return strided(b[W-1:], shape=(W,len(a)+W-1), strides=(-s,s))
Sample runs -
In [99]: a = [1,2,3]
In [100]: sliding_windows(a, W=3)
Out[100]:
array([[1, 2, 3, 0, 0],
[0, 1, 2, 3, 0],
[0, 0, 1, 2, 3]])
In [101]: a = [1,2,3,4,5]
In [102]: sliding_windows(a, W=3)
Out[102]:
array([[1, 2, 3, 4, 5, 0, 0],
[0, 1, 2, 3, 4, 5, 0],
[0, 0, 1, 2, 3, 4, 5]])
With the same philosophy, but less messier version, we can also leverage np.lib.stride_tricks.as_strided
based scikit-image's view_as_windows
to get sliding windows. More info on use of as_strided
based view_as_windows
.
from skimage.util.shape import view_as_windows
def sliding_windows_vw(a, W):
a = np.asarray(a)
p = np.zeros(W-1,dtype=a.dtype)
b = np.concatenate((p,a,p))
return view_as_windows(b,len(a)+W-1)[::-1]
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