Kirill
Kirill

Reputation: 133

MATLAB: search for elements in an array matching multidimensional condition

I have a column vector (V1) of real numbers like:

123.2100
125.1290
...
954.2190

If I add, let's say, a number 1 to each row in this vector, I will get (V2):

124.2100
126.1290
...
955.2190

I need to find out how many elements from V2 are inside some error-window created from V1. For example the error-window = 0.1 (but in my case every element in V1 has it's own error window):

123.1100 123.3100
125.0290 125.2290
...
954.1190 954.3190

I can create some code like this:

% x - my vector
% ppm - a variable responsible for error-window
window = [(1-(ppm/1000000))*x, (1+(ppm/1000000))*x]; % - error-window
mdiff = 1:0.001:20; % the numbers I will iteratively add to x 
                    % (like the number 1 in the example)
cdiff = zeros(length(mdiff),1); % a vector that will contain counts of elements
                                % corresponding to different mdiff temp = 0;

for i = 1:length(mdiff)
    for j = 1:size(window,1)
        xx = x + mdiff(i);
        indxx = find( xx => window(j,1) & xx <= window(j,2) );
        if any(indxx)
            temp = temp + length(indxx); %edited
        end
    end
    cdiff(i) = temp;
    temp = 0;
end

So, at the end cdiff will contain all the counts corresponding to mdiff. The only thing, I would like to make the code faster. Or is there a way to avoid using the second loop (with j)? I mean to directly use a multidimensional condition.

EDIT

I decided to simpify the code like this (thanking to the feedback I got here):

% x - my vector
% ppm - a variable responsible for error-window
window = [(1-(ppm/1000000))*x, (1+(ppm/1000000))*x]; % - error-window
mdiff = 1:0.001:20; % the numbers I will iteratively add to x 
                    % (like the number 1 in the example)
cdiff = zeros(length(mdiff),1); % a vector that will contain counts of elements
                                % corresponding to different mdiff temp = 0;

for i = 1:length(mdiff)
    xx = x + mdiff(i);
    cdiff(i) = sum(sum(bsxfun(@and,bsxfun(@ge,xx,window(:,1)'),bsxfun(@le,xx,window(:,2)'))));
end

In this case the code works faster and seems properly

Upvotes: 2

Views: 128

Answers (2)

Divakar
Divakar

Reputation: 221534

Think this might work for you -

%%// Input data
V1 = 52+rand(4,1)

V2 = V1+1;
t= 0.1;

low_bd = any(abs(bsxfun(@minus,V2,[V1-t]'))<t,2); %%//'
up_bd = any(abs(bsxfun(@minus,V2,[V1+t]'))<t,2); %%//'
count = nnz( low_bd | up_bd )

One could also write it as -

diff_map = abs(bsxfun(@minus,[V1-t V1+t],permute(V2,[3 2 1])));
count = nnz(any(any(diff_map<t,2),1))

Edit 1:

low_bd = any(abs(bsxfun(@minus,V2,window(:,1)'))<t,2); %%//'
up_bd = any(abs(bsxfun(@minus,V2,window(:,2)'))<t,2); %%//'
count = nnz( low_bd | up_bd )

Edit 2: Vectorized form for the edited code

t1 = bsxfun(@plus,x,mdiff);
d1 = bsxfun(@ge,t1,permute(window(:,1),[3 2 1]));
d2 = bsxfun(@le,t1,permute(window(:,2),[3 2 1]));
t2 = d1.*d2;
cdiff_vect = max(sum(t2,3),[],1)';

Upvotes: 0

Luis Mendo
Luis Mendo

Reputation: 112659

add = 1; %// how much to add
error = .1; %// maximum allowed error

V2 = V1 + add; %// build V2   
ind = sum(abs(bsxfun(@minus, V1(:).', V2(:)))<error)>1; %'// index of elements
%// of V1 satisfying the maximum error condition. ">1" is used to because each 
%// element is at least equal to itself
count = nnz(ind);

Upvotes: 0

Related Questions