python - Better way to create block matrices out of individual blocks in numpy? - Stack Overflow
python - How can I efficiently process a numpy array in blocks similar to Matlab's blkproc (blockproc) function - Stack Overflow
Is there an efficient way to form this block matrix with numpy or scipy? - Computational Science Stack Exchange
Forming a particular (averaged) block matrix with numpy - Computational Science Stack Exchange
Here are some examples of a different (loop free) way to work with blocks:
import numpy as np
from numpy.lib.stride_tricks import as_strided as ast
A= np.arange(36).reshape(6, 6)
print A
#[[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]
# ...
# [30 31 32 33 34 35]]
# 2x2 block view
B= ast(A, shape= (3, 3, 2, 2), strides= (48, 8, 24, 4))
print B[1, 1]
#[[14 15]
# [20 21]]
# for preserving original shape
B[:, :]= np.dot(B[:, :], np.array([[0, 1], [1, 0]]))
print A
#[[ 1 0 3 2 5 4]
# [ 7 6 9 8 11 10]
# ...
# [31 30 33 32 35 34]]
print B[1, 1]
#[[15 14]
# [21 20]]
# for reducing shape, processing in 3D is enough
C= B.reshape(3, 3, -1)
print C.sum(-1)
#[[ 14 22 30]
# [ 62 70 78]
# [110 118 126]]
So just trying to simply copy the matlab functionality to numpy is not all ways the best way to proceed. Sometimes a 'off the hat' thinking is needed.
Caveat:
In general, implementations based on stride tricks may (but does not necessary need to) suffer some performance penalties. So be prepared to all ways measure your performance. In any case it's wise to first check if the needed functionality (or similar enough, in order to easily adapt for) has all ready been implemented in numpy or scipy.
Update:
Please note that there is no real magic involved here with the strides, so I'll provide a simple function to get a block_view of any suitable 2D numpy-array. So here we go:
from numpy.lib.stride_tricks import as_strided as ast
def block_view(A, block= (3, 3)):
"""Provide a 2D block view to 2D array. No error checking made.
Therefore meaningful (as implemented) only for blocks strictly
compatible with the shape of A."""
# simple shape and strides computations may seem at first strange
# unless one is able to recognize the 'tuple additions' involved ;-)
shape= (A.shape[0]/ block[0], A.shape[1]/ block[1])+ block
strides= (block[0]* A.strides[0], block[1]* A.strides[1])+ A.strides
return ast(A, shape= shape, strides= strides)
if __name__ == '__main__':
from numpy import arange
A= arange(144).reshape(12, 12)
print block_view(A)[0, 0]
#[[ 0 1 2]
# [12 13 14]
# [24 25 26]]
print block_view(A, (2, 6))[0, 0]
#[[ 0 1 2 3 4 5]
# [12 13 14 15 16 17]]
print block_view(A, (3, 12))[0, 0]
#[[ 0 1 2 3 4 5 6 7 8 9 10 11]
# [12 13 14 15 16 17 18 19 20 21 22 23]
# [24 25 26 27 28 29 30 31 32 33 34 35]]
Process by slices/views. Concatenation is very expensive.
for x in xrange(0, 160, 16):
for y in xrange(0, 160, 16):
view = A[x:x+16, y:y+16]
view[:,:] = fun(view)
The code proposed by the OP can indeed made be more efficient, mainly by noting the fact that to form the sequence $A^i B$, with $i=0\,\dots,N$ you do not have to compute $A^i$ at each step, but you can exploit the fact that $A^i B = A\,(A^{i-1}B)$, reusing the result of the previous step.
My proposed implementation is
import numpy as np
N = 3
M = 1
A = np.random.random((N, N))
B = np.random.random((N, M))
X = np.zeros((N ** 2, N * M))
rsl = slice(0, N)
X[rsl, :M] = B
for i in range(1, N):
rsl_p, rsl = rsl, slice(i * N, (i + 1) * N)
X[rsl, :M] = A @ X[rsl_p, :M]
X[rsl, M : (i + 1) * M] = X[rsl_p, : i * M]
This question is more related to programming that computational science, so I add some general remarks, useful for a novice programmer.
never blindly translate mathematical expressions into code: think algorithmically.
X = np.linalg.matrix_power(A,i)@Bis much slower than
X=B; for j in range(i): X = A*Xif $M \ll N$
(exercise: compute operation count for both code fragments).
whenever possible reuse previous calculations.
pre-allocate output matrices, and do not store intermediate results in temp. matrices
If you need to explicitly construct the entire matrix, then Stefano M's answer is your best bet. If, however, you don't really need the whole matrix, but just need to be able to perform a matrix-vector-product (MVP), then you might want to consider the following approach. Based on your comments it's unclear to me if this helps you, and I realize this doesn't technically answer your question, but I thought I'd post it just in case.
Suppose you want to calculate the MVP:
$\left( \begin{array}{c}y_1 \\ y_2 \\ \vdots \\ y_N \end{array} \right) = \left( \begin{array}{cccc} B & 0 & ... & 0 \\ A B & B & ... & 0 \\ \vdots & \vdots & \ddots & \vdots \\ A^{N-1} B & A^{N-2} B & ... & B \end{array} \right) \left( \begin{array}{c}x_1 \\ x_2 \\ \vdots \\ x_N \end{array} \right)$
where $x_i$'s are size $Mx1$ and known and we want to calculate $y_i$'s which are size $Nx1$ and unknown. This can be expressed block-by-block as
$\begin{array}{lll} y_i & = & \sum\limits_{j=1}^{i} A^{i-j} B x_j\\ & = & B x_i + \sum\limits_{j=1}^{i-1} A^{i-j} B x_j \\ & = & B x_i + A \sum\limits_{j=1}^{i-1} A^{(i-1)-j} B x_j \\ & = & B x_i + A y_{i-1}\\ \end{array}$
for $i=1,2,...,N$. (The last step works if we assume $y_0 \equiv \mathbf{0}^{[N \times 1]}$.)
This should be much faster than using the full dense matrix.
Example Python code:
import numpy as np
def mvp(A,B,x):
n=A.shape[0]
m=B.shape[1]
# assume that x is 1D array of size [n*m]
y=np.zeros( (n*n) )
y[:n] = B @ x[:m]
for i in range(1,n):
y[i*n:(i+1)*n] = B @ x[i*m:(i+1)*m] + A @ y[(i-1)*n:i*n]
return y
N = 3
M = 1
A = np.random.random((N, N))
B = np.random.random((N, M))
x=np.random.random( (N*M) )
y=mvp(A,B,x)
IMO, np.eye already has everything you need, as you can define number of rows and columns separately.
So your function should simply look like
def fct(k):
return np.eye(k**2-k, k**2)
If I understand you correctly, this should work:
a = np.concatenate((np.eye((k-1)*k),np.zeros([(k-1)*k,k])), axis=1)
(at least, when I set k=3 and compare with the np.block(...) expression you gave, both results are identical)
Hey,
I have the following problem: I have a 2D numpy array (256 x 256 shape) and I want to divide it into equally sized blocks (for example 8 x 8 elements blocks) and apply a custom function to each block (which should reflect changes made in this function onto the original array).
What I first tried was simply (I know basically one should never do this) looping with a double for loop over the array (with step size being the blocks shape) and applying the function on each block. This worked, but it was really, really slow and barely worked for smaller block sizes like 2 x 2.
Next, I used the following (which is basically the view_as_blocks function from skimage.util.shape.
from numpy.lib.stride_tricks import as_strided
def chunk(arr_in: np.ndarray, block_shape:tuple) -> np.ndarray:
block_shape = np.array(block_shape)
arr_shape = np.array(arr_in.shape)
new_shape = tuple(arr_shape // block_shape) + tuple(block_shape)
new_strides = tuple(arr_in.strides * block_shape) + arr_in.strides
arr_out = as_strided(arr_in, shape=new_shape, strides=new_strides)
return arr_outAnd then looped through the resulting blocks one by one and assembling it into a new array like this:
def my_main_fun() -> None:
# the blocks
s = chunk(img, (chunk_size, chunk_size))
# the new array
t = np.zeros_like(img)
for i in range(s.shape[0]):
for j in range(s.shape[1]):
o_i = i * chunk_size
o_j = j * chunk_size
_, vals = myCustomFunction(s[i][j])
t[o_i:o_i + chunk_size, o_j:o_j + chunk_size] = valsThis was faster, but it also takes quite a lot time (I assume due to the double for loop in the reassembling (second) function).
Now my question: How can I do this much more efficiently?
Note that its guaranteed that the block shape (which is always a square) is evenly divisible by the arrays shape and I only care about 2D arrays for now.
Many thanks in advance ;)