Logical tests with char vectors

In Matlab this causes an error:

> false || '0xFFFFFFFF'
> Operands to the logical AND (&&) and OR (||) operators must be convertible to logical scalar values. Use the ANY or ALL functions to reduce operands to logical scalar values.

In Octave it does not:

> false || '0xFFFFFFFF'
> ans = 1
> whos ans
>    Attr Name        Size                     Bytes  Class
>    ==== ====        ====                     =====  =====
>         ans         1x1                          1  logical
> 
> Total is 1 element using 1 byte

My system

  • OS: Windows 10
  • Octave version: GNU Octave Version: 6.4.0 (hg id: 8d7671609955)
  • Installation method: Downloaded and installed “octave-6.4.0-w64-installer.exe” from Download

Octave is self-consistent in treating nonzero values as true. In 6.4.0:

>> false || 1
ans = 1
>> false || pi
ans = 1

This might be a feature, not a bug.

@arungiridhar - thanks for the response

I agree that it is “self-consistent”, however it is definitely a Matlab incompatibility. But maybe that horse left the barn a long time ago. :slightly_smiling_face:

It could also be argued that Matlab is “self-consistent” in that they require the arguments to the logical operator || to be logical.

I think it was probably one of the areas where Octave chose to disagree with Matlab consciously. E.g. the following expressions are enabled by implicit conversion to boolean:

a = 0, b = 0, c = 0
a++ && b
++b | c

Etc.

Looking through my codebase with grep, I do use that implicit conversion in some files, especially scripts that were ported from third-party C or C++ code.

We could probably do a better job of documenting this difference though.

In Octave, I guess character arrays are convertible to logical values.

Do you have actual working code that depends on an error being thrown for the kind of expression you showed in the original post?

The difference in Octave behavior is not due to the class of the object (character). Both Octave and Matlab will reduce a scalar character to a logical value.

false || 'a'
=> 1

The issue is what happens when the argument is not a scalar (vector or array). For example, what should this code return?

false || [1, 2, 3]

In Matlab this throws an error because it can’t decide how to convert this vector to a single scalar logical value. The error message helpfully suggests using all or any as possible ways to convert to a scalar.

In Octave, there is no check on the dimensions of the object and apparently the first element of the array is used. For example,

false || [0, 1, 2]

yields false because false || 0 is false.

I tend to agree with the reporter that this is not ideal behavior. Imagine that the comparison is false || x where x is data from some experiment. In that case the script will run differently based on the data which will be very hard to debug.

I also think this is, generally, a small issue that should be worked around by better coding (using all or any) and that it probably isn’t present very often.

Oh, I had completely missed the single quotes in the original post and had been testing it against hexadecimal-format integers and other numeric inputs.

Yes, if those were arrays then a short-circuit boolean does not make sense to convert implicitly. Sorry for my misreading the post.

I don’t think that last part is quite right. I think it applies an implicit all() to the rhs.

octave:2> a = false || true
a = 1
octave:3> a = false || [1,2,3]
a = 1
octave:4> a = false || [1,2,3]'
a = 1
octave:5> a = false || [0,2,3]
a = 0
octave:6> a = false || [1, 0,3]
a = 0
octave:7> a = false || [1, 0,3]'
a = 0

That’s probably right. The conversion to a logical variable is probably all (x(:)).

For example,

x = ones (2,3);
x(2,2) = 0
x =

   1   1   1
   1   0   1

all (x)
ans =

  1  0  1
false || x
ans = 0

Maybe, this was done intentionally in Octave to make the behavior consistent to how arrays convert to Boolean values in if conditions?
In Matlab R2022a:

>> if 'test', disp('Hello'); end
Hello
>> if [1, 0, 1], disp('Hello'); end
>> if [1, 1, 1], disp('Hello'); end
Hello

At least in that context, it seems to be using an implicit all(...).

@jwe

Do you have actual working code that depends on an error being thrown for the kind of expression you showed in the original post?

It was actually the opposite situation. I had a piece of code written by a colleague in Octave that broke when I tried to use it in Matlab. Octave was perfectly happy to treat '0xFFFFFFFF' as true but Matlab didn’t like it.

