Python numpy.einsum的输出形状

Python numpy.einsum的输出形状,python,numpy,numpy-einsum,Python,Numpy,Numpy Einsum,在给定einsum的输入参数(不运行计算)的情况下,是否有一种优雅的方法来预计算np.einsum结果的形状 #给出a、b和签名 #a.shape==(1,2,5) #b.形状==(4,5) einsum#u形状('ijk,mk->ik',a,b)#返回(1,5) 这里有些东西适用于一般输入数和相关的einsum表达式,也适用于特定的标量缩减情况- def einsum_outshape(einsum_expr, inputs): shps = np.concatenate([in_.s

在给定einsum的输入参数(不运行计算)的情况下,是否有一种优雅的方法来预计算
np.einsum
结果的形状

#给出a、b和签名
#a.shape==(1,2,5)
#b.形状==(4,5)
einsum#u形状('ijk,mk->ik',a,b)#返回(1,5)

这里有些东西适用于一般输入数和相关的einsum表达式,也适用于特定的标量缩减情况-

def einsum_outshape(einsum_expr, inputs):
    shps = np.concatenate([in_.shape for in_ in inputs])
    p = einsum_expr.split(',')
    s = p[:-1] + p[-1].split('->')
    if s[-1]=='':
        return ()
    else:
        inop = list(map(list,s))
        return tuple(shps[(np.concatenate(inop[:-1])[:,None]==inop[-1]).argmax(0)])
样本运行-

In [42]: a = np.random.rand(1,2,5)
    ...: b = np.random.rand(4,5)
    ...: c = np.random.rand(5,7,8)
    ...: d = np.random.rand(7,9)

In [43]: einsum_outshape('ijk,mk,kpq,pr->ikpqr', inputs=(a,b,c,d))
Out[43]: (1, 5, 7, 8, 9)

# Reduction to a scalar
In [44]: einsum_outshape('ijk,mk,kpq,pr->', inputs=(a,b,c,d))
Out[44]: ()

根据@Divakar的回答,我提出了以下内容,如果传递了不受支持的下标字符串,则可读性更高,并会引发错误

def einsum_outshape(下标,*operants):
“”“从'numpy.einsum'计算输出的形状。”。
不支持省略号。
"""
如果下标中有“.”:
raise VALUERROR(不支持f'省略号:{subscripts}')
insubs,outsubs=下标。替换(“,”,“”)。拆分(“->”)
如果outsubs==“”:
返回()
insubs=np.数组(列表(insubs))
innumber=np.concatenate([op.shape表示运算符中的op])
超出形状=[]
对于UBS中的o:
指数,=np,其中(insubs==o)
尝试:
append(innumber[Indexes].max())
除值错误外:
raise VALUERROR(f'无效下标:{subscripts}')
返回元组(outshape)

形状是
ik
,其中
i
a
的第一个维度,
k
是最后一个维度(同时是
a
b
)。是的,这很清楚。我在寻找一个函数,它可以让einsum的输出形状为einsum的结果预先分配数组。为什么要预先分配那个数组?我相信
out
参数是最近才出现的。打一次电话到
einsum
我想这不会给你带来任何好处。重复调用同一个
einsum
表达式可能会有所帮助,但您可以从第一个表达式中选择形状。@fhcll发布的解决方案对您有用吗?@hpaulj在我的代码
einsum
中被多次调用,并填充一个更大的预分配数组。预先分配该数组,而不是连接
einsum
的输出,感觉更自然,尽管我不知道它是否快得多。也许在记忆力方面更好?