【问题标题】:Questions regarding the dimension initialization of multiple numpy arrays within a single numpy array关于单个numpy数组中多个numpy数组维度初始化的问题
【发布时间】:2019-07-06 15:21:30
【问题描述】:

假设我们有 3 个Pauli matrices,每个都有尺寸 (2x2)。如下图:

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)

现在,如果我将这些每个单独的 (2x2) 矩阵作为另一个 (2x2) 矩阵的条目。说:

A = np.array([[X, 0], [0, Y]])
B = np.array([[X, X], [Y, Y]])

奇怪的是,A 的暗度为 (2x2) - 这是我想要的理想值 - 而 B 的暗度为 (2, 2, 2, 2),无论这是什么,如下所示

A = np.array([[X, 0], [0, Y]])

A.shape
Out[131]: (2, 2)

B = np.array([[X, X], [Y, Y]])

B.shape
Out[133]: (2, 2, 2, 2)

另一方面,假设C(1x3) 矩阵,D(1x2) 矩阵,例如

C = np.array([[X, Y, 0]])
D = np.array([[X, Y]])

如果我们再次查看初始化矩阵的维度

C = np.array([[X, Y, 0]])

C.shape
Out[136]: (1, 3)

D = np.array([[X, Y]])

D.shape
Out[138]: (1, 2, 2, 2)

所以似乎每当我在这样的数组中初始化数组时,如果有混合数据类型作为条目,即矩阵和整数,如AC,它会给我我想要的合理形状,即维度@ 987654335@,每个条目的“隐藏”维度为(2x2)。但是只要条目只是像BandD 这样的严格矩阵,它就会给我带来诸如(2, 2, 2, 2) 之类的无意义的维度。所以我的问题是:

如何使用严格的 (2, 2) 矩阵作为条目来初始化 (n, n) numpy 数组(矩阵),并且仍然保留其 (n, n) 维度,即,而不是给我一些奇怪的 numpy 维度 (w, x, y, z)

我想要这个的原因是因为我正在使用量子力学中的运算符进行计算,使用这些泡利矩阵,例如 XYZ,作为量子计算中的量子门。所以如果我有一些状态 rho 这也是一个 (2x2) 矩阵。让

rho = np.array([[1, 0],
                [0, 0]])

RHO 成为(2x2) 对角矩阵,其条目是(2x2) rho 矩阵。

RHO = np.array([[rho, 0],
                [0, rho]])

我希望计算像np.dot(D, RHO) 这样的东西

np.array([np.dot(X, rho), 0],
         [0, np.dot(Y, rho)])

我在 python 上检查了两个 (2x2) 矩阵的点积,其中 (2x2) 矩阵作为条目,它的条目乘法也都将是点积。

我对上面谈到的所有内容的动机是我希望使用这些属性作为矢量化我的算法的手段。目前,我的算法的一个非常粗略的示例如下所示:

for i in (integer_1):
    for j in (integer_2):
        #do something that involves operations with sums of dot products of many matrices#

并将其矢量化,使其可能成为

for i in (integer_1):
        #do something that involves operations with multiples of matrices with dot product of matrices as its entries#

这可能有效,或者无效!但我很想知道我的这种方法是否会加快速度。 我希望我已经很好地解释了我的问题。 提前致谢。

编辑(1)

I've added latex formatted maths so hopefully you can understand what I'm trying to do.

def compute_channel_operation(rho, operators):
    """
    Given a quantum state's density function rho, the effect of the
    channel on this state is:
    rho -> sum_{i=1}^n E_i * rho * E_i^dagger
    Args:
        rho (2x2 matrix): Density function
        operators (list): List of operators(matrices)
    Returns:
        number: The result of applying the list of operators
    """
    operation = [E@rho@E.conj().T for i, E in enumerate(operators)]
    return np.sum(operation, axis=0)

So then I was hoping that instead of using loops, this direct multiplication of tensor method might be quicker as I scale up my simulation, say having to do this 1 million times 这里的问题是 K 应该是任何 (1xn) 维度的列表,即 [I] 或 [I, X] 或 [I, X, Y] 或 [I, X, Y, Z]。我知道这里 X = X^{\dagger} 和 Y 和 Z 也是如此,但我的模拟中会出现这种情况。

我希望我现在已经解释清楚了。

【问题讨论】:

  • 你希望 A 和 B 是 4x4 矩阵,还是 2x2x2x2 张量?
  • 我希望我的 B(with (2, 2, 2, 2)) 具有与 A(with (2, 2)) 相同的暗度。还是它们基本上具有相同的尺寸?
  • 但是“将矩阵作为另一个矩阵的条目”是什么意思?你想创建一个块矩阵,还是真正的矩阵矩阵(不管是什么)?在 NumPy 中,(2, 2) 对象矩阵并不是很有用,因为大多数数学运算将停止工作......也许您可以提供一些示例输入数据、您想要执行的一些操作以及所需的输出数据?跨度>
  • 请看我上面的编辑。谢谢:)
  • 我已经为你的函数修改了一个加速解决方案

标签: python python-3.x numpy numpy-ndarray quantum-computing


【解决方案1】:

(2, 2, 2, 2) 不是一个奇怪的维度,它只是一个形状为 2x2x2x2 的 4D 张量

您看到 AB 的形状不同的原因是因为您使用标量 0 设置 A 而不是 2x2 零矩阵。改成

A = np.array([[X, np.zeros((2, 2))], [np.zeros((2, 2)), Y]])
B = np.array([[X, X], [Y, Y]])

你会得到两个 2x2x2x2 张量。

或者改成

C = np.vstack([
    np.hstack([X, np.zeros((2, 2))]),
    np.hstack([np.zeros((2, 2)), Y])
])
D = np.vstack([
    np.hstack([X, X]),
    np.hstack([Y, Y])
])

