bugGNU Octave - Bugs: bug #51412, strcmp with multidimensional char...

 
 

bug #51412: strcmp with multidimensional char arrays

Submitter:  Guillaume <gyom>
Submitted:  Fri 07 Jul 2017 09:48:27 AM UTC
   
 
Category:  Octave Function Severity:  3 - Normal
Priority:  5 - Normal Item Group:  Matlab Compatibility
Status:  Confirmed Assigned to:  None
Originator Name:  Guillaume Open/Closed:  * Open
Release:  * dev Operating System:  * Any
Fixed Release:  None Planned Release:  None
* Mandatory Fields

Add a New Comment Rich Markup
   

Jump to the original submission

Tue 13 Dec 2022 09:57:02 PM UTC, comment #10: 

just providing an update with octave 8.0.1 (hg id: 24bd675bceab) and matlab 2022b:

no change in the comment #0 response except the 2D case in Octave now gives a warning:

"warning: multi-row character matrix converted to a string, only the first row is used"


adding in the Matlab behavior with string arrays:


%1D array
>> a = string('abc')
a =
    "abc"
>> strcmp(a,a)
ans =
  logical
   1
>> strcmp(a,{a})
ans =
  logical
   0
>> strcmp({a},{a})
ans =
  logical
   0
>> strcmp(a,{a,a})
ans =
  1×2 logical array
   0   0
>> strcmp({a},{a,a})
ans =
  1×2 logical array
   0   0
>> a = ["abc","def"]
a =
  1×2 string array
    "abc"    "def"
>> strcmp(a,a)
ans =
  1×2 logical array
   1   1
>> strcmp(a,{a})
ans =
  1×2 logical array
   0   0
>> strcmp({a},{a})
ans =
  logical
   0
>> strcmp(a,{a,a})
ans =
  1×2 logical array
   0   0
>> strcmp({a},{a,a})
ans =
  1×2 logical array
   0   0

%2D array
>> a = ["abc","def"; "ghi", "jkl"]
a =
  2×2 string array
    "abc"    "def"
    "ghi"    "jkl"
>> strcmp(a,a)
ans =
  2×2 logical array
   1   1
   1   1
>> strcmp({a},{a})
ans =
  logical
   0
>> strcmp(a,{a,a})
Error using strcmp
Inputs must be the same size or either one can be a scalar.
>> strcmp({a},{a,a})
ans =
  1×2 logical array
   0   0

%3D array
>> a = cat(3,a,a)
  2×2×2 string array
a(:,:,1) =
    "abc"    "def"
    "ghi"    "jkl"
a(:,:,2) =
    "abc"    "def"
    "ghi"    "jkl"
>> strcmp(a,a)
  2×2×2 logical array
ans(:,:,1) =
   1   1
   1   1
ans(:,:,2) =
   1   1
   1   1
>> strcmp(a,{a})
  2×2×2 logical array
ans(:,:,1) =
   0   0
   0   0
ans(:,:,2) =
   0   0
   0   0
>> strcmp({a},{a})
ans =
  logical
   0
>> strcmp(a,{a,a})
Error using strcmp
Inputs must be the same size or either one can be a scalar.
>> strcmp({a},{a,a})
ans =
  1×2 logical array
   0   0


also, mike's check in comment #5, in octave 8.0.1:

>> a = ['aaa'; 'bbb'];
>> string_value (a)
error: 'string_value' undefined near line 1, column 1
>> cellstr_value (a)
error: 'cellstr_value' undefined near line 1, column 1

so it seems those functions no longer exist in octave?

and Rik's comment #6 and comment #7 tests:

Matlab 2022b:

>> x = {['aa'; 'bb']; ['aa'; 'cc']}
x =
  2×1 cell array
    {2×2 char}
    {2×2 char}
>> strcmp (x, 'aa')
ans =
  2×1 logical array
   0
   0
>> strcmp (x, {'aa'})
ans =
  2×1 logical array
   0
   0
>> strcmp (x, {'aa';'cc'})
ans =
  2×1 logical array
   0
   0
>> strcmp (x, {['aa';'cc']})
ans =
  2×1 logical array
   0
   1
>> x = {['ab']; ['cd'; 'ef']}
x =
  2×1 cell array
    {'ab'    }
    {2×2 char}
>> iscellstr (x)
ans =
  logical
   1
>> y = {['ab']; ['c'; 'e']}
y =
  2×1 cell array
    {'ab'    }
    {2×1 char}
>> iscellstr (y)
ans =
  logical
   1


and the same tests in Octave 8.0.1:

ﻳ誂>> x = {['aa'; 'bb']; ['aa'; 'cc']};
>> strcmp (x, 'aa')
warning: multi-row character matrix converted to a string, only the first row is used
warning: multi-row character matrix converted to a string, only the first row is used
ans =

  1
  1

>> strcmp (x, {'aa'})
ans =

  1
  1

>> strcmp (x, {'aa';'cc'})
ans =

  1
  0

>> strcmp (x, {['aa';'cc']})
warning: multi-row character matrix converted to a string, only the first row is used
ans =

  1
  1

