计算张量的有效方法
Efficient way to compute a tensor
假设c
是一个d维向量。我想计算以下三阶张量
其中e_i
代表欧氏space的第i
个标准基。有没有一种有效的方法来计算这个?我正在使用以下 for 循环和 Kruskal 张量 ktensor
来计算它,使用由桑迪亚国家实验室管理的 tensor toolbox:
x=ktensor({c,c,c});
I=eye(d);
for i=1:d
x=x+2*c(i)*ktensor({I(:,i),I(:,i),I(:,i)}
end
for i=1:d
for j=1:d
x=x- c(i)*c(j)*(ktensor({I(:,i),I(:,i),I(:,j)})+ktensor({I(:,i),I(:,j),I(:,i)})+ktensor({I(:,i),I(:,j),I(:,j)}))
end
end
这里有一个可能性。
- 我对第二项进行了优化,因为它将
c
的值沿张量的 "diagonal" 放置。
- 对于第一项,没有太大的优化空间,因为它是一个密集的乘法,所以
bsxfun
似乎是合适的。
- 对于第三项,我坚持
bsxfun
,但由于结果有点稀疏,如果矩阵的大小较大,您可能会受益于填充它 "by hand"。
代码如下:
dim = 10;
c = [1:dim]';
e = eye(dim);
x = zeros([dim, dim, dim]);
% initialize with second term
x(1:dim*(dim+1)+1:end) = 2 * c;
% add first term
x = x + bsxfun(@times, bsxfun(@times, c, shiftdim(c, -1)), shiftdim(c, -2));
% add third term
x = x - sum(sum(bsxfun(@times, shiftdim(c*c',-3), ...
bsxfun(@times, bsxfun(@times, permute(e, [1, 3, 4, 2, 5]), permute(e, [3, 1, 4, 2, 5])), permute(e, [3, 4, 1, 5, 2])) +...
bsxfun(@times, bsxfun(@times, permute(e, [1, 3, 4, 2, 5]), permute(e, [3, 1, 4, 5, 2])), permute(e, [3, 4, 1, 2, 5])) +...
bsxfun(@times, bsxfun(@times, permute(e, [1, 3, 4, 5, 2]), permute(e, [3, 1, 4, 2, 5])), permute(e, [3, 4, 1, 2, 5]))), 5), 4);
编辑
第三项的更高效(尤其是内存方面)计算:
ec = bsxfun(@times, e, c);
x = x - ...
bsxfun(@times, ec, shiftdim(c, -2)) -...
bsxfun(@times, c', reshape(ec, [dim, 1, dim])) -....
bsxfun(@times, c, reshape(ec, [1, dim, dim]));
您可以尝试 Parallel Computing Toolbox that is namely parfor
循环。
x=ktensor({c,c,c});
I=eye(d);
y = zeros(d,d,d, d);
parfor i=1:d
y(:,:,:, i) = 2*c(i)*ktensor({I(:,i),I(:,i),I(:,i)};
end
x = x + sum(y, 4);
z = zeros(d,d,d, d,d);
parfor i=1:d
for j=1:d % only one layer of parallelization is allowed
z(:,:,:, i,j) = c(i)*c(j)*(ktensor({I(:,i),I(:,i),I(:,j)})+ktensor({I(:,i),I(:,j),I(:,i)})+ktensor({I(:,i),I(:,j),I(:,j)}));
end
end
x = x - sum(sum(z, 5), 4);
x % is your result
它只运行未修改的 ktensor
命令,但在单独的线程中,因此工具箱会并行处理 运行 代码。
因为每次迭代的独立性属性,这意味着,例如c_{i+1, j+1}
不依赖c_{i, j}
,这是可能的。
根据您系统的内核(和超线程)数量,可能会有多达#-of-cores-times 的加速。
假设c
是一个d维向量。我想计算以下三阶张量
其中e_i
代表欧氏space的第i
个标准基。有没有一种有效的方法来计算这个?我正在使用以下 for 循环和 Kruskal 张量 ktensor
来计算它,使用由桑迪亚国家实验室管理的 tensor toolbox:
x=ktensor({c,c,c});
I=eye(d);
for i=1:d
x=x+2*c(i)*ktensor({I(:,i),I(:,i),I(:,i)}
end
for i=1:d
for j=1:d
x=x- c(i)*c(j)*(ktensor({I(:,i),I(:,i),I(:,j)})+ktensor({I(:,i),I(:,j),I(:,i)})+ktensor({I(:,i),I(:,j),I(:,j)}))
end
end
这里有一个可能性。
- 我对第二项进行了优化,因为它将
c
的值沿张量的 "diagonal" 放置。 - 对于第一项,没有太大的优化空间,因为它是一个密集的乘法,所以
bsxfun
似乎是合适的。 - 对于第三项,我坚持
bsxfun
,但由于结果有点稀疏,如果矩阵的大小较大,您可能会受益于填充它 "by hand"。
代码如下:
dim = 10;
c = [1:dim]';
e = eye(dim);
x = zeros([dim, dim, dim]);
% initialize with second term
x(1:dim*(dim+1)+1:end) = 2 * c;
% add first term
x = x + bsxfun(@times, bsxfun(@times, c, shiftdim(c, -1)), shiftdim(c, -2));
% add third term
x = x - sum(sum(bsxfun(@times, shiftdim(c*c',-3), ...
bsxfun(@times, bsxfun(@times, permute(e, [1, 3, 4, 2, 5]), permute(e, [3, 1, 4, 2, 5])), permute(e, [3, 4, 1, 5, 2])) +...
bsxfun(@times, bsxfun(@times, permute(e, [1, 3, 4, 2, 5]), permute(e, [3, 1, 4, 5, 2])), permute(e, [3, 4, 1, 2, 5])) +...
bsxfun(@times, bsxfun(@times, permute(e, [1, 3, 4, 5, 2]), permute(e, [3, 1, 4, 2, 5])), permute(e, [3, 4, 1, 2, 5]))), 5), 4);
编辑
第三项的更高效(尤其是内存方面)计算:
ec = bsxfun(@times, e, c);
x = x - ...
bsxfun(@times, ec, shiftdim(c, -2)) -...
bsxfun(@times, c', reshape(ec, [dim, 1, dim])) -....
bsxfun(@times, c, reshape(ec, [1, dim, dim]));
您可以尝试 Parallel Computing Toolbox that is namely parfor
循环。
x=ktensor({c,c,c});
I=eye(d);
y = zeros(d,d,d, d);
parfor i=1:d
y(:,:,:, i) = 2*c(i)*ktensor({I(:,i),I(:,i),I(:,i)};
end
x = x + sum(y, 4);
z = zeros(d,d,d, d,d);
parfor i=1:d
for j=1:d % only one layer of parallelization is allowed
z(:,:,:, i,j) = c(i)*c(j)*(ktensor({I(:,i),I(:,i),I(:,j)})+ktensor({I(:,i),I(:,j),I(:,i)})+ktensor({I(:,i),I(:,j),I(:,j)}));
end
end
x = x - sum(sum(z, 5), 4);
x % is your result
它只运行未修改的 ktensor
命令,但在单独的线程中,因此工具箱会并行处理 运行 代码。
因为每次迭代的独立性属性,这意味着,例如c_{i+1, j+1}
不依赖c_{i, j}
,这是可能的。
根据您系统的内核(和超线程)数量,可能会有多达#-of-cores-times 的加速。