2
$\begingroup$

I have a $53534\times 3$ matrix with $x$, $y$, and $z$ coordinates. I want to find the element of matrix within ranges as follows:

% coordinate range;
x1(x<-25|x>0);
x2(x<0|x>25);
y1(y<-40|y>0);
y2(y<0|y>40);
z1(z<45|z>0);
z2(z<0|z>82);

and insert them into a new matrix, so that it becomes

point1=[x1, y1, z1];
point2=[x2, y2, z2];

I need to find the distance between the two points.

% define points;
xd=x2-x1;
yd=y2-y1;
zd=z2-z1;
Distance=sqrt(xd*xd+yd*yd+zd*zd);

Is loop preferably efficient?

$\endgroup$
4
  • $\begingroup$ Hi @Jueru: I'm not quite sure what you mean with "Is loop preferrably efficient?"? Do you mean "Is it possible to do this task with a loop? The answer of course is "yes". Or "Are there other ways of doing it, and are they more efficient"? That then depends on the programming language but ultimately, unless you have an index of your data points, it will always have to be a loop over elements of the matrix. $\endgroup$ Commented Apr 15, 2013 at 2:34
  • 4
    $\begingroup$ First rule of MATLAB: avoid for loops. Second rule of MATLAB: avoid for loops. $\endgroup$ Commented Apr 15, 2013 at 2:37
  • $\begingroup$ Hi @Wolfgang. What I mean is I think of using loop, and if there's any better way? Thanks for helping :) $\endgroup$
    – user3991
    Commented Apr 15, 2013 at 3:10
  • $\begingroup$ What I meant is this: whether you write it explicitly, or you do it as user Dr_Sam shows below using code like $R(:,2)$, ultimately it all is a loop. In the latter case, Matlab just offered you a more convenient notation, but it's still a loop. $\endgroup$ Commented Apr 15, 2013 at 12:30

2 Answers 2

3
$\begingroup$

I'm suspecting a typo in at least some of the conditionals. For instance, z<45|z>0 is trivially true. But I'm going to pretend its not and write the code out anyway, so that if you correct it (perhaps z<-45|z>0) you'll still have the right structure.

x  = A(:,1); y = A(:,2); z = A(:,3); 
i1 = find((x<-25|x>0)&(y<-40|y>0)&(z<45|z>0),1,'first'); 
i2 = find((x<0|x>25)&(y<0|y>40)&(z<0|z>82),1,'first'); 
point1 = A(i1,:); 
point2 = A(i2,:); 
Distance = norm(point1-point2);

Like Dr. Sam showed, using tight for loops in MATLAB is truly disastrous for performance. Obviously, as Wolfgang pointed out, MATLAB is using optimized for loops internally to iterate through the elements of the vectors, but that's compiled code. If you were doing this with compiled C, you'd use for loops too, and avoid a lot of the temporary generation that MATLAB is doing here.

$\endgroup$
0
3
$\begingroup$

I made some tests on a slightly different example (you can easily adapt to your need): I generate a 53534x3 random matrix in Matlab (7.9.0)

R = rand(53534,3);

and I try to extract those row indices where all the three coordinates are greater than 0.5. I made a first version with a loop:

I1=[];
for i=1:53534
    if ( R(i,1)>0.5 && R(i,2)>0.5 && R(i,3)>0.5 )
       I1 = [I1; i];
    end
end

and a second version without loop but with the find function

I2 = find( (R(:,1) > 0.5) .* (R(:,2)> 0.5) .* (R(:,3)>0.5) )

(The element-wise product replaces the AND here). Both codes give exactly the same results.

Now the interesting part is the time required for both codes to run:

  • The version with loop takes around 0.05 secondes
  • The version without loop takes around 0.004 secondes

So, there is one order of magnitude between them! So, at least in my example, the loop was not the most efficient implementation.

One could argue that you have more flexibility with the loop. For example, if you know that there will be only one index, you can run the loop only until you find it (not until the end). However, this makes you win (in average) only a factor 2, and the find function has also something similar (check the help).

$\endgroup$
5
  • $\begingroup$ I wasn't kidding in my comment above, even though I expressed myself humorously. If it is possible to do without for loops in MATLAB, you should. Every single time. $\endgroup$ Commented Apr 15, 2013 at 14:46
  • 1
    $\begingroup$ @MichaelGrant That's why I had up-voted your comment! The result in this answer wasn't a surprise for me as well. $\endgroup$
    – Dr_Sam
    Commented Apr 15, 2013 at 14:51
  • $\begingroup$ I've tried both of your solutions and @MichaelGrant's. Yup, the find function is faster, no doubt. It works great too! Thanks to both of you. $\endgroup$
    – user3991
    Commented Apr 16, 2013 at 1:22
  • $\begingroup$ @Jueru, may I recommend you vote up Dr Sam's answer as well. He deserves it! ;-) $\endgroup$ Commented Apr 16, 2013 at 2:04
  • $\begingroup$ I was going to make both as accepted answers, indeed. Apparently scicomp only allow me to chose one, since i'm a newbie. But both of you totally deserves it :) $\endgroup$
    – user3991
    Commented Apr 16, 2013 at 2:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.