您将获得 4x4 矩阵。

您还可以使用从一种形式转换为另一种形式

E = A.transpose(0, 2, 1, 3).reshape(4, 4)
F = B.transpose(0, 2, 1, 3).reshape(4, 4)

np.allclose(C, E)  # True
np.allclose(D, F)  # True

返回

G = E.reshape(2, 2, 2, 2).transpose(0, 2, 1, 3)
H = F.reshape(2, 2, 2, 2).transpose(0, 2, 1, 3)

np.allclose(A, G)  # True
np.allclose(B, H)  # True

编辑:关于您的函数 compute_channel_operation(),如果您不执行列表推导而是将操作向量化并在所有操作中传入 3D 张量,则可以大大加快速度 p>

rho = np.random.rand(2, 2)
operators = [np.random.rand(2, 2) for _ in range(1000)]
operators_tensor = np.asarray(operators)  # same as np.random.rand(1000, 2, 2)

def compute_channel_operation(rho, operators):
    operation = [E@rho@E.conj().T for i, E in enumerate(operators)]
    return np.sum(operation, axis=0)

def compute_channel_operation2(rho, operators):
    return np.sum(operators @ rho @ operators.transpose(0, 2, 1).conj(), axis=0)

A = compute_channel_operation(rho, operators)
B = compute_channel_operation(rho, operators_tensor)
C = compute_channel_operation2(rho, operators_tensor)

np.allclose(A, B) # True
np.allclose(A, C) # True

%timeit compute_channel_operation(rho, operators)
# 6.95 ms ± 103 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit compute_channel_operation(rho, operators_tensor)
# 7.53 ms ± 141 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit compute_channel_operation2(rho, operators_tensor)
# 416 µs ± 12 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

【讨论】:

  • 对于密度算子(2x2 矩阵)rho = np.array([[1, 0], [0, 0]]),是否有一种快速的方法可以生成以rho 作为对角线条目的 (nxn) 对角线张量?即对于 (2x2) 或 (2,2,2,2) tensor = np.array([[rho, 0], [0, rho]]) 或对于 (3x3) 或 (3,3,2,2) tensor = np.array([[rho, 0, 0], [0, rho, 0], [0, 0, rho]]) ?
  • 是的,scipy.linalg.block_diag()。但请记住,对于大型矩阵,您的计算将变得非常低效。
  • 您的代码正是我想要的,所以我会正式接受它,所以谢谢!!但我意识到只有在operators 的大小为大,即(1,100),在我的情况下,我的只会是一个最大暗度为(1,4)的数组。所以现在对我来说很明显,为了我想要的加速,我应该矢量化前面提到的两个 ij 循环,我在 compute_channel_operation 之上运行,但我不确定我怎么能这样做,我在这里发布我的整个代码并不完全好。或许你还有兴趣,可以私下看看?
  • compute_channel_operation2() 是您的函数的矢量化解决方案。但是,如果这不能解决您的问题,只需创建另一个问题并选择在此处链接。
【解决方案2】:
In [343]: 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)                                                        
In [344]: X                                                                                                     
Out[344]: 
array([[0.+0.j, 1.+0.j],
       [1.+0.j, 0.+0.j]])
In [345]: Y                                                                                                     
Out[345]: 
array([[ 0.+0.j, -0.-1.j],
       [ 0.+1.j,  0.+0.j]])
In [346]: Z                                                                                                     
Out[346]: 
array([[ 1.+0.j,  0.+0.j],
       [ 0.+0.j, -1.+0.j]])

np.array 尝试创建一个多维数值数组,失败后创建一个 object dtype 数组(或引发错误)。

In [347]: np.array([X,0])                                                                                       
Out[347]: 
array([array([[0.+0.j, 1.+0.j],
       [1.+0.j, 0.+0.j]]), 0], dtype=object)

这个数组与[X,0] 列表基本相同——它包含指向对象X 和数字0 的指针或引用。

但是给定 2 个(或更多)大小匹配的数组,它会生成一个更高维的数值数组。例如具有复杂 dtype 的 (2,2,2) 数组。

In [348]: np.array([X,Y])                                                                                       
Out[348]: 
array([[[ 0.+0.j,  1.+0.j],
        [ 1.+0.j,  0.+0.j]],

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

block,或concatenate/stack 的某种组合可以组成一个二维数组。例如一个 (2,4) 复数数组:

In [349]: np.block([X,Y])                                                                                       
Out[349]: 
array([[ 0.+0.j,  1.+0.j,  0.+0.j, -0.-1.j],
       [ 1.+0.j,  0.+0.j,  0.+1.j,  0.+0.j]])

要创建一个包含 X 和 Y` 的对象 dtype 数组,我可以这样做:

In [356]: xy = np.empty((2,), object)                                                                           
In [357]: xy[0]= X                                                                                              
In [358]: xy[1]= Y                                                                                              
In [359]: xy                                                                                                    
Out[359]: 
array([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]])], dtype=object)

empty 后跟单独赋值是构建对象 dtype 数组的最可靠方法。它绕过Out[348]中显示的多维结果。

我不知道这些方法是否有助于实现您的计算目标。我没有充分研究你的描述。但请记住,快速的numpy 代码适用于多维数字(包括complex)数组(例如Out[348])。使用对象 dtype 数组的数学是命中注定的,而且几乎总是更慢。

@ 矩阵乘法适用于XYOut[348]rho 等,但不适用于Out[347]RHO+ 与对象 dtype 数组一起使用,前提是元素本身支持添加。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-28
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    • 2020-10-25
    • 1970-01-01
    • 2020-07-24
    • 2019-02-10
    相关资源
    最近更新 更多