Thanks to you all for your attention. It seems that it isn’t clear what is “the right thing to do”. It also seems that Matlab isn’t really consistent either, based on @mmuetzel’s example below (in R2022b):

>> if 'test', disp('Hello'); end
Hello

Or even this using my original “problem” char vector:

>> if '0xFFFFFFFF', disp('Hello'); end
Hello

but if you try this it fails:

>> if 'test' || 'test', disp('Hello'); end
Operands to the logical AND (&&) and OR (||) operators must be convertible to logical scalar values. Use
the ANY or ALL functions to reduce operands to logical scalar values.

Perhaps Matlab should apply the implicit all in both cases and issue a warning instead of an error?

I’m not sure how strong the Octave goal of Matlab compatibility is; I just wanted to point out this incompatibility.

I do agree with @arungiridhar that this incompatibility should be documented.

Meanwhile, I’ve modified the problem piece of code so that it works in both.

Thanks again

Octave generally aims for full functional compatibility, with additional functionality as a superset being acceptable. I think this falls into that case. the behavior isn’t different or incompatible. where it works - in an IF - it behaves the same. where matlab errors, octave provides a consistent behavior to the IF handling. Unless the lack of an error results in other compatibility problems with code that doesn’t throw an error in matlab, it’s usually ok.

where would be the best place to document this, in the binary boolean operators section of the manual?

That is where I would look for it.

noticing that Short-circuit Boolean Operators (GNU Octave (version 7.3.0)) already includes the following:

The expression boolean1 is evaluated and converted to a scalar using the equivalent of the operation 'all (boolean1(:))'.

is the idea that it just needs explicit mention that that is a matlab incompatibility? how about something like:

The expression boolean1 is evaluated and converted to a scalar using the equivalent of the operation `all (boolean1(:))`. Note that if boolean1 is not of type logical, Octave will perform automatic conversion of `boolean1` to a logical data type according to XREF@Automatic-Conversion-of-Data-Types. This is a known extension beyond MATLAB capability which throws an error if `boolean1` is not a logical scalar (as of v2022b).

(is the last sentence appropriate/necessary?)

now noting that Automatic-Conversion-of-Data-Types makes no mention of logicals and would need to be updated.

Last I see: Logical Values (GNU Octave (version 7.3.0))

the only point that seems to apply is at the end where it says:

Logical values can also be constructed by casting numeric objects to logical values, or by using the `true` or `false` functions.

perhaps something should be said there, but maybe it’s addressed well enough above.

I DID note, however, that it says ‘casting numeric objects’. I now realise this all started about char vectors. I see the following:

octave:1> logical("blah")
error: logical: wrong type argument 'string'
octave:2> logical('blah')
error: logical: wrong type argument 'sq_string'
octave:4> true && [0 1 2]
ans = 0
octave:5> true && ["a","b"]
ans = 1
octave:6> all(["a","b"])
ans = 1
octave:9> logical(char(0))
error: logical: wrong type argument 'sq_string'
octave:10> all(char(0))
ans = 0
octave:11> true && char(0)
ans = 0
octave:13> true + char(0)
ans = 1
octave:14> class(ans)
ans = double

it seems some functions do char->logical conversion. is there any inconsistency here to be addressed beyond documentation?

Yes. Within reason, we try to allow Matlab code to run in Octave, but we don’t normally care about flagging all possible places where code that works in Octave won’t work in Matlab.

1 Like

If you are working on the docs for the && and ||, maybe it would be worth noting that the following behavior that we want about is duplicated in Octave for Matlab compatibility?

Warning: there is one exception to the rule of evaluating all (boolean1(:)), which is when boolean1 is the empty matrix. The truth value of an empty matrix is always false so [] && true evaluates to false even though all ([]) is true.

If I remember correctly, in the old days of Matlab character arrays were just double arrays containing ASCII character codes because double arrays were the only data type in Matlab. The only difference between a character and numeric data was a flag set to say “display this array as ASCII characters instead of numbers”.

so, do we expect all char arrays to convert the same as doubles would? it seems we don’t exactly do that.