From: Jussi Forma on
Hi,

I have 4d-data, namely certain measurement vector V(t) for each point in x,y,z grid. From this set, I need to find one point x1,y1,z1 which is closest to my given reference vector, similarity metric is sum of squared errors between reference and data vector. Data vectors may be shifted also in t-dimension, all vectors are periodic.

So in essence I have one vector, and bunch of candidates to compare it with different lags. Here's my first version, let me know how to optimize this for speed.

%%%%%%%%%%%%%%%%%%%%%
refvec = reshape(rand(100,1),[1 1 1 100]); %reference vector
refblock = repmat(refvec,[5 5 5 1]); %replicate it to correspond the whole spatial %grid

floatblock = rand([5 5 5 100]); %example data set

maxshift = 10; % maximum shift of vectors in t-domain. (not in xyz)
%calculate MSE for each vector pair, and shift.
MSEs = zeros(size(refblock,1),size(refblock,2),size(refblock,3),2*maxshift+1);

% for each shift, get squared errors for the whole spatial grid.
for n = -maxshift : maxshift
MSEs(:,:,:,n+maxshift+1) = sum(( refblock - circshift(floatblock,[0 0 0 n]) ).^2,4);
end
From: Bruno Luong on
"Jussi Forma" <juss911(a)luukku.com> wrote in message <hov5sc$5pg$1(a)fred.mathworks.com>...

> ... sum(( refblock - circshift(floatblock,[0 0 0 n]) ).^2,4);

You can rewrite this as

sum(( refblock - circshift(floatblock,[0 0 0 n]) ).^2,4)
+ sum((refblock).^2,4) + sum((floatblock).^2,4)
- 2* sum(refblock.*circshift(floatblock,[0 0 0 n])),4)

The two first terms do not depend on n and can be computed once. The third term can be rewritten as circular convolution, which can be computed using fft on the fourth dimension (not sure if it's faster because you only need few elements of the convolution result, I let you play with it).

Bruno
From: Jussi Forma on
"Bruno Luong" <b.luong(a)fogale.findmycountry> wrote in message <hov8gp$cc8$1(a)fred.mathworks.com>...
> "Jussi Forma" <juss911(a)luukku.com> wrote in message <hov5sc$5pg$1(a)fred.mathworks.com>...
>
> > ... sum(( refblock - circshift(floatblock,[0 0 0 n]) ).^2,4);
>
> You can rewrite this as
>
> sum(( refblock - circshift(floatblock,[0 0 0 n]) ).^2,4)
> + sum((refblock).^2,4) + sum((floatblock).^2,4)
> - 2* sum(refblock.*circshift(floatblock,[0 0 0 n])),4)
>
> The two first terms do not depend on n and can be computed once. The third term can be rewritten as circular convolution, which can be computed using fft on the fourth dimension (not sure if it's faster because you only need few elements of the convolution result, I let you play with it).
>
> Bruno

Thanks a lot Bruno

Taking those terms out from the loop helped, and calculating the last term with fft's and picking the right elements, roughly doubled the speed from my first attempt.

Here's how I calculated the last term:

term = -2*ifft(fft(refblock,[],4).*fft(flipdim(floatblock,4),[],4),[],4);
term = flipdim(term(:,:,:,end-(2*maxshift+1)+1:end) ,4)
From: Bruno Luong on
"Jussi Forma" <juss911(a)luukku.com> wrote in message <hp1mei$5ar$1(a)fred.mathworks.com>...

>
> term = -2*ifft(fft(refblock,[],4).*fft(flipdim(floatblock,4),[],4),[],4);

Because refblock is repmat of refvec, it should be faster to compute quantity fft(refblock,[],4) by:

fftref = fft(refvec);
fftref = reshape(fftref ,[1 1 1 100]); % if needed
fftref= repmat(fftref ,[5 5 5 1]);

% Bruno