[英]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.