在NumPy中添加块状常数矩阵

huangapple go评论51阅读模式
英文:

Adding block-constant matrices in numpy

问题

让我们假设我们有一个:

  • n*n 矩阵 A
  • m*m 矩阵 B
  • 一个包含块大小的向量 b=[b_1,...,b_m],满足 b_1 + ... + b_m = nb_i >= 1

然后,我定义了一个 n*n 块矩阵 B_block,其 (i,j) 块是一个具有常值 B_{ij}b_i*b_j 矩阵。如何在 numpy 中高效计算 A+B_block

到目前为止,我正在执行以下操作:

A = np.arange(36).reshape(6,6)
B = np.arange(9).reshape(3,3)
blocks_sizes = np.array([3,2,1])
B_block = np.block([[np.ones((a,b))*B[i,j] for j,b in enumerate(block_sizes)] for i,a in enumerate(block_sizes)])
C = A + B_block
print(A)
print(B_block)
print(C)

得到的结果如下:

[[ 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]]
[[0. 0. 0. 1. 1. 2.]
 [0. 0. 0. 1. 1. 2.]
 [0. 0. 0. 1. 1. 2.]
 [3. 3. 3. 4. 4. 5.]
 [3. 3. 3. 4. 4. 5.]
 [6. 6. 6. 7. 7. 8.]]
[[ 0.  1.  2.  4.  5.  7.]
 [ 6.  7.  8. 10. 11. 13.]
 [12. 13. 14. 16. 17. 19.]
 [21. 22. 23. 25. 26. 28.]
 [27. 28. 29. 31. 32. 34.]
 [36. 37. 38. 40. 41. 43.]]

这个方法是有效的,但似乎效率不高。是否有一种不需要手动构建块矩阵或使用 Python 循环的 numpy 解决方案?

如果所有的块大小都相同,那么可以使用 np.kron...

英文:

Let's say we have a

  • n*n matrix A
  • m*m matrix B
  • a vector b=[b_1,...,b_m] of block sizes with b_1 + ... + b_m = n and b_i >= 1.

Then I define a n*n block matrix B_block whose (i,j)-th block is a b_i*b_j matrix of constant value B_{ij}. How can I efficiently compute A+B_block in numpy?

So far I am doing

A = np.arange(36).reshape(6,6)
B = np.arange(9).reshape(3,3)
blocks_sizes = np.array([3,2,1])
B_block = np.block([[np.ones((a,b))*B[i,j] for j,b in enumerate(block_sizes)] for i,a in enumerate(block_sizes)])
C = A + B_block
print(A)
print(B_block)
print(C)

resulting in

[[ 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]]
[[0. 0. 0. 1. 1. 2.]
 [0. 0. 0. 1. 1. 2.]
 [0. 0. 0. 1. 1. 2.]
 [3. 3. 3. 4. 4. 5.]
 [3. 3. 3. 4. 4. 5.]
 [6. 6. 6. 7. 7. 8.]]
[[ 0.  1.  2.  4.  5.  7.]
 [ 6.  7.  8. 10. 11. 13.]
 [12. 13. 14. 16. 17. 19.]
 [21. 22. 23. 25. 26. 28.]
 [27. 28. 29. 31. 32. 34.]
 [36. 37. 38. 40. 41. 43.]]

which works fine but seems inefficient. Is there a numpy-solution which does not require constructing the block matrix by hand, or python-loops?

If all the blocks were of the same size, then I could use np.kron...

答案1

得分: 1

B_block = B[np.arange(len(blocks_sizes)).repeat(blocks_sizes)][:, np.arange(len(blocks_sizes)).repeat(blocks_sizes)]
C = A + B_block

我的性能

4.36 微秒 ± 93.9 纳秒每次循环7 次运行的平均值 ± 标准差每次循环100,000

您的性能

83.1 微秒 ± 34.7 微秒每次循环7 次运行的平均值 ± 标准差每次循环10,000

如果您愿意也可以定义 `slice_ids = np.arange(len(blocks_sizes)).repeat(blocks_sizes)` 来使其更轻便

B_block = B[slice_ids][:, slice_ids]
C = A + B_block
英文:
B_block = B[np.arange(len(blocks_sizes)).repeat(blocks_sizes)][:, np.arange(len(blocks_sizes)).repeat(blocks_sizes)]
C = A + B_block

my performance:

4.36 µs ± 93.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

your performance:

83.1 µs ± 34.7 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

If you prefer you can also define slice_ids = np.arange(len(blocks_sizes)).repeat(blocks_sizes) in order to make the lighter and so:

B_block = B[slice_ids][:, slice_ids]
C = A + B_block

huangapple
  • 本文由 发表于 2023年2月16日 18:47:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/75471155.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定