if statement with 'or' operator gives different results when conditions are swapped - matlab

I'm using strfind with an 'or' comparison like so:
name='hello';
if strfind(name,'hello') | strfind(name,'hi')
disp('yes!')
end
>> yes!
The if statement must evaluate as true, since yes! is displayed.
In contrast, MATLAB doesn't return yes! if the statements are swapped:
if strfind(name,'hi') | strfind(name,'hello')
disp('yes!')
end
Why?

This is because short-circuiting. Short-circuited logical operators are a thing to speed up code. You can have
if veryShort | superlongComputation
so what MATLAB does is first evaluate veryShort and if it is true, then no need to evaluate the second one! The if condition is already met.
In your case strfind(name,'hello') returns 1, but strfind(name,'hi') returns [].
In the first example, as the first thing evaluated returns 1, you get to the display. However in the second case, it returns [], therefore MATLAB evaluates the second thing in the if, and returns 1. Then MATLAB applies the or operations where [] | 1 is an 0x0 empty logical array, so the if is not true.
Note, generally you want to use || to enforce short-circuiting, but | also does it, if it is inside a while or an if:
https://uk.mathworks.com/matlabcentral/answers/99518-is-the-logical-operator-in-matlab-a-short-circuit-operator

Both of the following conditions are empty []:
name='hello';
strfind(name,'hello') | strfind(name,'hi'); % = []
strfind(name,'hi') | strfind(name,'hello'); % = []
As referenced in Ander's answer, the | operator is using short circuiting to skip evaluation of the second condition if the first is false (or empty).
Some quick debugging will give you better understanding if we ignore short-circuiting:
strfind(name,'hi'); % = []
strfind(name,'hello'); % = 1
In both cases you are doing "if empty or non-zero", which is empty and "if []" is false (that conditional statement won't be executed).
What you want to use to be explicit is something like this:
if ~isempty(strfind(name, 'hello')) & ~isempty(strfind(name, 'hi'))
disp('yes!')
end
Here, we guarantee that everything being evaluated in the if statement is a Boolean variable, not empty or an index like strfind returns, so unexpected results are less likely.
There are simpler methods, like using strcmp or ismember if your strings should match exactly. Or contains if you have R2016b or newer:
if contains('hello', {'hello','hi'})
disp('yes!');
end

Related

|| operators must be convertible to logical scalar values in case of an empty matrix

Consider the following code
t = ones(3,5)
Ind2save = find(t(1,:) == 0,1,'first')
So for example I am trying to find if even the first zero of the first row, so if the first element is a non zero then
if(Ind2save ~= 1 )
disp('no')
end
now for the above condition it doesn't display 'no' because the condition is not fulfilled but because all the rows are filled and Ind2save is an empty matrix so we another condition to check if it is fully filled then
if(Ind2save > 1 || isempty(Ind2save))
disp('no')
end
I get the following error
Operands to the || and && operators must be convertible to logical scalar values.
I searched for the reasons due to which this error is caused and in majority of the cases people were comparing two vectors so a better idea was to replace || with | but in my case the conditions are never vectors but Ind2save > 1 returns an empty matrix , does anyone know why is the reason for that? How can I accommodate both the conditions?
The issue is because in your case Ind2save is empty ([]) therefore the first part of your condition can't be used with || since [] > 1 doesn't yield a logical scalar (it results in []).
In order to fix this, you can to flip the order of your conditions such that you check if the array is empty first.
if isempty(Ind2save) || Ind2save > 1
The reason that this works is that if Ind2Save is empty, then the first condition evaluates to true therefore short-circuiting the rest of the checks.
You may have other issues if for some reason Ind2save is a vector. In that case you could need to so something to convert it to a logical scalar:
if isempty(Ind2save) || ismember(1, Ind2save)

Turn off Warning: Extension: Conversion from LOGICAL(4) to INTEGER(4) at (1) for gfortran?

I am intentionally casting an array of boolean values to integers but I get this warning:
Warning: Extension: Conversion from LOGICAL(4) to INTEGER(4) at (1)
which I don't want. Can I either
(1) Turn off that warning in the Makefile?
or (more favorably)
(2) Explicitly make this cast in the code so that the compiler doesn't need to worry?
The code will looking something like this:
A = (B.eq.0)
where A and B are both size (n,1) integer arrays. B will be filled with integers ranging from 0 to 3. I need to use this type of command again later with something like A = (B.eq.1) and I need A to be an integer array where it is 1 if and only if B is the requested integer, otherwise it should be 0. These should act as boolean values (1 for .true., 0 for .false.), but I am going to be using them in matrix operations and summations where they will be converted to floating point values (when necessary) for division, so logical values are not optimal in this circumstance.
Specifically, I am looking for the fastest, most vectorized version of this command. It is easy to write a wrapper for testing elements, but I want this to be a vectorized operation for efficiency.
I am currently compiling with gfortran, but would like whatever methods are used to also work in ifort as I will be compiling with intel compilers down the road.
update:
Both merge and where work perfectly for the example in question. I will look into performance metrics on these and select the best for vectorization. I am also interested in how this will work with matrices, not just arrays, but that was not my original question so I will post a new one unless someone wants to expand their answer to how this might be adapted for matrices.
I have not found a compiler option to solve (1).
However, the type conversion is pretty simple. The documentation for gfortran specifies that .true. is mapped to 1, and false to 0.
Note that the conversion is not specified by the standard, and different values could be used by other compilers. Specifically, you should not depend on the exact values.
A simple merge will do the trick for scalars and arrays:
program test
integer :: int_sca, int_vec(3)
logical :: log_sca, log_vec(3)
log_sca = .true.
log_vec = [ .true., .false., .true. ]
int_sca = merge( 1, 0, log_sca )
int_vec = merge( 1, 0, log_vec )
print *, int_sca
print *, int_vec
end program
To address your updated question, this is trivial to do with merge:
A = merge(1, 0, B == 0)
This can be performed on scalars and arrays of arbitrary dimensions. For the latter, this can easily be vectorized be the compiler. You should consult the manual of your compiler for that, though.
The where statement in Casey's answer can be extended in the same way.
Since you convert them to floats later on, why not assign them as floats right away? Assuming that A is real, this could look like:
A = merge(1., 0., B == 0)
Another method to compliment #AlexanderVogt is to use the where construct.
program test
implicit none
integer :: int_vec(5)
logical :: log_vec(5)
log_vec = [ .true., .true., .false., .true., .false. ]
where (log_vec)
int_vec = 1
elsewhere
int_vec = 0
end where
print *, log_vec
print *, int_vec
end program test
This will assign 1 to the elements of int_vec that correspond to true elements of log_vec and 0 to the others.
The where construct will work for any rank array.
For this particular example you could avoid the logical all together:
A=1-(3-B)/3
Of course not so good for readability, but it might be ok performance-wise.
Edit, running performance tests this is 2-3 x faster than the where construct, and of course absolutely standards conforming. In fact you can throw in an absolute value and generalize as:
integer,parameter :: h=huge(1)
A=1-(h-abs(B))/h
and still beat the where loop.

if/else statement not executing 'if' statement

I have been trying to print some complex numbers. If the complex number (modTrace) is like 'a-ib' then my code:
modTrace
v = [real(modTrace(:)) imag(modTrace(:))].';
fprintf(fileID,'%e+%ei\n',v);
gives the output as:
2.355387e-13+-7.217925e-13i
To avoid the extra + sign in front of the negative imaginary piece I write:
v = [real(modTrace(:)) imag(modTrace(:))].';
if imag(modTrace(:))>0
fprintf(fileID,'%e+%ei\n',v);
else
fprintf(fileID,'%e%ei\n',v);
end
Now in the output the 'if' is not being executed. So if I have a complex number 'a+ib' it prints
'a bi' and if a complex number is 'a-ib' it prints 'a-bi' according to the else statement.
if I then modify the code like:
v = [real(modTrace(:)) imag(modTrace(:))].';
if imag(modTrace(:))<0
fprintf(fileID,'%e%ei\n',v);
else
fprintf(fileID,'%e+%ei\n',v);
end
then again the 'if' statement in not being executed. So for a complex number 'a-ib' the output is 'a+-bi' and the 'else' statement in being executed correctly.
Could any body please help me to find the output in the correct form?
Thanks.
I think that in this case you are better off using a loop:
for k = 1:length(modTrace)
if imag(modTrace(k))>0
fprintf(fileID,'%e+%ei\n',real(modTrace(k)), imag(modTrace(k)));
else
fprintf(fileID,'%e%ei\n',real(modTrace(k)), imag(modTrace(k)));
end
end
You can't vectorize it that easily because if you pass a vector to if it only evaluates true when (http://www.mathworks.com/help/matlab/ref/if.html):
the result is nonempty and contains all nonzero elements (logical or
real numeric). Otherwise, the expression is false.

matlab - what is the equivalent of null / None / nil / NULL etc.?

In most OO languages, where variables may point to objects, they may also have a null value, which is highly convenient.
In Matlab, I have a function which parses a command, and then returns a cell array, or false (which is equal to zero — which is another common pattern) if it fails:
function re = parse(s)
...
if (invalid)
re = false;
return;
end
end
The problem is that when I check the result, it gives an error:
re = parse(s);
if (false == re)
Undefined function 'eq' for input arguments of type 'cell'.
I've written a function to check it without an error: strcmp('logical', class(re)) && false == re, but that seems to be really slow for use in hot areas of the code, and also inconvenient if I have to add this function to every M file I'm writing.
Using NaN is even worse, because besides throwing that error, it also isn't equal to itself.
What's a better alternative for use with this pattern?
You can use the isequal function to compare any two items without causing that error. For example:
if isequal (re, false)
%code here
end
A good alternative is to use the empty array: [] and isempty(re) to check. This doesn't throw the error.
Reference: http://www.mathworks.com.au/matlabcentral/newsreader/view_thread/148764
If you can change the function parse one solution would be to return two output arguments [re status] = parse(s), where status would be logical variable. Set it to true in case of success, and to false otherwise.
I would use the empty cell array {} if it is not a valid result otherwise. Using empty matrices is MATLAB standard (see Evgeni Sergeev's answer), but using an empty cell array instead of an empty numeric array ensures that you'll always end up with the same type of result.
If, on the other hand, the empty cell array {} is a valid result of your function, then I'd use an exception to signalize a problem:
if invalid
error('Parse:InvalidArgumentError', 'The input is invalid.');
end
Make sure to use an appropriate error ID (first argument to error) so that you can catch exactly that exception when you call the function:
try:
result = parse(something);
catch ME
if strcmp(ME.identifier, 'Parse:InvalidArgumentError')
fprintf('Ooops\n');
else
% Some other error
ME.rethrow();
end
end
I think the problem is that matlab functions don't return pointers but copies of values.
IMHO the best best approach would be to define your own "pointer" class. Inside you can define an "isNull()" command or even override comparison to produce the behavior you desire.

Unable to add a condition to a while loop in Matlab

I have a while loop which looks like this:
while ((min_t_border>0) && (colided_border_num > 0) && (~(min_t>0)))
...
end
I want to add to it another condition: (exit_border_point ~= false) or (exit_border_point)
when I put ether of the conditions above in an if statement it works. But when I try to add it as an additional condition to the while, or even when I try to add another condition to the if, for example I've tried if ((exit_border_point ~= false) && (true)) it tells me:
"Operands to the || and && operators must be convertible to logical scalar values."
What am I doing wrong?
*exit_border_point gets ether a (3x1) vector or false
Since exit_border_point can be a vector, try using the any or all functions, like this:
if (~any(exit_border_point))
As you can probably guess, any returns true if anything in the array evaluates to true and all returns true if everything in the array is true. They're kind of like vector equivalents to || and &&.
For the condition to make sense in the context of an if or while statement, it should evaluate to a scalar.
Thus, you should write
all(exit_border_point)
(which is equivalent to all(exit_border_point == true)), if you want true if all are true. Replace all with any if you want to exit the while-loop as soon as any exit_border_point is true.
Note that && and || only work for scalars. They're short-cut operators in that the second statement won't be evaluated if the first one determines the outcome (e.g. evaluates to false in case of &&. If you want to element-wise compare arrays, use & and |.
If exit_border_point is a 3x1 vector then (exit_border_point ~= false) also returns a 3x1 vector, hence the error. Use this condition instead:
~isequal(exit_border_point, false)