1
\$\begingroup\$

I would like to optimize a snippet of code, which uses a multiple nested if statements. I am looking for a formula to make it as a combination of multiple arrays logical operations. Please, I need just a hint to start. Can you please help me review the loop and vectorize it?

The I is an input image (any):

I = 5*rand(4,4);
A = rand(4,4);
B = [ 1 0 1 0; 0 0 1 1 ; 0 1 1 0; 0 0 1 1];

result = zeros(4,4);
 for i = 1:4
     for j = 1:4
         if A(i,j) > 0.75
             result(i,j) = 1;
         elseif A(i,j) < 0.25
             result(i,j) = 0;
         else
             if B(i,j) == 1
                 result(i,j) = 1;
             elseif B(i,j) == 0
                 result(i,j) = 0;
             end
         end
     end
 end

 figure, 
 subplot(2,1,1), imagesc(A),title('I');
 subplot(2,1,2), imagesc(result),title('result');
\$\endgroup\$
  • \$\begingroup\$ Your original title was inappropriate, since it didn't describe the task performed by the code, as per the How to Ask guidelines. I've removed "random" from the title and the tags, but please note that whatever code you have posted is fair game for review. \$\endgroup\$ – 200_success Jun 20 '16 at 23:15
  • \$\begingroup\$ Is I relevant to the question? \$\endgroup\$ – 200_success Jun 20 '16 at 23:19
  • \$\begingroup\$ The code is simplified version of a more complex code, the title is not convenient, sorry \$\endgroup\$ – user21479 Jun 23 '16 at 17:02
  • \$\begingroup\$ Simplified excerpts are fine, but please keep in mind that we are reviewing the code that you actually posted, not guessing how to help you improve code that you chose not to post. \$\endgroup\$ – 200_success Jun 23 '16 at 18:11
2
\$\begingroup\$

You shouldn't use i and j as variables in MATLAB, as they are used to denote the imaginary unit (sqrt(-1)). In fact, the official MATLAB documentation warns you about it. It's better to use 1i or 1j for the imaginary unit. The documentation says the performance is better, but that's not really true. The main problem however is that using those variable names can result in some stange behavior. As i is not undefined, you don't get the usual Undefined function or variable 'x'.

For instance, assume you intended to write i = true, but forgot it. Now, try out:

if i == true
   disp('What happens here?')
end

This should normally result in "What happens here?" being displayed on the screen, but since i = sqrt(-1), which is neither true nor false, you get nothing. You won't get anything for this either:

if i == false
   disp('What happens here?')
end

Similarly, this will result in an infinite loop:

while i < 10
    i = i * 2;
end

So, change i and j to ii and jj (this is common for users on SO at least), or some other variable names.

Now, what about the loops and ifs?

You are right, this should definitely be vectorized. Althoug the performance of loops have been drastically improved after the new exectuion engine was included, vectorization is still fastest in most cases.

First off, you should know that boolean values can be treated as numeric values. They can be subtracted, added, etc. Furthermore, any non-zero real number is considered to be true, while a zero is considered to be false. Also, if a == true is the same as just if a, and if a == false is the same as just if ~a (~ means not in this case), or if a ~= 0.

If you had only the first part about where result is defined only be the values of A, then this could be done quite simply:

results = (A > 0.75)  % or `results = (A > 0.75)

The part with A < 0.25 is irrelevant there, since those elements are already zero.

x | y means x == true and/or y == true. So, it's enough that one of the conditions are true. If you do x & y, then both x and y must be true.

Since you include the part with B, you must add a term, the above line is not enough. First note that the part with B is only relevant if the two conditions

A < 0.75

and

A > 0.25

are both false. We can disregard the A < 0.75 part, since those elements are already set to 1.

In plain text: The elements in result shall be 1 if either A > 0.75 or A > 0.25 and B == 1. Since the last part has an and in there, we must use &.

So, the loops and ifs can simply be rewritten as:

result = ((A > 0.75) | (A > 0.25 & B))

It's a matter of preference, but you might want to do ... & B == true alternatively ... & B == 1 for clarity. It's common to ignore the true part, but it is a bit clearer to include it.

Example:

A =

   0.568800   0.162200   0.165600   0.689200
   0.469400   0.794300   0.602000   0.748200
   0.011900   0.311200   0.263000   0.450500
   0.337100   0.528500   0.654100   0.083800

B =
   1   0   1   0
   0   0   1   1
   0   1   1   0
   0   0   1   1

res =
   1   0   0   0
   0   1   1   1
   0   1   1   0
   0   0   1   0
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy