设置(M x N x N)矩阵对角线的快速方法? Einsum/n维fill_diagonal?
Fast way to set diagonals of an (M x N x N) matrix? Einsum / n-dimensional fill_diagonal?
我正在尝试编写基于矩阵的快速优化代码,并且最近发现 einsum 作为实现显着加速的工具。
是否可以使用它来有效地设置多维数组的对角线,还是只能使用 return 数据?
在我的问题中,我试图通过对每个方阵 (N x N) 中的列求和来设置方阵数组(形状:M x N x N)的对角线。
我当前的(缓慢的,基于循环的)解决方案是:
# Build dummy array
dimx = 2 # Dimension x (likely to be < 100)
dimy = 3 # Dimension y (likely to be between 2 and 10)
M = np.random.randint(low=1, high=9, size=[dimx, dimy, dimy])
# Blank the diagonals so we can see the intended effect
np.fill_diagonal(M[0], 0)
np.fill_diagonal(M[1], 0)
# Compute diagonals based on summing columns
diags = np.einsum('ijk->ik', M)
# Set the diagonal for each matrix
# THIS IS LOW. CAN IT BE IMPROVED?
for i in range(len(M)):
np.fill_diagonal(M[i], diags[i])
# Print result
M
请问这可以改进吗?似乎 np.fill_diagonal 不接受非方矩阵(因此强制使用基于循环的解决方案)。或许 einsum 也可以提供帮助?
一种方法是重塑为 2D
,在 ncols+1
步长处使用对角线值设置列。重塑创建一个视图,因此允许我们直接访问那些对角线位置。因此,实现将是 -
s0,s1,s2 = M.shape
M.reshape(s0,-1)[:,::s2+1] = diags
如果你这样做 np.source(np.fill_diagonal)
你会看到在 2d 情况下它使用 'strided' 方法
if a.ndim == 2:
step = a.shape[1] + 1
end = a.shape[1] * a.shape[1]
a.flat[:end:step] = val
@Divakar's
解决方案通过 'flattening' 在 2 维上将此应用于您的 3d 案例。
您可以用 M.sum(axis=1)
对列求和。尽管我依稀记得一些时间发现 einsum
实际上要快一点。 sum
比较常规。
有人要求能够在 einsum
中扩展维度,但我认为这不会实现。
我正在尝试编写基于矩阵的快速优化代码,并且最近发现 einsum 作为实现显着加速的工具。
是否可以使用它来有效地设置多维数组的对角线,还是只能使用 return 数据?
在我的问题中,我试图通过对每个方阵 (N x N) 中的列求和来设置方阵数组(形状:M x N x N)的对角线。
我当前的(缓慢的,基于循环的)解决方案是:
# Build dummy array
dimx = 2 # Dimension x (likely to be < 100)
dimy = 3 # Dimension y (likely to be between 2 and 10)
M = np.random.randint(low=1, high=9, size=[dimx, dimy, dimy])
# Blank the diagonals so we can see the intended effect
np.fill_diagonal(M[0], 0)
np.fill_diagonal(M[1], 0)
# Compute diagonals based on summing columns
diags = np.einsum('ijk->ik', M)
# Set the diagonal for each matrix
# THIS IS LOW. CAN IT BE IMPROVED?
for i in range(len(M)):
np.fill_diagonal(M[i], diags[i])
# Print result
M
请问这可以改进吗?似乎 np.fill_diagonal 不接受非方矩阵(因此强制使用基于循环的解决方案)。或许 einsum 也可以提供帮助?
一种方法是重塑为 2D
,在 ncols+1
步长处使用对角线值设置列。重塑创建一个视图,因此允许我们直接访问那些对角线位置。因此,实现将是 -
s0,s1,s2 = M.shape
M.reshape(s0,-1)[:,::s2+1] = diags
如果你这样做 np.source(np.fill_diagonal)
你会看到在 2d 情况下它使用 'strided' 方法
if a.ndim == 2:
step = a.shape[1] + 1
end = a.shape[1] * a.shape[1]
a.flat[:end:step] = val
@Divakar's
解决方案通过 'flattening' 在 2 维上将此应用于您的 3d 案例。
您可以用 M.sum(axis=1)
对列求和。尽管我依稀记得一些时间发现 einsum
实际上要快一点。 sum
比较常规。
有人要求能够在 einsum
中扩展维度,但我认为这不会实现。