Matlab 数组比较的矢量化

Matlab 数组比较的矢量化,matlab,vectorization,jit,Matlab,Vectorization,Jit,通过将数组中的一个元素与第二个数组中的一个或多个元素进行匹配,我创建了满射函数 为了只获得所述函数的双射元素,我向前运行相同的函数 Matches1=Matcher.match(Descriptors1,Descriptors2); 然后向后 Matches2=Matcher.match(Descriptors2,Descriptors1); 然后按以下方式查找两个函数中出现的元素: k=1; DoubleMatches=Matches1; for i=1:length(Matches1)

通过将数组中的一个元素与第二个数组中的一个或多个元素进行匹配,我创建了满射函数

为了只获得所述函数的双射元素,我向前运行相同的函数

Matches1=Matcher.match(Descriptors1,Descriptors2);
然后向后

Matches2=Matcher.match(Descriptors2,Descriptors1);
然后按以下方式查找两个函数中出现的元素:

k=1;
DoubleMatches=Matches1;

for i=1:length(Matches1)
    for j=1:length(Matches2)
        if((Matches1(i).queryIdx==Matches2(j).trainIdx)&&(Matches1(i).trainIdx==Matches2(j).queryIdx))
            DoubleMatches(k)=Matches1(i);
            k=k+1;
       end
   end
end

DoubleMatches(k:end)=[];
这当然会起作用,但它相当不公平,而且似乎会干扰JIT加速器(计算时间时
accel on
accel off
是一样的)

你能想出一个方法来矢量化这个表达式吗?有没有其他方法可以避免JIT“罢工”


非常感谢并对奇怪的结构表示抱歉,我正在使用MEX函数。让我知道在“普通”数组中重写代码是否有助于

在MATLAB中访问多维结构中的数据是出了名的慢,因此将数据转换为普通数组肯定会有帮助:

kk = 1;
DoubleMatches = Matches1;

%// transform to regular array
Matches1queryIdx = [Matches1.queryIdx];
Matches1trainIdx = [Matches1.trainIdx];

Matches2queryIdx = [Matches2.queryIdx];
Matches2trainIdx = [Matches2.trainIdx];

%// loop through transformed data instead of structures
for ii = 1:length(Matches1queryIdx)
    for jj = 1:length(Matches1queryIdx)
        if((Matches1queryIdx(ii)==Matches2trainIdx(jj)) && ...
                (Matches1trainIdx(ii)==Matches2queryIdx(jj)))
            DoubleMatches(kk) = Matches1(ii);
            kk = kk+1;
        end
    end
end

DoubleMatches(kk:end)=[];
还有一个几乎完全矢量化的解决方案:

matches = sum(...
    bsxfun(@eq, [Matches1.queryIdx], [Matches2.trainIdx].') & ...
    bsxfun(@eq, [Matches1.trainIdx], [Matches2.queryIdx].'));

contents = arrayfun(@(x)..
    repmat(Matches1(x),1,matches(x)), 1:numel(matches), ...
    'Uniformoutput', false);

DoubleMatches2 = [contents{:}]';
请注意,这可能会占用更多内存(它有O(N²)的峰值内存占用,而其他的则是O(N),尽管峰值内存的数据类型是
逻辑
,因此比
小8倍)。最好事先检查一下你应该用哪一种

一个小测试。我使用了以下虚拟数据:

Matches1 = struct(...
    'queryIdx', num2cell(randi(25,1000,1)),...
    'trainIdx', num2cell(randi(25,1000,1))...
);

Matches2 = struct(...
    'queryIdx', num2cell(randi(25,1000,1)),...
    'trainIdx', num2cell(randi(25,1000,1))...
);
以及以下测试:

%// Your original method
tic    
    kk = 1;
    DoubleMatches = Matches1;

    for ii = 1:length(Matches1)
        for jj = 1:length(Matches2)
            if((Matches1(ii).queryIdx==Matches2(jj).trainIdx) && ...
                    (Matches1(ii).trainIdx==Matches2(jj).queryIdx))
                DoubleMatches(kk) = Matches1(ii);
                kk = kk+1;
            end
        end
    end

    DoubleMatches(kk:end)=[];

toc

DoubleMatches1 = DoubleMatches;


%// Method with data transformed into regular array
tic

    kk = 1;
    DoubleMatches = Matches1;

    Matches1queryIdx = [Matches1.queryIdx];
    Matches1trainIdx = [Matches1.trainIdx];

    Matches2queryIdx = [Matches2.queryIdx];
    Matches2trainIdx = [Matches2.trainIdx];

    for ii = 1:length(Matches1queryIdx)
        for jj = 1:length(Matches1queryIdx)
            if((Matches1queryIdx(ii)==Matches2trainIdx(jj)) && ...
                    (Matches1trainIdx(ii)==Matches2queryIdx(jj)))
                DoubleMatches(kk) = Matches1(ii);
                kk = kk+1;
            end
        end
    end

    DoubleMatches(kk:end)=[];

toc

DoubleMatches2 = DoubleMatches;


% // Vectorized method
tic

    matches = sum(...
        bsxfun(@eq, [Matches1.queryIdx], [Matches2.trainIdx].') & ...
        bsxfun(@eq, [Matches1.trainIdx], [Matches2.queryIdx].'));

    contents = arrayfun(@(x)repmat(Matches1(x),1,matches(x)), 1:numel(matches), 'Uniformoutput', false);

    DoubleMatches3 = [contents{:}]';

toc

%// Check if all are equal
isequal(DoubleMatches1,DoubleMatches2, DoubleMatches3)
结果:

Elapsed time is 6.350679 seconds. %// (  1×) original method
Elapsed time is 0.636479 seconds. %// (~10×) method with regular array
Elapsed time is 0.165935 seconds. %// (~40×) vectorized
ans =
     1                            %// indeed, outcomes are equal

假设Matcher.match返回作为参数传递给它的相同对象的数组,您可以这样解决这个问题

% m1 are all d1s which have relation to d2
m1 = Matcher.match(d1,d2);
% m2 are all d2s, which have relation to m1
% and all m1 already have backward relation
m2 = Matcher.match(d2,m1);

什么是
匹配1
?您定义的类的对象?我不明白语法
如何匹配1(I).queryIdx
是正确的。。。(但我从未在Matlab中使用过类,所以这可能是个问题)这实际上是一个非常好的问题;如果你同意的话,我将把这个问题作为一个示范性的问题,供其他人参考。@reverse_engineer:Hi,MatchesX是结构,这是包含各种元素的结构(因此匹配(I))和每个元素不同字段中的各种值(其中一个是.queryIdx)。@RodyOldenhuis Hi Rody,谢谢你的夸奖。请随时使用它作为一个例子,当你需要它!顺便说一句:谢谢你的回答!hi@divanov,这确实是解决问题的一种非常合乎逻辑的方法,但不幸的是,这个函数采用的参数不同,我无法从输出中构造输入。无论如何谢谢你!多么惊人的回答!我不相信访问结构会那么慢!很高兴学到新东西。矢量化看起来也很快,我找了很长时间,但就是找不到。谢谢!