switch-case with multiple matches in matlab for code generation
Asked Answered
L

1

6

The following code is valid matlab sytax to check whether b matches any elements in a. However, if the code is used for code generation (i.e. simulink) then I get the error:

'code generation only supports cell operations for varargin and varargout  

You can check this by adding %#codegen at the top of the script.)

a={2 3};
b=3;
switch b
    case a
        disp yay
    otherwise
        disp boo
end

What should I do to match multiple patterns in a case statement in code-generation compatible code?

The following don't work for me:

case a(1) || a(2) %//with a=[2, 3] above, since cells not allowed

case a(:)
Libenson answered 27/7, 2015 at 7:58 Comment(1)
I think Matlab Coder is really limited so you have to change your code in order to make it work. Instead of the switch statement, you can use the if statement, it should work. I think the switch statement requires a cell value for multiple instances.Blasting
N
9

Matlab coder does not support 'cell arrays', and has a limited set of functions it can handle. Remember than C is not as flexible as Matlab, specially regarding the type of data it handles. C does not do dynamic type (a structure should be defined once and the definition cannot change in the code). So Matlab cannot let you use cell array which is very loosely typed and where the next element you would add to your cell array would be of different type than the other ones.

So there will be cases where you will have to explicit things for Matlab if you expect it to convert it into possible C language.

For your case, different options:

Explicit list directly in case statement

If you do not have to reuse a for comparison too often, you can replace case a with an explicit list like case {2,3,4,5}:

function test_coder(b)
switch b
    case {2,3,4,5}
        disp yay
    otherwise
        disp boo
end

It looks like a cell array but it isn't. Because it is explicit enough (the variable just hold 4 double type) Matlab will internally use an array and compare b to each element (it will "expand" the case statements). Indeed, this part of the generated code look like (pure C way):

  guard1 = FALSE;
  switch ((int32_T)emlrtIntegerCheckFastR2012b(b, &emlrtDCI, emlrtRootTLSGlobal))
  {
   case 2:
    guard1 = TRUE;
    break;

   case 3:
    guard1 = TRUE;
    break;

   case 4:
    guard1 = TRUE;
    break;

   case 5:
    guard1 = TRUE;
    break;
... // and so on

use ismember with arrays.

The function ismember is supported by the code generator. So the code below works too:

function test_coder(b)

a=[2 3 4 5] ; %// define array "a"
c=[8 9 10]  ; %// define array "c"

if ismember(b,a)
    disp yay
elseif ismember(b,c)
    disp youhou
else
    disp boo

end

Note however that the coder requires the arrays sent to ismember to be sorted otherwise it will throw an error.

This works if you have a lot of comparison to do, however given the complexity of the generated code, I would advise using ismember only when you really need it.
when your cases are simple enough I would recommend to go for explicit declarations of your cases (using the {...} "shortcut" if you need it.


Also be careful always to look at your generated code:
In you initial example, when you specify b=3 in the code, Matlab detect that, detect that the code will always flow this way so it wasn't even coding the comparison logic ... The generated code was just a quick disp yay ...

I had to place b as an input to get Matlab to actually code the comparison logic. To compile the code above, you have to specify which type the input variable b will be. So I compiled the above using:

codegen test_coder.m -args {0}
Nickelson answered 27/7, 2015 at 10:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.