🌐
NumPy
numpy.org › doc › stable › reference › generated › numpy.block.html
numpy.block — NumPy v2.5 Manual
The most common use of this function is to build a block matrix: >>> import numpy as np >>> A = np.eye(2) * 2 >>> B = np.eye(3) * 3 >>> np.block([ ... [A, np.zeros((2, 3))], ... [np.ones((3, 2)), B ] ...
🌐
w3resource
w3resource.com › numpy › manipulation › block.php
NumPy: numpy.block() function - w3resource
April 24, 2026 - Numpy Array manipulation: numpy.block() is stack arrays in sequence vertically (row wise).
🌐
NumPy
numpy.org › doc › 2.3 › reference › generated › numpy.block.html
numpy.block — NumPy v2.3 Manual
The most common use of this function is to build a block matrix: >>> import numpy as np >>> A = np.eye(2) * 2 >>> B = np.eye(3) * 3 >>> np.block([ ... [A, np.zeros((2, 3))], ... [np.ones((3, 2)), B ] ...
🌐
NumPy
numpy.org › devdocs › reference › generated › numpy.block.html
numpy.block — NumPy v2.6.dev0 Manual
The most common use of this function is to build a block matrix: >>> import numpy as np >>> A = np.eye(2) * 2 >>> B = np.eye(3) * 3 >>> np.block([ ... [A, np.zeros((2, 3))], ... [np.ones((3, 2)), B ] ...
🌐
SciPy
docs.scipy.org › doc › numpy-1.13.0 › reference › generated › numpy.block.html
numpy.block — NumPy v1.13 Manual
... Stack arrays in sequence ... array into a list of multiple sub-arrays vertically. ... When called with only scalars, np.block is equivalent to an ndarray call....
🌐
TutorialsPoint
tutorialspoint.com › build-a-block-matrix-in-numpy
Build a block matrix in Numpy
February 17, 2022 - Python TechnologiesDatabasesComputer ... QualityManagement Tutorials View All Categories ... To build a block of matrix, use the numpy.block() method in Python Numpy....
🌐
w3resource
w3resource.com.cach3.com › numpy › manipulation › block.php.html
NumPy: block() function - w3resource
Numpy Array manipulation: block is stack arrays in sequence vertically (row wise).
Find elsewhere
🌐
SciPy
docs.scipy.org › doc › numpy-1.15.0 › reference › generated › numpy.block.html
numpy.block — NumPy v1.15 Manual
... Stack arrays in sequence ... array into a list of multiple sub-arrays vertically. ... When called with only scalars, np.block is equivalent to an ndarray call....
🌐
NumPy
numpy.org › doc › 1.22 › reference › generated › numpy.block.html
numpy.block — NumPy v1.22 Manual
Blocks can be of any dimension, but will not be broadcasted using the normal rules. Instead, leading axes of size 1 are inserted, to make block.ndim the same for all blocks. This is primarily useful for working with scalars, and means that code like np.block([v, 1]) is valid, where v.ndim == 1.
🌐
KooR.fr
koor.fr › Python › API › scientist › numpy › block.wp
KooR.fr - Fonction block - module numpy - Description de quelques librairies Python
``np.block([[a, b], [c, d]])`` is not restricted to arrays of the form:: AAAbb AAAbb cccDD But is also allowed to produce, for some ``a, b, c, d``:: AAAbb AAAbb cDDDD Since concatenation happens along the last axis first, `block` is *not* capable of producing the following directly:: AAAbb cccbb cccDD Matlab's "square bracket stacking", ``[A, B, ...; p, q, ...]``, is equivalent to ``np.block([[A, B, ...], [p, q, ...]])``. Examples -------- The most common use of this function is to build a block matrix: >>> import numpy as np >>> A = np.eye(2) * 2 >>> B = np.eye(3) * 3 >>> np.block([ ... [A, n
Top answer
1 of 6
26

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]]
2 of 6
11

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)
🌐
Pydocs
pydocs.github.io › p › numpy › 1.22.4 › api › numpy.block.html
Document
The most common use of this function is to build a block matrix · >>> A = np.eye(2) * 2 ... B = np.eye(3) * 3 ... np.block([ ... [A, np.zeros((2, 3))], ... [np.ones((3, 2)), B ] ...
Top answer
1 of 2
8

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.

  1. never blindly translate mathematical expressions into code: think algorithmically.

    X = np.linalg.matrix_power(A,i)@B 
    

    is much slower than

    X=B; 
    for j in range(i): X = A*X
    

    if $M \ll N$

    (exercise: compute operation count for both code fragments).

  2. whenever possible reuse previous calculations.

  3. pre-allocate output matrices, and do not store intermediate results in temp. matrices

2 of 2
2

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)

🌐
Dustin
dkenefake.github.io › blog › Numpy_Block
Numpy Block is slow · Dustin
November 30, 2020 - import numpy row = numpy.array([[i] for i in range(10)]) row_blocking = [row for i in range(1000)] %timeit dustin_block(row_blocking) %timeit numpy.block(row_blocking) brick = numpy.eye(5) row = [brick for i in range(10)] row_blocking = [row for i in range(10)] %timeit dustin_block(row_blocking) %timeit numpy.block(row_blocking)
Author: bamos