快速向量 - “对角线”矩阵乘法

计算科学 线性代数 矩阵 拉帕克 布拉斯
2021-12-21 21:01:30

1Rd是一个所有元素都等于的向量1. 定义:

D=diag(1,1,,1)=[111111]Rd×d2

我想计算Dx对于任何向量xRd2. 有人可以建议我一种有效计算该产品的方法吗?(自从D有一个很特殊的结构,我想应该有这样的方式)。

先感谢您。

3个回答

这可以解释为对一个张量的索引求和,当向量x被重新塑造成一个数字框而不是一个列表。特别是,如果X是个d-by-d折叠版x,那么你正在做的操作是,

Dx=vec((I1)vec(X))=vec(1TXI)=vec(1TX).

执行此操作的 matlab 代码非常简单。它是,

sum(reshape(x,d,d))'

这是它的一个实际示例 - 您可以看到它远远优于标准密集乘法、稀疏矩阵乘法和 for 循环版本:

>> onesmatrixquestion
dense matrix multiply
Elapsed time is 0.000873 seconds.
sparse matrix multiply
Elapsed time is 0.000115 seconds.
for loop version
Elapsed time is 0.000154 seconds.
tensorized version
Elapsed time is 0.000018 seconds.

这是生成这些计时结果的代码:

%onesmatrixquestion.m
d = 100;
onevec = ones(1,d);
D = kron(eye(d,d),onevec);
Dsparse = sparse(D);

x = randn(d^2,1);

disp('dense matrix multiply')
tic
aa = D*x;
toc

disp('sparse matrix multiply')
tic
bb = Dsparse*x;
toc

disp('for loop version')
tic
cc = zeros(d,1);
ind = 1;
for kk=1:d
    for jj=1:d
        cc(kk) = cc(kk) + x(ind);
        ind = ind + 1;
    end
end
toc

disp('tensorized version')
tic
dd = sum(reshape(x,d,d))';
toc

if (norm(aa - bb) > 1e-9 || norm(bb - cc) > 1e-9 ...
        || norm(cc - dd) > 1e-9)
    disp('error: different methods give different results')
end

这相当于计算连续连续子向量的总和x. 如果你有一个自动矢量化编译器,你不会比简单的手工编码嵌套循环做得更好,因为你可能会受到内存带宽的限制d.

编辑:删除了令人困惑的代码


是的,有一个捷径,这里有一些 Python 代码:



import numpy as np

d = 3


D = np.repeat(np.identity(d), d, axis=1)
print('D:')
print D
print


print('x:')
x = np.arange(d*d, dtype=float)
print x
print


print('D * x:')
print D.dot(x)
print


print('shortcut:')
print x.reshape((d, d)).sum(axis=1)
print

输出:


丁:
[[ 1. 1. 1. 0. 0. 0. 0. 0. 0.]
 [ 0. 0. 0. 1. 1. 1. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 1. 1. 1.]]


X:
[ 0. 1. 2. 3. 4. 5. 6. 7. 8.]


D * x:
[3. 12. 21.]


捷径:
[3. 12. 21.]