If you want to get the result without calling expm multiple times in a for loop, you can construct the input like this:
import numpy as np
from scipy.linalg import expm
n = 4
t = np.zeros([n*2, n*2])
for i in range(n):
t[2*i:2*i+2, 2*i:2*i+2] = i
C0 = expm(t)
This results in a format
>>> t
array([[0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 1., 1., 0., 0., 0., 0.],
[0., 0., 1., 1., 0., 0., 0., 0.],
[0., 0., 0., 0., 2., 2., 0., 0.],
[0., 0., 0., 0., 2., 2., 0., 0.],
[0., 0., 0., 0., 0., 0., 3., 3.],
[0., 0., 0., 0., 0., 0., 3., 3.]])
>>> C0
array([[ 1. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. ],
[ 0. , 1. , 0. , 0. ,
0. , 0. , 0. , 0. ],
[ 0. , 0. , 4.19452805, 3.19452805,
0. , 0. , 0. , 0. ],
[ 0. , 0. , 3.19452805, 4.19452805,
0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ,
27.79907502, 26.79907502, 0. , 0. ],
[ 0. , 0. , 0. , 0. ,
26.79907502, 27.79907502, 0. , 0. ],
[ 0. , 0. , 0. , 0. ,
0. , 0. , 202.21439675, 201.21439675],
[ 0. , 0. , 0. , 0. ,
0. , 0. , 201.21439675, 202.21439675]])
If you insist on having the results in your example structure of C, I believe that you'll have to use some kind of loop (list comprehension, range, or otherwise) to achieve this, as I don't think that is a standard output structure for this kind of function.
i1 = range(0, 2*n, 2)
i2 = range(1, 2*n+1, 2)
i = (tuple(i1 + i2 + i1 + i2), tuple(i1 + i1 + i2 + i2))
C = C0[i].reshape(2,2,n)
>>> C
array([[[ 1. , 4.19452805, 27.79907502, 202.21439675],
[ 0. , 3.19452805, 26.79907502, 201.21439675]],
[[ 0. , 3.19452805, 26.79907502, 201.21439675],
[ 1. , 4.19452805, 27.79907502, 202.21439675]]])
For larger inputs, expm handles sparse square arrays so you shouldn't have any issues with memory.
AandB? You could always do it by eigndecomposition.expmin that case, you'd only need toexpthe eigenvalues and then recompose by the eigenvectors. Andnp.linalg.eigcan handle arrays of shape(*, N, N)all at once