简体   繁体   English

是否有可能沿轴对ndarray进行linalg.multi_dot?

[英]Is it possible to do linalg.multi_dot for an ndarray along an axis?

First of all, I have a group of 12 (2x2) matrices. 首先,我有一组12(2x2)矩阵。

II = np.identity(2, dtype=complex)
X = np.array([[0, 1], [1, 0]], dtype=complex)
Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
Z = np.array([[1, 0], [0, -1]], dtype=complex)
PPP = (-II + 1j*X + 1j*Y + 1j*Z)/2
PPM = (-II + 1j*X + 1j*Y - 1j*Z)/2
PMM = (-II + 1j*X - 1j*Y - 1j*Z)/2
MMM = (-II - 1j*X - 1j*Y - 1j*Z)/2
MMP = (-II - 1j*X - 1j*Y + 1j*Z)/2
MPP = (-II - 1j*X + 1j*Y + 1j*Z)/2
PMP = (-II + 1j*X - 1j*Y + 1j*Z)/2
MPM = (-II - 1j*X + 1j*Y - 1j*Z)/2

Currently I have a function operator_groups that draws a random matrix from this group for every j loop and it gets appended into a list sequence . 目前,我有一个功能operator_groups ,它为每个j循环从该组中绘制一个随机矩阵,并将其追加到列表sequence The random matrix drawn inbetween all the individual j loops are then used to do some calculations, irrelevant to our discussion here. 然后,将所有j循环之间绘制的随机矩阵用于进行一些计算,与此处的讨论无关。 At the end of the j loop, the sequences of the elements of the list sequence are reversed, then linalg.multi_dot is performed and then its hermitian conjugate is being taken (hence the .conj().T ) j循环的末尾,列表sequence中元素的sequence被颠倒,然后执行linalg.multi_dot ,然后采用其linalg.multi_dot共轭(因此.conj().T

def operator_groups():
    return random.choice([II, X, Y, Z, PPP, PPM, PMM, MMM, MMP, MPP, PMP, MPM])


for i in range(1, sample_size+1, 1):
    sequence = []
    for j in range(1, some_number, 1):
        noise = operator_groups()
        """some matrix calculations here"""
        sequence.append(noise)
    sequence_inverse = np.linalg.multi_dot(sequence[::-1]).conj().T

Now I wish to vectorize the i loop , by just doing the j loop in one big matrix. 现在,我希望通过在一个大矩阵中执行j循环来向量化i循环 The noise is now an ndarray of N matrices(instead of just 1 matrix) randomly sampled from the group, with each matrix representing the iterations of j , but parallelized. 现在, noise是从组中随机采样的N个矩阵的ndarray(而不是仅1个矩阵),每个矩阵表示j的迭代,但并行化。 The code now looks something like this. 代码现在看起来像这样。

def operator_groups(sample_size):
    return random.sample([II, X, Y, Z], sample_size)


sequence = []
for j in range(1, some_number, 1):
    noise = operator_groups(sample_size)
    sequence.append(noise)
sequence_inverse = np.linalg.multi_dot(sequence[::-1]).conj().T

Now that sequence is a multi-dimensional array, I'm having trouble with appending the multidimensional noise into the right order within sequence , and then subsequently also problem with performing linalg.multidot for the inverse of sequence and taking its Hermitian conjugate. 现在,该sequence是多维数组,在将多维noise添加到sequence的正确顺序时遇到了麻烦,然后又linalg.multidot了对sequence的逆执行linalg.multidot并采用其Hermitian共轭的问题。 In this case I'd want to multi_dot the inverse of all the stored up noise for each j row corresponding to each of the j loop. 在这种情况下,我想对与每个j循环相对应的每个j行的所有存储的noise的倒数进行multi_dot处理。 How can this be done? 如何才能做到这一点?

I'll provide some "pseudo-examples" below to further demonstrate my problem, using j = 3. For simplicity, here I'll only "randomly draw" X, Y, Z . 我将在下面提供一些“伪示例”,以使用j = 3进一步演示我的问题。为简单起见,这里我仅“随机绘制” X, Y, Z

Non-vectorised case: 非向量化情况:

i = 1
sequence = []
    j = 1
    noise = X (randomised)
    sequence.append(noise)
    sequence = [X]
    j = 2
    noise = Y (randomised)
    sequence.append(noise)
    sequence = [X, Y]
    j = 3
    noise = Z (randomised)
    sequence.append(noise)
    sequence = [X, Y, Z]

    end of j loop
take reverse order: [Z, Y, X]
do multi_dot: [ZYX] (Note: dot products, not element-wise multiplication)
take conjugate and tranpose(to get Hermitian): [ZYX].conj().T = [ZYX.conj().T]

Vectorized case(say if I was doing sample_size = 3): 向量化案例(假设我是否在执行sample_size = 3):

sequence = []
    j = 1
    noise = [X,Z,Y](randomised)
    sequence.append(noise)
    sequence = [[X,Z,Y]]
    j = 2
    noise = [Z,Y,X] (randomised)
    sequence.append(noise)
    sequence = [[X,Z,Y],
                [Z,Y,X]]
    j = 3
    noise = [Z,Z,X] (randomised)
    sequence.append(noise)
    sequence = [[X,Z,Y],
                [Z,Y,X],
                [Z,Z,X]]
    end of j loop
take reverse order: [[Z,Z,X],
                     [Z,Y,X],
                     [X,Z,Y]]
do multi_dot(along an axis,
which is what I have trouble with): [ZZX,ZYZ,XXY]
take conjugate and tranpose(to get Hermitian): 
[ZZX,ZYZ,XXY].conj().T = [ZZX.conj().T, ZYZ.conj().T, XXY.conj().T]

I hope these examples demonstrate my problem 我希望这些例子能说明我的问题

With your two random selectors: 使用您的两个随机选择器:

In [13]: operator_groups()        # returns one (2,2) array                                                                                   
Out[13]: 
array([[-0.5+0.5j,  0.5-0.5j],
       [-0.5-0.5j, -0.5-0.5j]])
In [14]: operator_groups1(4)      # returns a list of (2,2) arrays                                                                           
Out[14]: 
[array([[0.+0.j, 1.+0.j],
        [1.+0.j, 0.+0.j]]), array([[ 0.+0.j, -0.-1.j],
        [ 0.+1.j,  0.+0.j]]), array([[ 1.+0.j,  0.+0.j],
        [ 0.+0.j, -1.+0.j]]), array([[1.+0.j, 0.+0.j],
        [0.+0.j, 1.+0.j]])]

Your loop creates a list of arrays: 您的循环创建一个数组列表:

In [15]: seq=[] 
    ...: for j in range(4): 
    ...:     seq.append(operator_groups()) 
    ...:                                                                                                     
In [16]: seq                                                                                                 
Out[16]: 
[array([[-0.5-0.5j, -0.5+0.5j],
        [ 0.5+0.5j, -0.5+0.5j]]), array([[1.+0.j, 0.+0.j],
        [0.+0.j, 1.+0.j]]), array([[-0.5+0.5j, -0.5-0.5j],
        [ 0.5-0.5j, -0.5-0.5j]]), array([[-0.5-0.5j,  0.5-0.5j],
        [-0.5-0.5j, -0.5+0.5j]])]

which can be given to multi_dot for sequential dotting: 可以将其赋予multi_dot以便进行顺序multi_dot

In [17]: np.linalg.multi_dot(seq)                                                                            
Out[17]: 
array([[0.-1.j, 0.+0.j],
       [0.+0.j, 0.+1.j]])

If we build the sequence with the groups selector, we get a list of lists: 如果使用groups选择器构建序列,则会获得列表列表:

In [18]: seq=[] 
    ...: for j in range(4): 
    ...:     seq.append(operator_groups1(3)) 
    ...:                                                                                                     
In [19]: seq                                                                                                 
Out[19]: 
[[array([[ 0.+0.j, -0.-1.j],
         [ 0.+1.j,  0.+0.j]]), array([[ 1.+0.j,  0.+0.j],
         [ 0.+0.j, -1.+0.j]]), array([[0.+0.j, 1.+0.j],
         [1.+0.j, 0.+0.j]])], [array([[ 0.+0.j, -0.-1.j],
         [ 0.+1.j,  0.+0.j]]), array([[ 1.+0.j,  0.+0.j],
         [ 0.+0.j, -1.+0.j]]), array([[0.+0.j, 1.+0.j],
         [1.+0.j, 0.+0.j]])], [array([[1.+0.j, 0.+0.j],
         [0.+0.j, 1.+0.j]]), array([[ 1.+0.j,  0.+0.j],
         [ 0.+0.j, -1.+0.j]]), array([[ 0.+0.j, -0.-1.j],
         [ 0.+1.j,  0.+0.j]])], [array([[1.+0.j, 0.+0.j],
         [0.+0.j, 1.+0.j]]), array([[ 1.+0.j,  0.+0.j],
         [ 0.+0.j, -1.+0.j]]), array([[ 0.+0.j, -0.-1.j],
         [ 0.+1.j,  0.+0.j]])]]
In [20]: len(seq)                                                                                            
Out[20]: 4
In [21]: len(seq[0])                                                                                         
Out[21]: 3

We can 'stack' the inner lists, creating a list of (n,2,2) arrays: 我们可以“堆叠”内部列表,创建一个(n,2,2)个数组的列表:

In [22]: seq1 = [np.stack(el) for el in seq]                                                                 
In [23]: seq1                                                                                                
Out[23]: 
[array([[[ 0.+0.j, -0.-1.j],
         [ 0.+1.j,  0.+0.j]],

        [[ 1.+0.j,  0.+0.j],
         [ 0.+0.j, -1.+0.j]],

        [[ 0.+0.j,  1.+0.j],
         [ 1.+0.j,  0.+0.j]]]), array([[[ 0.+0.j, -0.-1.j],
         [ 0.+1.j,  0.+0.j]],

        [[ 1.+0.j,  0.+0.j],
         [ 0.+0.j, -1.+0.j]],

        [[ 0.+0.j,  1.+0.j],
         [ 1.+0.j,  0.+0.j]]]), array([[[ 1.+0.j,  0.+0.j],
         [ 0.+0.j,  1.+0.j]],

        [[ 1.+0.j,  0.+0.j],
         [ 0.+0.j, -1.+0.j]],

        [[ 0.+0.j, -0.-1.j],
         [ 0.+1.j,  0.+0.j]]]), array([[[ 1.+0.j,  0.+0.j],
         [ 0.+0.j,  1.+0.j]],

        [[ 1.+0.j,  0.+0.j],
         [ 0.+0.j, -1.+0.j]],

        [[ 0.+0.j, -0.-1.j],
         [ 0.+1.j,  0.+0.j]]])]

we can then apply matmul repeatedly on this list: 然后,我们可以在此列表上重复应用matmul

In [25]: res = seq1[0] 
    ...: for el in seq1[1:]: 
    ...:     res = res@el 
    ...:      
    ...:                                                                                                     
In [26]: res                                                                                                 
Out[26]: 
array([[[1.+0.j, 0.+0.j],
        [0.+0.j, 1.+0.j]],

       [[1.+0.j, 0.+0.j],
        [0.+0.j, 1.+0.j]],

       [[1.+0.j, 0.+0.j],
        [0.+0.j, 1.+0.j]]])

In effect matmul is like dot , but it treats the leading dimension(s) as a 'batch' dimension. 实际上, matmul就像dot一样,但是它将前导维视为“批量”维。

With random selection it's a pain to compare different results (unless I set the seed), so I leave the verification up to you. 使用随机选择时,比较不同的结果很麻烦(除非我设置了种子),所以我将验证留给您。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM