1

So, I'm trying to optimize a program I made, and two glaring inefficiencies I have found with the help of the profiler are these:

    if (min(image_arr(j,i,:)) > 0.1)
      image_arr(j,i,:) = image_arr(j,i,:) - min(image_arr(j,i,:));
    end
    %"Grounds" the data, making sure the points start close to 0

Called 4990464 times, takes 58.126s total, 21.8% of total compile time.

    [max_mag , max_index] = max(image_arr(j, i, :));
    %finds the maximum value and its index in the set

Called 4990464 times, takes 50.900s total, 19.1% of total compile time.

Is there any alternative to max and min that I can use here, that would be more efficient?
There is no way to reduce the number of times these lines are called.

NGXII
  • 407
  • 2
  • 9
  • 18

4 Answers4

2

Based on the call count, these are probably inside a loop. Both min and max are vectorized (they work on vectors of vectors).

Since you want to find extrema along the third dimension, you can use:

image_arr = bsxfun(@minus, image_arr, min(image_arr, [], 3));

and

[max_mag , max_index] = max(image_arr, [], 3);
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • This is exactly what I needed! However, I get an error when using the first one (haven't implemented the second one yet). image_arr is an [X,Y,N] matrix while min(image_arr,[],3) returns an [X,Y] matrix, so the subtraction results in an error: Error using - Matrix dimensions must agree. How can we change the syntax to fix this? – NGXII Sep 18 '14 at 01:02
  • @user3817992: try `bsxfun(@minus, image_arr, min(image_arr, [], 3))` – Ben Voigt Sep 18 '14 at 01:09
  • Works perfectly! I'll implement your suggestion for maximum in a few, and may or may not run into an issue, but this is definitely the best answer. – NGXII Sep 18 '14 at 02:02
  • 1
    @user3817992: I'd love to hear how much performance improvement you got from the vectorized version. – Ben Voigt Sep 18 '14 at 03:33
1

It seems like:

   if (min(image_arr(j,i,:)) > 0.1)
      image_arr(j,i,:) = image_arr(j,i,:) - min(image_arr(j,i,:));
    end

could be rewritten like this:

data = image_arr(j,i,:);
mn = min(data);
if (mn > 0.1)
  image_arr(j,i,:) = data - mn;
end

which seems like the inner loop of something that could be written like:

minarr = min(image_arr)
[a,b] = find(minarr > 0.1);
image_arr(a,b,:) = image_arr(a,b,:) - minarr(a,b)
carlosdc
  • 12,022
  • 4
  • 45
  • 62
  • 1
    `find` is probably worse than logical addressing here. But just performing the subtraction unconditionally is probably best of all. – Ben Voigt Sep 13 '14 at 05:23
0

Rename your i and j.

Those names have meaning to MATLAB, and every time it sees them it has to check whether you have your own definition or they mean sqrt(-1).

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • @BenVoigt That is past ;) – Robert Seifert Sep 13 '14 at 06:40
  • 1
    @thewaywewalk: Perhaps the performance penalty is reduced, but the behavior of predefined `i` and `j` is definitely not *past*. – Ben Voigt Sep 13 '14 at 11:24
  • @BenVoigt I meant it performance-wise. You're right, in a clean workspace these variables still return the imaginary unit. (the downvote is btw. not by me.) – Robert Seifert Sep 13 '14 at 11:50
  • The performance penalty is, in any even slightly modern version of MATLAB, not just reduced but very tiny indeed. It's not true that every time MATLAB sees them it needs to determine whether you have your own definition: the JIT can look through the entire function before it's run, to see whether `i` or `j` are defined by the code, or refer to imaginary units. – Sam Roberts Sep 13 '14 at 18:19
  • @Sam: All of that seems adequately covered at http://stackoverflow.com/q/14790740/103167 – Ben Voigt Sep 13 '14 at 22:55
0

The first part can be done without loops using bsxfun.

m = min(image_arr,[],3);
image_arr = bsxfun(@minus, image_arr, m.*(m>0.1));
Luis Mendo
  • 110,752
  • 13
  • 76
  • 147