我想模拟一个有三个组成部分的量子系统。
我有一个三个元素的“矢量”,对应于三个自旋分量的N个点的单个波函数。每个元素都是一个1D数组,因此“向量”数组的形状为3xN。
我有3乘3的矩阵运算符,其中单元格包含N个点的运算符数组。矩阵的形状为3x3xN。
我希望能够进行常规的线性代数运算。例如,我希望矩阵指数以同样的方式工作。对角矩阵的指数就是对角线上元素的指数的对角矩阵
A = ([1,2] 0 0
0 [2,4] 0
0 0 [3,6])
exp(A) = ([e^1,e^2] 0 0
0 [e^2,e^4] 0
0 0 [e^3,e^6])
在Python中有没有一种优雅的方式来实现这一点?
我试过使用常规NumPy数组来实现这一点,但是当广播不同的形状时,它变得太复杂了。
3条答案
按热度按时间gmol16391#
为了更明确,这里是如何(如果我正确理解你的最后一个轴是什么,那只是执行N次线性代数运算的方法;这是numpy通常处理的方式,相反,第一个轴),您可以使用
np.moveaxis
。例如,指数的预期结果(同样,如果我理解正确的话),可以通过这种方式获得
也就是说,将最后一个轴移动到第一个位置:
np.moveaxis(M,2,0)
是一个N×3×3阵列。expm
执行N次指数运算,对N个3x 3矩阵中的每个矩阵执行一次,并返回N个3x 3数组,对应于N个结果。由于您想要的是一个3x 3xN的数组,所以您可以将结果的第一个轴移回最后一个位置。请注意,
np.moveaxis
几乎不做任何事情。它只是改变了阵列的strides
,这会影响数据的访问方式。它不分配任何新的内存(它是相同的数据),它不移动任何数据。np.moveaxis(M,2,0)[0,1,2]
是与M[1,2,0]
相同的元素,但有另一个名称(我的意思是不相同的“值”,内存中的相同数据;np.moveaxis(M,2,0)[0,1,2]=15
实际上改变了M[1,2,0]
的值。因此,简而言之,它不需要花费任何费用,或者几乎不需要花费任何费用。但这并不意味着你可以移动轴,然后对N×3×3矩阵和N×3向量执行任何线性代数,就像你对3x 3矩阵和3-向量一样。大多数numpy操作都是这样工作的,但不是全部。有时候这是不可能的。
以
@
矩阵向量乘法为例。它不能工作,因为它是模棱两可的。A@B
是矩阵-矩阵乘法,如果A和B是二维阵列。如果A是一个2D数组,B是一个1D数组,则它是一个矩阵向量乘法。但是如果A是一个3D数组,V是一个2D数组呢?在numpy的精神中,我们使用额外的轴进行“矢量化”。但这必须被理解为N个2D-2D阵列(总是具有相同的V)吗?还是N二维-一维乘法?几乎是一样的,你会说。毕竟,根据定义,矩阵-矩阵乘法只是M矩阵-向量乘法。但在这种情况下,“额外”维度是最后一个,而不是第一个。
因此,简而言之,它是模糊的。并且numpy中每个操作数超过2个轴的
@
选择的定义不是您想要的。话虽如此,您可以使用其他方法。例如,你可以在你的vector中添加另一个1大小的维度,这样它就被
@
视为2D(只有1列,在数学上,这与vector相同,但在numpy中并不完全相同,例如,在这种情况下就不是这样),您还可以使用
einsum
(至少更短)以更简单的方式完成此操作。但要理解完整的einsum
需要一些挠头)另一方面,矩阵-矩阵乘法的工作原理类似于
expm
示例。也就是说,如果你有两个N×3×3
矩阵,那么只使用@就可以简单地在3x 3矩阵上执行N次乘法。由于您拥有的是3x3×N
矩阵,因此在简单的情况下,只需移动轴返回,然后将结果的轴移动回来,就像np.expm
一样或者,同样是
einsum
(但在这种情况下,这是不必要的,因为一般的moveaxis(op(moveaxis(...)))
技巧是有效的。tyu7yeag2#
你需要做一些修改。
首先,你的数组应该是统一的:
第二,您要查找的矩阵运算是
scipy.linalg.expm
:最后,
expm
在最后两个维度上需要一个正方形数组,所以你需要稍微操作一下你的数组:d7v8vwbk3#
创建数组:
不能全部使用:
np.vectorize
或np.frompyfunc
可以单独应用函数。但请注意非对角线的变化:但是对于这样的操作员来说不需要这个
忽略offdiagonals将需要一些进一步的覆盖实用程序,例如数组测试:
这种事情可以概括。只是不要期望像编译的数字numpy代码那样的性能。