爱因斯坦符号

2021-02-18 03:33:27

使用爱因斯坦求和约定,可以用一种简单的方式表示许多常见的多维线性代数数组运算。在隐式模式下,einsum计算这些值。

在显式模式下,einsum通过禁用或强制对指定的下标标签求和,从而提供了更大的灵活性来计算其他数组操作(可能不被视为经典的爱因斯坦求和操作)。

将要求和的下标指定为逗号分隔的下标标签列表。除非包含显式指示符“->”以及精确输出形式的下标标签,否则将执行隐式(经典的爱因斯坦求和)计算。

如果提供了该选项,则强制计算使用指定的数据类型。请注意,您可能还必须提供一个更宽松的强制转换参数才能进行转换。默认为无。

顺序{'C','F','A','K'},可选

控制输出的内存布局。 “ C”表示它应该是C连续的。 'F'表示它应该是Fortran连续的,'A'表示如果所有输入都为'F'则应该为'F',否则为'C'。'K'表示它应该与输入asis尽可能靠近布局可能,包括任意排列的轴。默认值为“ K”。

强制转换{'no','equiv','safe','same_kind','unsafe'},可选

控制可能发生的数据类型转换。不建议将其设置为“不安全”,因为这会对积聚产生不利影响。

“ same_kind”表示仅允许安全类型转换或同一类型(例如float64到float32)内的类型转换。

控制是否应进行中间优化。如果将False和True缺省设置为“贪心”算法,则不会进行优化。还要接受np.einsum_path函数的显式收缩列表。有关更多详细信息,请参见np.einsum_path。默认为False。

einops软件包提供了类似的详细界面,以涵盖其他操作:转置,重塑/展平,重复/拼贴,挤压/取消挤压和缩小。

爱因斯坦求和约定可用于计算许多多维的线性代数数组运算。 einsum提供了一种简洁的表示方式。

这些操作的非详尽列表(可以通过einsum计算)在下面显示,并提供示例:

