多个 2x2 矩阵序列的向量化乘法

Vectorized multiplication of several sequences of 2x2 matrices

对于非矢量化版本,我有一系列 (2, 2) 形状的矩阵(即形状为 (n, 2, 2) 的 ndarray)并且需要按顺序将它们相乘(矩阵乘法),这意味着 n 顺序矩阵乘法。 这是一个最小的例子

def get_matrix_product_eig_val(J):
    # J holds the sequence of matrices to multiply and has shape=(n, 2, 2)
    M = np.identity(2, dtype=np.double)
    for i in range(n_gens):
        M = np.matmul(M, J[i])
    eig_val, eig_vec = np.linalg.eig(M)  # eig_val is what I'm interested in
    return eig_val

现在我有一个 k 这样的矩阵序列数组(一个形状为 (k, n, 2, 2) 的数组)并且需要为每个 k 条目做相同的顺序矩阵乘积. 天真的方法是做

# Now J has shape=(k, n, 2, 2)
for i in range(k):
    eig_vals[i] = get_matrix_product_eig_val(J[i, :, :, :])

有没有办法摆脱循环并以矢量化方式执行此操作?

备注:

1) n 预计在 ~100 的数量级。 k 可以介于 ~100 到 ~10,000 之间

2) 有人建议用 np.linalg.multi_dot 替换内循环。这实际上大大减慢了速度

3) 我可以看到 3x3 矩阵在遥远的未来应用,但是 2x2 的特定解决方案很好。无论哪种方式,所有矩阵都是正方形的,并且具有相同的维度

for i in range(n - 1):
    J[:, i + 1, :, 0] = np.broadcast_to((J[:, i+1, 0, 0])[..., None], (k, 2)) * J[:, i, :, 0] + \
                        np.broadcast_to((J[:, i+1, 1, 0])[..., None], (k, 2)) * J[:, i, :, 1]
    J[:, i + 1, :, 1] = np.broadcast_to((J[:, i+1, 0, 1])[..., None], (k, 2)) * J[:, i, :, 0] + \
                        np.broadcast_to((J[:, i+1, 1, 1])[..., None], (k, 2)) * J[:, i, :, 1]

eig_vals, _ = np.linalg.eig(J[:, -1, :, :])