优化稀疏矩阵的加权和

发布于 2024-10-20 03:46:29 字数 646 浏览 6 评论 0 原文

我欢迎对以下代码优化问题提供任何帮助:

我有一个 N 个大小相同的稀疏矩阵 ([s1 s2]) 的集合,存储在元胞数组 A 和存储在向量w中的相应数量的标量权重。我想计算 A 中所有矩阵的总和,并按 w 中存储的值加权。通过我的程序的迭代,只有 w 中的值发生变化。因此,我可以先验地计算结果中非零元素的数量,并使用 spalloc 为其预先分配一些内存。
目前我有这样的想法:

result = spalloc(s1,s1,number_of_non_zero);
for i=1:N
    result = result + w(i)*A{i};
end

我真的需要优化这部分,目前它占用了我程序中的大部分计算时间(使用分析工具检查)。
一些附加信息:
-上述代码运行了数百万次,因此即使是很小的改进也是受欢迎的。
-A 中的矩阵来自有限元代码(一维或二维)
-如果我可以节省一些时间(例如使用cell2mat(A)),我可以毫无问题地离开单元结构。

感谢您提供有关如何加快这部分代码速度的任何提示。

一个。

I welcome any help for the following code optimization problem:

I have a collection of N sparse matrices of identical sizes ([s1 s2]) stored in a cell array A and a corresponding number of scalar weights stored in an vector w. I want to compute the sum of all the matrices in A weighted by the values stored in w. Through the iterations of my program, only the values in wchange. I can therefore compute a priori the number of non-zero elements in my result and pre-allocate some memory for it using spalloc.
For the moment I have something like:

result = spalloc(s1,s1,number_of_non_zero);
for i=1:N
    result = result + w(i)*A{i};
end

I really need do optimize this part which for the moment takes most of the computing time in my program (checked with the profiling tools).
Some additional information:
-The above code runs millions of times so even minor improvements are welcome.
-The matrices in A come from a finite element code (1D or 2D)
-I have no problem moving away from the cell structure if I can save some time (like using cell2mat(A))

Thank you for any hint on how to speed up this part of the code.

A.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

(り薆情海 2024-10-27 03:46:29

我不能肯定地说这个解决方案是否会更具计算效率,但它是其他可以尝试的东西......

如果你真的必须将你的矩阵表示为稀疏矩阵(即完整矩阵占用太多内存)并且 MATLAB 中的内置稀疏表示 无法提供您想要的性能,那么你可以尝试用不同的方式表示稀疏矩阵。具体来说,您可以将它们表示为 N×3 矩阵,其中前两列包含所有非零值的矩阵行索引和列索引,第三列包含非零值。您可以使用函数 FIND 将数据转换为这种形式,如下所示:

for iMatrix = 1:numel(A)
  [r,c,v] = find(A{iMatrix});
  A{iMatrix} = [r c v];
end

每次需要计算这些矩阵的加权和时,首先需要将这些值乘以权重:

B = A;  %# Store a temporary copy of A
for iMatrix = 1:numel(B)
  B{iMatrix}(:,3) = w(iMatrix).*B{iMatrix}(:,3);
end

然后,您可以使用函数 ACCUMARRAY

B = vertcat(B{:});  %# Convert B from a cell array to an N-by-3 matrix
result = accumarray(B(:,1:2),B(:,3));

在这种情况下,变量 result 将是一个完整的矩阵。如果您需要 result 为稀疏矩阵,您可以在对 ACCUMARRAY 像这样:

result = accumarray(B(:,1:2),B(:,3),[],[],[],true);

I can't say for sure if this solution will be more computationally-efficient, but it's something else to try...

If you really have to represent your matrices as sparse (i.e. full matrices take up too much memory) and the built-in sparse representation in MATLAB isn't giving you the performance you desire, then you can try representing the sparse matrices in a different way. Specifically, you can represent them as N-by-3 matrices where the first two columns contain the row and column indices into the matrix for all the non-zero values and the third column contains the non-zero values. You can convert your data to this form using the function FIND like so:

for iMatrix = 1:numel(A)
  [r,c,v] = find(A{iMatrix});
  A{iMatrix} = [r c v];
end

Each time you need to compute the weighted sum of these matrices, you first need to multiply the values by the weights:

B = A;  %# Store a temporary copy of A
for iMatrix = 1:numel(B)
  B{iMatrix}(:,3) = w(iMatrix).*B{iMatrix}(:,3);
end

Then, you can compute the final sum using the function ACCUMARRAY:

B = vertcat(B{:});  %# Convert B from a cell array to an N-by-3 matrix
result = accumarray(B(:,1:2),B(:,3));

The variable result in this case will be a full matrix. If you need result to be a sparse matrix, you can add extra arguments in the call to ACCUMARRAY like so:

result = accumarray(B(:,1:2),B(:,3),[],[],[],true);
み青杉依旧 2024-10-27 03:46:29

如果将 A 转换为矩阵而不是元胞数组,那么您可以使用一些 RESHAPEREPMAT杂技。假设我们有以下数据:

>> A(:,:,1) = [1 0 0; 0 0 2; 0 0 0];
>> A(:,:,2) = [3 0 1; 0 3 0; 0 1 0]

A(:,:,1) =

     1     0     0
     0     0     2
     0     0     0


A(:,:,2) =

     3     0     1
     0     3     0
     0     1     0

>> w = [2; 3]

w =

     2
     3

重塑 w 以便您可以进行逐个元素的乘法,然后求和:

>> w = reshape(w, [1 1 length(w)])

w(:,:,1) =

     2


w(:,:,2) =

     3

>> w = repmat(w, [size(A,1) size(A,2) 1])

w(:,:,1) =

     2     2     2
     2     2     2
     2     2     2


w(:,:,2) =

     3     3     3
     3     3     3
     3     3     3

>> w .* A

ans(:,:,1) =

     2     0     0
     0     0     4
     0     0     0


ans(:,:,2) =

     9     0     3
     0     9     0
     0     3     0

>> sum(w .* A, 3)

ans =

    11     0     3
     0     9     4
     0     3     0

If you convert A to a matrix instead of a cell array then you could vectorize the loop using some RESHAPE and REPMAT acrobatics. Pretend we have the following data:

>> A(:,:,1) = [1 0 0; 0 0 2; 0 0 0];
>> A(:,:,2) = [3 0 1; 0 3 0; 0 1 0]

A(:,:,1) =

     1     0     0
     0     0     2
     0     0     0


A(:,:,2) =

     3     0     1
     0     3     0
     0     1     0

>> w = [2; 3]

w =

     2
     3

Reshape w so that you can do an element-by-element multiplication and then sum:

>> w = reshape(w, [1 1 length(w)])

w(:,:,1) =

     2


w(:,:,2) =

     3

>> w = repmat(w, [size(A,1) size(A,2) 1])

w(:,:,1) =

     2     2     2
     2     2     2
     2     2     2


w(:,:,2) =

     3     3     3
     3     3     3
     3     3     3

>> w .* A

ans(:,:,1) =

     2     0     0
     0     0     4
     0     0     0


ans(:,:,2) =

     9     0     3
     0     9     0
     0     3     0

>> sum(w .* A, 3)

ans =

    11     0     3
     0     9     4
     0     3     0
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文