0

I was wondering if anyone could help me vectorize this piece of code.

fr_bw is a matrix.

 for i=1:height
   for j=1:width      
                [min_w, min_w_index] = min(w(i,j,:));  
                mean(i,j,min_w_index) = double(fr_bw(i,j));
                sd(i,j,min_w_index) = sd_init;
     end
end
user729206
  • 11
  • 1

2 Answers2

1

I can't help you with this sif (match == 0) stuff -- if it's supposed to be if (match == 0) you're not changing match so it could be brought outside the loop.

Otherwise, how about this:

[min_w, min_w_index] = min(w, [], 3);
r = repmat((1:height)',1,width);
c = repmat(1:width,height,1);
ind = sub2ind(size(w),r(:),c(:),min_w_index(:));
w_mean(ind) = double(fr_bw);
w_sd(ind) = repmat(sd_init,height,width);

(Please note that mean is a built-in function so I renamed your variables to w_mean and w_sd.)

The sub2ind call gives you linear indices that correspond to subscripts. (Direct subscripts won't work; z([a1 a2 a3],[b1 b2 b3],[c1 c2 c3]) refers to 27 elements in the z array with subscripts that are the cartesian product of the specified subscripts, rather than z(a1,b1,c1) and z(a2,b2,c2) and z(a3,b3,c3) that you might expect.)

Here's an illustration of this technique:

>> height = 6; width = 4;
>> w = randi(1000,height,width,2)

w(:,:,1) =

   426   599    69   719
   313   471   320   969
   162   696   531   532
   179   700   655   326
   423   639   408   106
    95    34   820   611


w(:,:,2) =

   779   441   638   696
   424   528   958    68
    91   458   241   255
   267   876   677   225
   154   519   290   668
   282   944   672   845

>> [min_w, min_w_index] = min(w, [], 3);
>> min_w_index

min_w_index =

     1     2     1     2
     1     1     1     2
     2     2     2     2
     1     1     1     2
     2     2     2     1
     1     1     2     1

>> z = zeros(height,width,2);
>> r = repmat((1:height)',1,width);
>> c = repmat(1:width,height,1);
>> ind = sub2ind(size(w),r(:),c(:),min_w_index(:));
>> z(ind) = 1

z(:,:,1) =

     1     0     1     0
     1     1     1     0
     0     0     0     0
     1     1     1     0
     0     0     0     1
     1     1     0     1


z(:,:,2) =

     0     1     0     1
     0     0     0     1
     1     1     1     1
     0     0     0     1
     1     1     1     0
     0     0     1     0
Jason S
  • 184,598
  • 164
  • 608
  • 970
  • I have removed the if statement. – user729206 May 04 '11 at 16:04
  • @Richie Thank you for your answer this does not seem to work as well as the for loop, I am unsure why, but the code seems to produce better performance but does not produce the correct results, could you see any reason why? – user729206 May 05 '11 at 00:03
  • without more context / information about what you're expecting, we can't diagnose the problems you are having. – Jason S May 05 '11 at 12:37
  • There seems to be values left in the w_mean that should not be there after a few runs of the code. So what I mean is this piece of code is ran multiple times and does not seem to update correctly this dosent seem to happen using the for loop, does that help it is hard to explain? – user729206 May 05 '11 at 12:43
  • Unless you have example data that I can use, I can't reproduce it on my end. – Jason S May 05 '11 at 14:21
0

A few comments on your code:

  1. Did you mean if rather than sif?

  2. The code isn't replicable at the moment, since you haven't provided examples of the variables w, fr_bw and sd_init. This makes it tricky to give an exact answer.

  3. It looks like you are assigning things to a variable named mean. This will shadow the mean function, and probably cause you grief.

  4. I'm just guessing, but I don't think double does what you think it does. You don't need to convert individual elements of a numeric matrix to type double; they are already the correct type. (On the other hand, if fr_bw is a different type, say integers, then you should create a new variable dbl_fr_bw = double(fr_bw); before the loops.

You might need to adjust the dimension over which you calculate the minimums, but the first line of the loop can be replaced with

[min_w, min_w_index] = min(w, [], 3)

The second line with

mean_values(:, :, min_w_index) = double(fr_bw)

Not sure about the third line, since I don't know what sd_init is/does.

Richie Cotton
  • 118,240
  • 47
  • 247
  • 360
  • Your second line suggestion will **not** work. Try it. You'll get an error. – Jason S May 04 '11 at 13:39
  • namely, subscript indices are independent and do not work with a matrix of values. Unless all the min_w_index values are the same, it refers to indices that are all the rows and columns and the union of all the min_w_index values. This is a 3-dimensional slice of mean_values and MATLAB expects the right-hand-side to be a 3-D matrix of the right size. – Jason S May 04 '11 at 13:42
  • @Jason S: Good catch; offending line removed. Will defer to your answer. – Richie Cotton May 04 '11 at 14:42
  • I could have sworn there was a way to do what you suggest (it was my first approach too, until it didn't work), but aside from logical addressing, I'm not aware of anything. – Jason S May 04 '11 at 15:17
  • @Jason, @Richie Thank you for your answer this does not seem to work as well as the for loop, I am unsure why, but the code seems to produce better performance but does not produce the correct results, could you see any reason why? – user729206 May 04 '11 at 15:56