向量化矩阵中不同对角线的总和

问题描述:

我想向量化以下MATLAB代码。我认为这一定很简单,但我觉得它很混乱。向量化矩阵中不同对角线的总和

r = some constant less than m or n 
[m,n] = size(C); 
S = zeros(m-r,n-r); 
for i=1:m-r+1 
    for j=1:n-r+1 
     S(i,j) = sum(diag(C(i:i+r-1,j:j+r-1))); 
    end 
end 

的代码计算得分的表,小号,对于动态规划算法,从另一个得分表,Ç
对角线求和是针对所有可能的部分(大小为r)生成用于生成的各个数据片段的分数,所述数据用于生成C

在此先感谢您的任何答案!很抱歉,如果这一块应该是显而易见的......

注意
内置CONV2竟然是比convnfft更快,因为我的眼睛(R)是相当小的(5 < = R < = 20) 。 convnfft.m指出r应该是> 20以表示任何好处。

如果我理解正确,你试图计算C的每个子数组的对角线总和,你已经删除C的最后一行和一列(如果你不应该删除行/列,你需要循环到m-r + 1,并且您需要将整个数组C传递给我的解决方案中的函数)。

您可以通过convolution做这个手术,就像这样:

S = conv2(C(1:end-1,1:end-1),eye(r),'valid'); 

如果C和R都很大,你可能想看看CONVNFFT从MATLAB文件交换来加快计算。

+0

太棒了,谢谢。 明天我会看看CONVNFFT。在我用于测试的数据子集(比实际数据大约小500倍)上,与循环相比,内置的conv2函数实现了69,652次调用次数减少和34.56次执行时间减少(23.5 vs 0.68秒)。 – 2010-05-19 12:33:12

我认为你可能需要将C重新排列成3D矩阵,然后沿着其中一个维度求和它。我会尽快发布答案。

编辑

我没能找到一个方法来清洁它vectorise,但我没有找到功能accumarray,这可能有一定的帮助。当我回家时,我会更详细地看它。

EDIT#2

实测值利用线性索引更简单的解决方案,但是这可能是存储器密集型的。在C(1,1)处,我们想要求和的索引是1+ [0,m + 1,2 * m + 2,3 * m + 3,4 * m + 4,...] ,或(0:R-1)+(0:M:(R-1)* M)

sum_ind = (0:r-1)+(0:m:(r-1)*m); 

创建S_offset,一个(MR)通过(NR)中的R矩阵,使得S_offset(: ,:,1)= 0,S_offset(:,:2)= m + 1,S_offset(:,:3)= 2 * m + 2,依此类推。

S_offset = permute(repmat(sum_ind, [m-r, 1, n-r]), [1, 3, 2]); 

创建S_base,基地阵列地址的矩阵,从中计算偏移量。

S_base = reshape(1:m*n,[m n]); 
S_base = repmat(S_base(1:m-r,1:n-r), [1, 1, r]); 

最后,使用S_base+S_offset解决C.

S = sum(C(S_base+S_offset), 3); 

你可以,当然,使用bsxfun等方法,使之更加高效;在这里我选择了为了清晰起见。我还没有对此进行基准测试,以了解它如何与双循环方法进行比较;我需要先回家吃晚饭!

+0

嗯,与从二维索引对角线成为该索引的第三维? – 2010-05-19 09:36:27

+1

@JS:好主意。 'im2col'可能可以为你节省几行代码。 – Jonas 2010-05-20 01:30:58

+0

@Jonas:我添加了一个完全相同的解决方案! – Amro 2010-05-21 21:02:12

基于对JS的想法,并且如Jonas在评论所指出的,这可以在使用IM2COL一些数组操作两行来完成:

B = im2col(C, [r r], 'sliding'); 
S = reshape(sum(B(1:r+1:end,:)), size(C)-r+1); 

基本上B包含所有滑动块的元素的矩阵r-by-r在矩阵C上。然后我们将这些块的每个块的对角线上的元素B(1:r+1:end,:),计算它们的总和,并将结果重塑为预期的大小。


比较这由乔纳斯基于卷积的解决方案,这并不执行任何矩阵乘法,只有索引...

+0

如果你能负担得起内存,im2col通常是一个很好的选择。 – Jonas 2010-05-21 22:34:30

+0

im2col返回值而不是索引,所以第二行应该有'reshape(sum(B(1:r + 1:end,:))),size(C)-r + 1);'。 – 2010-11-26 00:27:21

+0

@reve_etrange:你说的很对,谢谢指出 – Amro 2010-11-26 05:20:44

这是你在找什么?该函数添加对角线并将它们放入一个类似于函数'sum'将矩阵中的所有列相加并将其放入向量中的方式的向量。

function [diagSum] = diagSumCalc(squareMatrix, LLUR0_ULLR1) 
% 
% Input: squareMatrix: A square matrix. 
%  LLUR0_ULLR1: LowerLeft to UpperRight addition = 0  
%      UpperLeft to LowerRight addition = 1 
% 
% Output: diagSum: A vector of the sum of the diagnols of the matrix. 
% 
% Example: 
% 
% >> squareMatrix = [1 2 3; 
%     4 5 6; 
%     7 8 9]; 
% 
% >> diagSum = diagSumCalc(squareMatrix, 0); 
% 
% diagSum = 
% 
%  1 6 15 14 9 
% 
% >> diagSum = diagSumCalc(squareMatrix, 1); 
% 
% diagSum = 
% 
%  7 12 15 8 3 
% 
% Written by M. Phillips 
% Oct. 16th, 2013 
% MIT Open Source Copywrite 
% Contact [email protected] fmi. 
% 

if (nargin < 2) 
    disp('Error on input. Needs two inputs.'); 
    return; 
end 

if (LLUR0_ULLR1 ~= 0 && LLUR0_ULLR1~= 1) 
    disp('Error on input. Only accepts 0 or 1 as input for second condition.'); 
    return; 
end 

[M, N] = size(squareMatrix); 

if (M ~= N) 
    disp('Error on input. Only accepts a square matrix as input.'); 
    return; 
end 

diagSum = zeros(1, M+N-1); 

if LLUR0_ULLR1 == 1 
    squareMatrix = rot90(squareMatrix, -1); 
end 

for i = 1:length(diagSum) 
    if i <= M 
     countUp = 1; 
     countDown = i; 
     while countDown ~= 0 
      diagSum(i) = squareMatrix(countUp, countDown) + diagSum(i); 
      countUp = countUp+1; 
      countDown = countDown-1; 
     end 
    end 
    if i > M 
     countUp = i-M+1; 
     countDown = M; 
     while countUp ~= M+1 
      diagSum(i) = squareMatrix(countUp, countDown) + diagSum(i); 
      countUp = countUp+1; 
      countDown = countDown-1; 
     end 
    end 
end 

干杯