-
Notifications
You must be signed in to change notification settings - Fork 0
/
nearestpoint.m
161 lines (140 loc) · 4.35 KB
/
nearestpoint.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
function [IND, D] = nearestpoint(x,y,m)
% NEARESTPOINT - find the nearest value in another vector
%
% IND = NEARESTPOINT(X,Y) finds the value in Y which is the closest to
% each value in X, so that abs(Xi-Yk) => abs(Xi-Yj) when k is not equal to j.
% IND contains the indices of each of these points.
% Example:
% NEARESTPOINT([1 4 12],[0 3]) -> [1 2 2]
%
% [IND,D] = ... also returns the absolute distances in D,
% that is D == abs(X - Y(IND))
%
% NEARESTPOINT(X, Y, M) specifies the operation mode M:
% 'nearest' : default, same as above
% 'previous': find the points in Y that are closest, but preceeds a point in X
% NEARESTPOINT([0 4 3 12],[0 3],'previous') -> [NaN 2 1 2]
% 'next' : find the points in Y that are closets, but follow a point in X
% NEARESTPOINT([1 4 3 12],[0 3],'next') -> [2 NaN 2 NaN]
%
% If there is no previous or next point in Y for a point X(i), IND(i)
% will be NaN.
%
% X and Y may be unsorted.
%
% This function is quite fast, and especially suited for large arrays with
% time data. For instance, X and Y may be the times of two separate events,
% like simple and complex spike data of a neurophysiological study.
%
%
% Nearestpoint('test') will run a test to show it's effective ness for
% large data sets
% Created : august 2004
% Author : Jos van der Geest
% Email : [email protected]
% Modifications :
% aug 25, 2004 - corrected to work with unsorted input values
% nov 02, 2005 -
% apr 28, 2006 - fixed problem with previous points
if nargin==1 && strcmp(x,'test'),
testnearestpoint ;
return
end
error(nargchk(2,3,nargin)) ;
if nargin==2,
m = 'nearest' ;
else
if ~ischar(m),
error('Mode argument should be a string (either ''nearest'', ''previous'', or ''next'')') ;
end
end
if ~isa(x,'double') || ~isa(y,'double'),
error('X and Y should be double matrices') ;
end
% sort the input vectors
sz = size(x) ;
[x, xi] = sort(x(:)) ;
[dum, xi] = sort(xi) ; % for rearranging the output back to X
nx = numel(x) ;
cx = zeros(nx,1) ;
qx = isnan(x) ; % for replacing NaNs with NaNs later on
[y,yi] = sort(y(:)) ;
ny = length(y) ;
cy = ones(ny,1) ;
xy = [x ; y] ;
[xy, xyi] = sort(xy) ;
cxy = [cx ; cy] ;
cxy = cxy(xyi) ; % cxy(i) = 0 -> xy(i) belongs to X, = 1 -> xy(i) belongs to Y
ii = cumsum(cxy) ;
ii = ii(cxy==0).' ; % ii should be a row vector
% reduce overhead
clear cxy xy xyi ;
switch lower(m),
case {'nearest','near','absolute'}
% the indices of the nearest point
ii = [ii ; ii+1] ;
ii(ii==0) = 1 ;
ii(ii>ny) = ny ;
yy = y(ii) ;
dy = abs(repmat(x.',2,1) - yy) ;
[dum, ai] = min(dy) ;
IND = ii(sub2ind(size(ii),ai,1:nx)) ;
case {'previous','prev','before'}
% the indices of the previous points
ii(ii < 1) = NaN ;
IND = ii ;
case {'next','after'}
% the indices of the next points
ii = ii + 1 ;
ii(ii>ny) = NaN ;
IND = ii ;
otherwise
error('Unknown method "%s"',m) ;
end
IND(qx) = NaN ; % put NaNs back in
% IND = IND(:) ; % solves a problem for x = 1-by-n and y = 1-by-1
if nargout==2,
% also return distance if requested;
D = repmat(NaN,1,nx) ;
q = ~isnan(IND) ;
D(q) = abs(x(q) - y(IND(q))) ;
D = reshape(D(xi),sz) ;
end
% reshape and sort to match input X
IND = reshape(IND(xi),sz) ;
% because Y was sorted, we have to unsort the indices
q = ~isnan(IND) ;
IND(q) = yi(IND(q)) ;
% END OF FUNCTION
function testnearestpoint
disp('TEST for nearestpoint, please wait ... ') ;
M = 13 ;
tim = repmat(NaN,M,3) ;
tim(8:M,1) = 2.^(8:M).' ;
figure('Name','NearestPointTest','doublebuffer','on') ;
h = plot(tim(:,1),tim(:,2),'bo-',tim(:,1),tim(:,3),'rs-') ;
xlabel('N') ;
ylabel('Time (seconds)') ;
title('Test for Nearestpoint function ... please wait ...') ;
set(gca,'xlim',[0 max(tim(:,1))+10]) ;
for j=8:M,
N = 2.^j ;
A = rand(N,1) ; B = rand(N,1) ;
tic ;
D1 = zeros(N,1) ;
I1 = zeros(N,1) ;
for i=1:N,
[D1(i), I1(i)] = min(abs(A(i)-B)) ;
end
tim(j,2) = toc ;
pause(0.1) ;
tic ;
[I2,D2] = nearestpoint(A,B) ;
tim(j,3) = toc ;
% isequal(I1,I2)
set(h(1),'Ydata',tim(:,2)) ;
set(h(2),'Ydata',tim(:,3)) ;
drawnow ;
end
title('Test for Nearestpoint function') ;
legend('Traditional for-loop','Nearestpoint',2) ;