下标字符串是用逗号分隔的下标标签列表,其中每个标签均指对应操作数的维数。每当重复标签时,它都会被累加,因此np.einsum(' i,i' a,b)等于np.inner(a,b)。如果一个标签仅出现一次,则不会对其求和,因此np.einsum(' i&#39 ;, a)会产生一个无变化的a视图。另一个示例np.einsum(ij,jk' a,b)描述了传统的矩阵乘法,并且等效于np.matmul(a,b)。 oneoperand中重复的下标标签取对角线。例如,np.einsum(ⅈ#39; a)等效于np.trace(a)。

在隐式模式下,选择的下标很重要,因为输出的轴按字母顺序重新排序。这意味着np.einsum(' ij&#39 ;, a)不会影响2D数组,而np.einsum(' ji&#39 ;, a)将对其进行转置。此外,np.einsum(' ij,jk&#39 ;, a,b)返回矩阵乘法,而np.einsum(' ij,jh&#39 ;, a,b)返回转置。因为下标'h'在下标'i'之前,所以是乘法的乘积。

在显式模式下,可以通过指定输出下标标签直接控制输出。这需要标识符“->”以及输出下标标签列表。此功能增加了功能的灵活性,因为可以在需要时禁用或强制求和。调用np.einsum(' i-&gt ;, a)就像np.sum(a,axis = -1)和np.einsum(' ii-> i&# 39; a)类似于np.diag(a),不同之处在于einsum默认情况下不允许广播,另外np.einsum(&#39,ij,jh-> ih&#39 ;, a,b)直接指定输出下标标签的顺序,因此返回矩阵乘法,这与上面的隐式模式示例不同。

要启用和控制广播,请使用省略号。 DefaultNumPy样式的广播是通过在每个术语的左侧添加一个省略号来完成的,例如np.einsum(< ii-> ... i&#39 ;, a)。最后一个轴,您可以执行np.einsum(&i ... i&#39 ;, a),或者使用最左边的索引而不是最右边的索引来做矩阵矩阵乘积,就可以执行np.einsum (',jk ...-> ik ...',a,b)。

当只有一个操作数时,没有轴求和,也没有提供outputparameter,则返回对该操作数的视图,而不是新的数组。因此,将对角线作为np.einsum(ii-i' a)产生视图(在版本1.10.0中进行了更改)。

einsum还提供了另一种方式来提供下标和操作数作为einsum(op0,sublist0,op1,sublist1,...,[sublistout])。如果未以这种格式提供输出形状,einsum将以隐式模式进行计算,否则下面的示例具有使用twoparameter方法的对应einsum调用。

现在,只要输入数组可写,从einsum返回的视图就可以写。例如,np.einsum(< ijk ...-> kji ...&#39 ;, a)现在将具有与np.swapaxes(a,0,2)和np.einsum( < ii-> i',a)将返回2D数组对角线的可写视图。

添加了optimize参数,该参数将优化einsum表达式的收缩顺序。对于具有三个或更多操作数的压缩,这可以大大提高计算效率,但需要在计算过程中增加内存占用量。

通常,采用“贪心”算法,根据经验测试,该算法在大多数情况下会返回最佳路径。在某些情况下,“最优”将通过更昂贵,更详尽的搜索返回最高级路径。对于迭代计算,建议最好计算一次最佳路径并通过将其作为参数重用该路径。下面给出一个例子。

>>> np。 einsum(' ii-" i,a)array([0,6,12,18,24])> np。 einsum(a,[0,0],[0])array([0,6,12,18,24])> np。诊断(a)数组([0,6,12,18,24])

>>> np。 einsum(< ij-> i',a)array([10,35,60,85,110])> np。 einsum(a,[0,1],[0])数组([10,35,60,85,110]) np。总和(a,轴= 1)数组([10,35,60,85,110])

>>> np。 einsum(' ... j-> ...' a)数组([10,35,60,85,110])> np。 einsum(a,[椭圆,1],[椭圆])数组([10,35,60,85,110])

>>> np。 einsum(< ji',c)array([[0,3],[1,4],[2,5]])> np。 einsum(< ij-> ji',c)array([[0,3],[1,4],[2,5]])> np。 einsum(c,[1,0])array([[0,3],[1,4],[2,5]])> np。转置(c)数组([[0,3],[1,4],[2,5]])

>>> np。 einsum(' ij,j',a,b)数组([30,80,130,180,230]) np。 einsum(a,[0,1,b,[1])数组([30,80,130,180,230]) np。点(a,b)数组([30,80,130,180,230])> np。 einsum(' ... j,j',a,b)数组([30,80,130,180,230])

>>> np。 einsum(' ...,...',3,c)array([[0,3,6],[9,12,15]])> np。 einsum(',ij',3,c)array([[0,3,6],[9,12,15]]) np。 einsum(3,[省略号],c,[省略号])数组([[0,3,6],[9,12,15]]) np。乘以(3,c)数组([[0,3,6],[9,12,15]])

>>> np。 einsum(&#39,i&j39;,np。arange(2)+ 1,b)array([[0,1,2,3,4],[0,2,4,6,8] ])>> np。 einsum(np。arange(2)+1,[0],b,[1])数组([[0,1,2,3,4],[0,2,4,6,8]])&gt ;>> np。外部(np。arange(2)+1,b)数组([[0,1,2,3,4],[0,2,4,6,6,8]])

>>> a = np。范围(60.)。重塑(3、4、5)>> b = np。范围(24.)。重塑(4、3、2)>> np。 einsum(< ijk,jil-> kl',a,b)数组([[4400.,4730.],[4532.,4874.],[4664.,5018.],[4796 。,5162.],[4928.,5306.]])>> np。 einsum(a,[0,1,2],b,[1,0,3],[2,3])数组([[4400.,4730.],[4532.,4874.],[4664。 ,[5018。],[4796.,5162。],[4928.,5306。]])>> np。张量点(a,b,轴=([1,0],[0,1]))数组([[4400.,4730.],[4532.,4874.],[4664.,5018.],[ 4796.,5162.],[4928.,5306.]])

>>> a = np。零((3,3))>> np。 einsum(' ii-i',a)[:] = 1>>数组([[1.,0.,0.],[0.,1.,0.],[0.,0.,1.]])

>>> a = np。范围(6)。重塑((3,2))> b = np。范围(12)。重塑((4,3))> np。 einsum(' ki,jk-> ij',a,b)数组([[10,28,46,64],[13,40,67,94]]) ; np。 einsum(' ... k-> i ...',a,b)数组([[10,28,46,64],[13,40,67,94] ])>> np。 einsum(',jk',a,b)数组([[10,28,46,64],[13,40,67,94]])

链式数组操作。对于更复杂的收缩,可以通过重复计算“贪婪”路径或预先计算“最佳”路径并使用einsum_path插入(自1.12.0版开始)重复应用来实现加速。对于较大的阵列,性能改进尤其重要: