解释numpy';埃因苏姆酒店

解释numpy';埃因苏姆酒店,numpy,numpy-ndarray,numpy-einsum,Numpy,Numpy Ndarray,Numpy Einsum,我目前正在做一些关于用einsum函数计算numpy中的四阶张量的研究 我正在计算的张量是用爱因斯坦符号写的,函数einsun做得很好!但我想知道它在以下情况下做了什么: import numpy as np a=np.array([[2,0,3],[0,1,0],[0, 0, 4]]) b= np.eye(3) r1=np.einsum("ij,kl->ijkl", a, b) r2=np.einsum("ik,jl->ijkl", a,

我目前正在做一些关于用einsum函数计算numpy中的四阶张量的研究

我正在计算的张量是用爱因斯坦符号写的,函数einsun做得很好!但我想知道它在以下情况下做了什么:

import numpy as np

a=np.array([[2,0,3],[0,1,0],[0, 0, 4]])
b= np.eye(3)

r1=np.einsum("ij,kl->ijkl", a, b)
r2=np.einsum("ik,jl->ijkl", a, b)
r1
中,我基本上是在做标准的张量积(相当于
np.tensordot(a,b,axes=0)

r2
中呢

我知道我可以通过执行
a[:,None,:,None]*b[None,:,None,:]
来获取值,但我不知道索引在做什么。这个操作有名字吗


抱歉,如果这太基本了

我尝试使用转置定义来更改多个轴

它适用于
'ij,kl->ijkl'、'ik,jl->ijkl'、'kl,ij->ijkl'
但是对于“il,jk->ijkl”、“jl,ik->ijkl”和“jk,il->ijkl”失败。

import numpy as np

a=np.eye(3)
a[0][0]=2
a[0][-1]=3
a[-1][-1]=4

b=np.eye(3)

def permutation(str_,Arr):
    
    Arr=np.reshape(Arr,[3,3,3,3])
   
    def splitString(str_):
        tmp1=str_.split(',')
        tmp2=tmp1[1].split('->')
        str_idx1=tmp1[0]
        str_idx2=tmp2[0]
        str_idx_out=tmp2[1]
        return str_idx1,str_idx2, str_idx_out
    
    
    idx_a, idx_b, idx_out=splitString(str_)
    
    dict_={'i':0,'j':1,'k':2,'l':3}
    
    def split(word): 
        return [char for char in word]
                
    
    a,b=split(idx_a)
    c,d=split(idx_b)
    
    Arr=np.transpose(Arr,(dict_[a],dict_[b],dict_[c],dict_[d]))

    return Arr


str_='jk,il->ijkl'

d=np.outer(a,b)
f=np.einsum(str_, a,b)

check=permutation(str_,d)

if (np.count_nonzero(f-check)==0):
    print ('Code is working!')

else:
    print("Something is wrong...")

感谢您的建议

我尝试使用转置定义来更改多个轴

它适用于
'ij,kl->ijkl'、'ik,jl->ijkl'、'kl,ij->ijkl'
但是对于“il,jk->ijkl”、“jl,ik->ijkl”和“jk,il->ijkl”失败。

import numpy as np

a=np.eye(3)
a[0][0]=2
a[0][-1]=3
a[-1][-1]=4

b=np.eye(3)

def permutation(str_,Arr):
    
    Arr=np.reshape(Arr,[3,3,3,3])
   
    def splitString(str_):
        tmp1=str_.split(',')
        tmp2=tmp1[1].split('->')
        str_idx1=tmp1[0]
        str_idx2=tmp2[0]
        str_idx_out=tmp2[1]
        return str_idx1,str_idx2, str_idx_out
    
    
    idx_a, idx_b, idx_out=splitString(str_)
    
    dict_={'i':0,'j':1,'k':2,'l':3}
    
    def split(word): 
        return [char for char in word]
                
    
    a,b=split(idx_a)
    c,d=split(idx_b)
    
    Arr=np.transpose(Arr,(dict_[a],dict_[b],dict_[c],dict_[d]))

    return Arr


str_='jk,il->ijkl'

d=np.outer(a,b)
f=np.einsum(str_, a,b)

check=permutation(str_,d)

if (np.count_nonzero(f-check)==0):
    print ('Code is working!')

else:
    print("Something is wrong...")

感谢您的建议

r2
r1
基本上是相同的张量,但索引被重新排列。特别地,
r2[i,j,k,l]
等于
a[i,k]*b[k,l]

例如:

>>> r2[0,1,2,1]
3.0
这与
a[0,2]*b[1,1]
3*1
这一事实相对应,实际上是3


考虑这一点的另一种方法是观察
a[:,j,:,l]
在j==l时等于
a
,否则为零矩阵。

r2
r1
基本上是相同的张量,但索引被重新排列。特别地,
r2[i,j,k,l]
等于
a[i,k]*b[k,l]

例如:

>>> r2[0,1,2,1]
3.0
这与
a[0,2]*b[1,1]
3*1
这一事实相对应,实际上是3


思考这个问题的另一种方法是观察
a[:,j,:,l]
在j==l时等于
a
,反之则为零矩阵。

我认为
r1
r2
都是外积。第二个只是对4d结果的轴重新排序。矩阵积可以做同样的乘法,但它对一个或多个轴求和(共享索引)。在你的例子中,没有乘积之和
r1
也可以通过广播写入-只需重新排列
None
np。tensordot
重塑并转置输入,直到可以生成标准的2d
dot
产品,然后将结果转换回来。我的记忆是,单个数字轴参数被转换为轴的扩展元组。我发现
einsum
索引更清晰、更强大。至于你关于索引在做什么的问题,你的意思并不清楚,但听起来你好像在问
None
在做什么。它创建了一个大小为1的额外维度,这样数组就可以兼容乘法了。它被称为广播。r2只是R11的轴置换版本。我认为,
r1
r2
都是外部产品。第二个只是对4d结果的轴重新排序。矩阵积可以做同样的乘法,但它对一个或多个轴求和(共享索引)。在你的例子中,没有乘积之和
r1
也可以通过广播写入-只需重新排列
None
np。tensordot
重塑并转置输入,直到可以生成标准的2d
dot
产品,然后将结果转换回来。我的记忆是,单个数字轴参数被转换为轴的扩展元组。我发现
einsum
索引更清晰、更强大。至于你关于索引在做什么的问题,你的意思并不清楚,但听起来你好像在问
None
在做什么。它创建了一个大小为1的额外维度,这样数组就可以兼容乘法了。它被称为广播。r2只是r1的轴置换版本