【问题标题】:Matrix combination logic in a numpythonic waynumpythonic 方式的矩阵组合逻辑
【发布时间】:2017-06-06 09:39:50
【问题描述】:

我有以下矩阵:

,

.

其中每个元素都是一个 3x3 矩阵(即 A_01 是一个 3x3 矩阵)。这意味着 A 和 B 张量是 9x9 矩阵。 不使用 for 命令,如何结合前面的方程以获得:

.

目标是获得一个 numpythonic 解决方案,因为在实际情况下,AB 矩阵的大小可以是 (N,N)。

【问题讨论】:

  • 那么,如果 A 和 B 为 (N,N),每个元素仍然是 3 x 3
  • 每个 A 和 B 都是一个 3x3 张量。这被称为逐块张量,其中每个元素都是另一个张量。
  • 那么,A 和 B 总是会有 3 x 3 = 9 个块?
  • 是的。例如 A_01 = [[a_xx, a_xy, a_xz], [a_yx, a_yy, a_yz], [a_zx, a_zy, a_zz]]
  • 是(以更清晰的方式):例如 A_01 = [[a_01^xx, a_01^xy, a_01^xz], [a_01^yx, a_01^yy, a_01^yz], [a_01^zx, a_01^zy, a_01^zz]]

标签: python numpy math optimization parallel-processing


【解决方案1】:

只是为了好玩(和单机 Divakar),这里有一个非常紧凑的解决方案:

def mingle(AA, BB, m=3):
    n = len(AA) // m
    out = np.empty((m, 2, n, m, 2, n))
    out[:, [0, 1], ..., [0, 1], :] = AA.reshape((1, m, n, m, n))
    out[:, [0, 1], ..., [1, 0], :] = BB.reshape((1, m, n, m, n))
    out.shape = m * 2 * n, m * 2 * n
    out[np.arange(m * 2 * n), np.arange(m * 2 * n)] = 1
    return out

【讨论】:

  • 很好,我是这么想的,就是没完成。
  • @Divakar 谢谢,显然受到您的解决方案的启发。
【解决方案2】:

这是一种方法 -

def matrix_combination(A,B):
    N = A.shape[0]//3  # Size of each block
    A4D = A.reshape(3,N,3,N)
    B4D = B.reshape(3,N,3,N)

    r,c = np.nonzero(~np.eye(3,dtype=bool))
    out = np.zeros((6,N,6,N),dtype=A.dtype)    

    idx0 = 2*np.arange(3)
    out[idx0[r],:,idx0[c]] = A4D[r,:,c]
    out[idx0[r]+1,:,idx0[c]+1] = A4D[r,:,c]

    out[idx0[r],:,idx0[c]+1] = B4D[r,:,c]
    out[idx0[r]+1,:,idx0[c]] = B4D[r,:,c]
    out = out.reshape(N*6,-1)
    np.fill_diagonal(out,1)
    return out

示例运行 -

In [41]: A
Out[41]: 
array([[ 0,  0, 44, 98, 40, 69],
       [ 0,  0, 22, 55, 51, 19],
       [16, 58,  0,  0, 95, 95],
       [90, 88,  0,  0, 47, 91],
       [65, 96, 21, 50,  0,  0],
       [15, 91, 23, 91,  0,  0]])

In [42]: B
Out[42]: 
array([[ 0,  0, 20, 36, 85, 15],
       [ 0,  0, 17, 78, 56, 55],
       [86, 19,  0,  0, 60, 96],
       [76, 30,  0,  0, 34, 36],
       [73, 63, 28, 58,  0,  0],
       [40, 19, 22, 96,  0,  0]])

In [43]: matrix_combination(A,B)
Out[43]: 
array([[ 1,  0,  0,  0, 44, 98, 20, 36, 40, 69, 85, 15],
       [ 0,  1,  0,  0, 22, 55, 17, 78, 51, 19, 56, 55],
       [ 0,  0,  1,  0, 20, 36, 44, 98, 85, 15, 40, 69],
       [ 0,  0,  0,  1, 17, 78, 22, 55, 56, 55, 51, 19],
       [16, 58, 86, 19,  1,  0,  0,  0, 95, 95, 60, 96],
       [90, 88, 76, 30,  0,  1,  0,  0, 47, 91, 34, 36],
       [86, 19, 16, 58,  0,  0,  1,  0, 60, 96, 95, 95],
       [76, 30, 90, 88,  0,  0,  0,  1, 34, 36, 47, 91],
       [65, 96, 73, 63, 21, 50, 28, 58,  1,  0,  0,  0],
       [15, 91, 40, 19, 23, 91, 22, 96,  0,  1,  0,  0],
       [73, 63, 65, 96, 28, 58, 21, 50,  0,  0,  1,  0],
       [40, 19, 15, 91, 22, 96, 23, 91,  0,  0,  0,  1]])

【讨论】:

    【解决方案3】:

    你可以试试

    import numpy as np
    
    def checker_index(n, m=3):
        """create an index vector that addresses m blocks of n consecutive
        elements with the blocks separated by gaps of n elements
        """
        # the next line creates the array
        # /   0    1 ...   n-1  \
        # |  2n 2n+1 ...   3n-1 |
        # \  4n 4n+1 ...   5n-1 /
        i = np.arange(m*n).reshape((m, n)) + n*np.arange(m)[:, None]
        # next line just puts the rows side by side
        # now observe the these are precisely the places where you want to
        # put your first row of of A's (with a leading id) in the first
        # row of the target structure, and similarly with columns
        # also, observe that one just needs to add n to get indices
        # suitable for placing the first row/column of B's
        return i.ravel()
    
    def mingle(AA, BB, m=3):
        """combine AA and BB into the target structure
    
        here AA and BB are the full 3x3 block matrices you define in
        your question
        """
        n = len(AA) // m
        i1 = checker_index(n, m)
        # ix_ creates an "open grid" from its arguments
        # so indexing with y1, x1 below will select nm x nm elements
        # contrast this with ...
        y1, x1 = np.ix_(i1, i1)
        i2 = i1 + n
        y2, x2 = np.ix_(i2, i2)
    
        IAA = AA.copy()
        # ... the following line which only selects the diagonal,
        # thus just mn elements
        IAA[np.arange(m*n), np.arange(m*n)] = 1
        out = np.empty((2*m*n, 2*m*n))
        out[y1, x1] = IAA
        out[y1, x2] = BB
        out[y2, x1] = BB
        out[y2, x2] = IAA
        return out
    

    足够Numpythonic吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-19
      • 2020-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-02
      相关资源
      最近更新 更多