Matlab code vectorization

I am new to vectorization. I tried myself, but could not. Can someone help me vectorize this code, as well as give a brief explanation of how to do this so that I can adapt my thinking. Thank you

function [result] = newHitTest (point,Polygon,r,tol,stepSize) %This function calculates whether a point is allowed. %First is a quick test is done by calculating the distance from point to %each point of the polygon. If that distance is smaller than range "r", %the point is not allowed. This will slow down the algorithm at some %points, but will greatly speed it up in others because less calls to the %circleTest routine are needed. polySize=size(Polygon,1); testCounter=0; for i=1:polySize d = sqrt(sum((Polygon(i,:)-point).^2)); if d < tol*r testCounter=1; break end end if testCounter == 0 circleTestResult = circleTest (point,Polygon,r,tol,stepSize); testCounter = circleTestResult; end result = testCounter; 
+4
source share
1 answer

Given that Polygon is 2-dimensional, point is a row vector, and the rest of the variables are scalars, here is the first version of your new function (scroll down to see that there are many ways to skin this cat):

 function [result] = newHitTest (point,Polygon,r,tol,stepSize) result = 0; linDiff = Polygon-repmat(point,size(Polygon,1),1); testLogicals = sqrt( sum( ( linDiff ).^2 ,2 )) < tol*r; if any(testLogicals); result = circleTest (point,Polygon,r,tol,stepSize); end 

The thought process for vectoring in Matlab involves trying to use as much data as possible using one command. Most of the core Matlab built-in functions work very well with multidimensional data. Using a for loop is the opposite, as you break your data into smaller segments for processing, each of which must be interpreted individually. By decomposing data using for loops, you might lose some of the enormous performance benefits associated with highly optimized code behind Matlab's built-in functions.

The first thing you need to think about in your example is the conditional break in your main loop. You cannot refuse a vectorized process. Instead, calculate all the possibilities, make an array of results for each row of your data, then use the any keyword to find out if any of your rows indicated that the circleTest function should be called.

NOTE. It’s not easy to effectively conditionally break out of the calculation in Matlab. However, since you are simply calculating the shape of the Euclidean distance in the loop, you are likely to see a performance increase using the vectorized version and calculating all the features. If the calculation in your loop was more expensive, the input was big, and you wanted to break out as soon as you came across a certain condition, then the matlab extension made using a compiled language could potentially be much faster than the vector version, where you can Perform unnecessary calculations. However, it is assumed that you know how to program code that matches the performance of the embedded Matlab embedded in a language that compiles into native code.

Back to the topic ...

The first thing to do is take the linear difference ( linDiff in the sample code) between Polygon and your point line vector. To do this in vector form, the sizes of the two variables must be the same. One way to achieve this is to use repmat to copy each point line to make it equal to the size of the Polygon . However, bsxfun usually an excellent alternative to repmat ( as described in this recent SO question ), making code ...

 function [result] = newHitTest (point,Polygon,r,tol,stepSize) result = 0; linDiff = bsxfun(@minus, Polygon, point); testLogicals = sqrt( sum( ( linDiff ).^2 ,2 )) < tol*r; if any(testLogicals); result = circleTest (point,Polygon,r,tol,stepSize); end 

I flipped your d value into d column by summing along the 2nd axis (note the removal of the array index from Polygon and the addition of ,2 to the sum command). Then I went ahead and evaluated the testLogicals inline boolean array with distance measure calculation. You'll quickly realize that the disadvantage of heavy vectorization is that it can make the code less clear for those who are not familiar with Matlab, but its performance is worth it. Comments are very necessary.

Now, if you want to go crazy, you can argue that the test function is so simple now that it requires the use of an “anonymous function” or “lambda” rather than a full definition of the function. The test for whether to do circleTest also does not require the stepSize argument, which is another reason, perhaps, for using an anonymous function. You can overturn your anonymous function test and then use circleTest in your script call, which will document the code to some extent.,

 doCircleTest = @(point,Polygon,r,tol) any(sqrt( sum( bsxfun(@minus, Polygon, point).^2, 2 )) < tol*r); if doCircleTest(point,Polygon,r,tol) result = circleTest (point,Polygon,r,tol,stepSize); else result = 0; end 

Now everything is vectorized, using functional descriptors gives me another idea.,

If you plan on doing this at multiple points in the code, repeating if will be a little ugly. To stay dry , it seems reasonable to put a test with a conditional function in one function, as in the original post. However, the usefulness of this function will be very narrow - it will only check if the circleTest function should be executed, and then execute it if necessary.

Now imagine that after a while you have other conditional functions, like circleTest , with their own doCircleTest equivalent. It would be nice to reuse the conditional switch code. To do this, create a function similar to your original that accepts the default value, the logical result of a computationally cheap test function, and the function descriptor of an expensive conditional function with its associated arguments ...

 function result = conditionalFun( default, cheapFunResult, expensiveFun, varargin ) if cheapFunResult result = expensiveFun(varargin{:}); else result = default; end end %//of function 

You can call this function from the main script with the following.,

 result = conditionalFun(0, doCircleTest(point,Polygon,r,tol), @circleTest, point,Polygon,r,tol,stepSize); 

... and its beauty - you can use any test, the default value and an expensive feature. This may be too simple an example, but it was there that my mind wandered when I brought up the idea of ​​using function handles.

+7
source

Source: https://habr.com/ru/post/1440482/


All Articles