>> x = {['ab']; ['cd'; 'ef']}
x =
{
  [1,1] = ab
  [2,1] =

cd
ef

}

>> iscellstr (x)
ans = 1
>> y = {['ab']; ['c'; 'e']}
y =
{
  [1,1] = ab
  [2,1] =

c
e

}

>> iscellstr (y)
ans = 1


Nicholas Jankowski <nrjank>
Group Member
Tue 11 Jul 2017 04:25:48 PM UTC, comment #9: 

This does need to be tackled, but it is not going to be easy.  Matlab's documentation refers to cellstr as


"A cell array of character vectors is a cell array where every cell contains a character vector."


Octave has assumed, quite reasonably, that a character vector is a 1xN char array.  But the code examples clearly show that Matlab doesn't require a vector---It only requires a char array object for each cell.

Also, Matlab has recently introduced string arrays which are yet another fundamental object type to join char arrays and cellstrs.  Eventually Octave will probably support these so it makes sense that at the same time that is_string, string_value, and cellstr_value are overhauled to make them Matlab compatible, that we also address string arrays.  In fact, we might want to reserve is_string to test for the new string array class and use another function name (maybe ischar?) to test if something is just a char array.

Some more slightly bad news.  I did work up a cset that fixes the issue with strcmp, but by avoiding cellstr it is 10X slower. 

Rik <rik5>
Group administrator
Tue 11 Jul 2017 09:04:07 AM UTC, comment #8: 

MATLAB 2016a

x = {['aa'; 'bb']; ['aa'; 'cc']};
strcmp (x, 'aa')
strcmp (x, {'aa'})
strcmp (x, {'aa';'cc'})
strcmp (x, {['aa';'cc']})
ans =
     0
     0
ans =
     0
     0
ans =
     0
     0
ans =
     0
     1




x = {['ab']; ['cd'; 'ef']}
iscellstr (x)
y = {['ab']; ['c'; 'e']}
iscellstr (y)
x =
    'ab'
    [2x2 char]
ans =
     1
y =
    'ab'
    [2x1 char]
ans =
     1


Ceral Paquet <octavebugs>
Mon 10 Jul 2017 08:53:14 PM UTC, comment #7: 

Another test for someone with Matlab


x = {['ab']; ['cd'; 'ef']}
iscellstr (x)
y = {['ab']; ['c'; 'e']}
iscellstr (y)


If I read the documentation correctly, Matlab should return false for both cases.

Rik <rik5>
Group administrator
Mon 10 Jul 2017 06:39:05 PM UTC, comment #6: 

Could someone with matlab test this?


x = {['aa'; 'bb']; ['aa'; 'cc']};
strcmp (x, 'aa')
strcmp (x, {'aa'})
strcmp (x, {'aa';'cc'})
strcmp (x, {['aa';'cc']})



Rik <rik5>
Group administrator
Mon 10 Jul 2017 05:16:57 PM UTC, comment #5: 

In addition I think we need to be wary about the definitions of "string" and "cell string" in this function, and places where string_value and cellstr_value are used to compare two operands.

The is_string and iscellstr tests return true for values that cannot be exactly represented by our normal definition of what a "string" is.

Simple example of a two-dimensional character matrix:


>> a = ['aaa'; 'bbb'];
>> string_value (a)
ans = aaa
>> cellstr_value (a)
ans =
{
  [1,1] = aaa
}


The string_value method truncates a multi-dimensional character vector to return just the first row (this has been discussed in other bug reports). The cellstr_value method calls string_value.

Mike Miller <mtmiller>
Group Member
Mon 10 Jul 2017 04:59:17 PM UTC, comment #4: 

Documentation for Matlab's behavior is at http://www.mathworks.com/help/matlab/ref/strcmp.html.

Mixed char matrix / cellstr comparisons are tricky.  In bug #51187 I had to change the ismember functionality specifically for Matlab compatibility

The do_strcmp_fun function is in libinterp/corefcn/strfns.cc.  I see that there are several cases to handle broadcasting correctly.  For example, when doing


strcmp ("b", {"a", "b", "c", "d"})


I have to rebuild Octave with debugging features in order to test what is going on, but it may be an obvious extra case in the if/else tree needs to be added to handle this.


Rik <rik5>
Group administrator
Mon 10 Jul 2017 04:53:47 PM UTC, comment #3: 

Ok, so our definition of "iscellstr" is correct, but something for which "iscellstr" returns true cannot necessarily be turned into a one-dimensional array of strings.

Mike Miller <mtmiller>
Group Member
Mon 10 Jul 2017 09:25:39 AM UTC, comment #2: 

Here is the Matlab output for the same calls:


>> a = ['aa'; 'bb'];
>> strcmp (a, {a})

ans =

  2x1 logical array

   0
   0

>> strcmp (a, {a,a})

ans =

  1x2 logical array

   0   0

>> a = ['aaa'; 'bbb'; 'ccc'];
>> strcmp (a, {a})

ans =

  3x1 logical array

   0
   0
   0

>> strcmp (a, {a,a})
Error using strcmp
The number of rows of the string matrix must match the number of elements in the cell vector.

>> a = repmat ('a', 3, 3, 3);
>> iscellstr({a})

ans =

  logical

   1


Guillaume <gyom>
Fri 07 Jul 2017 08:04:53 PM UTC, comment #1: 

So to me the immediately interesting cases are


>> a = ['aa'; 'bb'];
>> strcmp (a, {a})
ans =

  1
  0

>> strcmp (a, {a,a})
ans =

  1  0



>> a = ['aaa'; 'bbb'; 'ccc'];
>> strcmp (a, {a})
ans =

  1
  0
  0

>> strcmp (a, {a,a})
ans = 0


The 3-dimensional cases probably fail because


>> a = repmat ('a', 3, 3, 3);
>> iscellstr({a})
ans = 1


but elsewhere in Octave's baseline, code expects that if something is a cellstr, it can be converted into a vector of strings.

What does Matlab iscellstr return in this case?

Mike Miller <mtmiller>
Group Member
Fri 07 Jul 2017 09:48:27 AM UTC, original submission:  

strcmp seems to differ from Matlab when the input is not a row vector, see with the following code:


% 1D array
a = char(ceil(rand(1,5)*5+'a'));
strcmp(a,a)
strcmp(a,{a})
strcmp({a},{a})
strcmp(a,{a,a})
strcmp({a},{a,a})

% 2D array
a = char(ceil(rand(2,5)*5+'a'));
strcmp(a,a)
strcmp(a,{a})
strcmp({a},{a})
strcmp(a,{a,a})
strcmp({a},{a,a})

% 3D array
a = char(ceil(rand(2,5,2)*5+'a'));
strcmp(a,a)
strcmp(a,{a})
strcmp({a},{a})
strcmp(a,{a,a})
strcmp({a},{a,a})


In Octave:


octave:1> % 1D array
octave:1> a = char(ceil(rand(1,5)*5+'a'));
octave:2> strcmp(a,a)
ans = 1
octave:3> strcmp(a,{a})
ans = 1
octave:4> strcmp({a},{a})
ans = 1
octave:5> strcmp(a,{a,a})
ans =

  1  1

octave:6> strcmp({a},{a,a})
ans =

  1  1

octave:7>
octave:7> % 2D array
octave:7> a = char(ceil(rand(2,5)*5+'a'));
octave:8> strcmp(a,a)
ans = 1
octave:9> strcmp(a,{a})
ans =

  1
  0

octave:10> strcmp({a},{a})
ans = 1
octave:11> strcmp(a,{a,a})
ans =

  1  0

octave:12> strcmp({a},{a,a})
ans =

  1  1

octave:13>
octave:13> % 3D array
octave:13> a = char(ceil(rand(2,5,2)*5+'a'));
octave:14> strcmp(a,a)
ans = 1
octave:15> strcmp(a,{a})
error: invalid conversion of charNDArray to string_vector
octave:15> strcmp({a},{a})
error: invalid conversion of charNDArray to string
octave:15> strcmp(a,{a,a})
error: invalid conversion of charNDArray to string_vector
octave:15> strcmp({a},{a,a})
error: invalid conversion of charNDArray to string


while in Matlab:


>> % 1D array
>> a = char(ceil(rand(1,5)*5+'a'));
>> strcmp(a,a)
ans =
  logical
   1
>> strcmp(a,{a})
ans =
  logical
   1
>> strcmp({a},{a})
ans =
  logical
   1
>> strcmp(a,{a,a})
ans =
  1x2 logical array
   1   1
>> strcmp({a},{a,a})
ans =
  1x2 logical array
   1   1
>>
>> % 2D array
>> a = char(ceil(rand(2,5)*5+'a'));
>> strcmp(a,a)
ans =
  logical
   1
>> strcmp(a,{a})
ans =
  2x1 logical array
   0
   0
>> strcmp({a},{a})
ans =
  logical
   1
>> strcmp(a,{a,a})
ans =
  1x2 logical array
   0   0
>> strcmp({a},{a,a})
ans =
  1x2 logical array
   1   1
>>
>> % 3D array
>> a = char(ceil(rand(2,5,2)*5+'a'));
>> strcmp(a,a)
ans =
  logical
   1
>> strcmp(a,{a})
ans =
  2x1 logical array
   0
   0
>> strcmp({a},{a})
ans =
  logical
   1
>> strcmp(a,{a,a})
ans =
  1x2 logical array
   0   0
>> strcmp({a},{a,a})
ans =
  1x2 logical array
   1   1


Guillaume <gyom>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

No files currently attached

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by nrjank (Posted a comment)
  • -email is unavailable- added by octavebugs (Posted a comment)
  • -email is unavailable- added by rik5 (Posted a comment)
  • -email is unavailable- added by mtmiller (Posted a comment)
  • -email is unavailable- added by gyom (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only group members can vote.

     

    Follows 1 latest change.

    Date Changed by Updated Field Previous Value => Replaced by
    2017-07-11 rik5 StatusNone Confirmed

    Back to the top

    Powered by Savane 3.13-f8d8.
    Corresponding source code