Search code examples
modelica

Array indexing with boolean array


Given a Real array (e.g. myArray) and a Boolean array (e.g. myMask), I'd like to have:

  • if myMask[i] == true then myArray[i] = myValueTrue
  • if myMask[i] == false then myArray[i] = myValueFalse

This does work

model BooleanIndexing
  parameter Boolean myMask[3] = {false, true, true};
  parameter Boolean myMask_negated[3] = {true, false, false};
  Real myArray[3];
  parameter Real myValueTrue = 3.0;
  parameter Real myValueFalse = 5.0;
equation
  myArray[Modelica.Math.BooleanVectors.index(myMask)] = fill(myValueTrue, Modelica.Math.BooleanVectors.countTrue(myMask));
  myArray[Modelica.Math.BooleanVectors.index(myMask_negated)] = fill(myValueFalse, Modelica.Math.BooleanVectors.countTrue(myMask_negated));
end BooleanIndexing;

but this does not

model BooleanIndexing
  parameter Boolean myMask[3] = {false, true, true};
  parameter Boolean myMask_negated[3] = not myMask;
  Real myArray[3];
  parameter Real myValueTrue = 3.0;
  parameter Real myValueFalse = 5.0;
equation
  myArray[Modelica.Math.BooleanVectors.index(myMask)] = fill(myValueTrue, Modelica.Math.BooleanVectors.countTrue(myMask));
  myArray[Modelica.Math.BooleanVectors.index(myMask_negated)] = fill(myValueFalse, Modelica.Math.BooleanVectors.countTrue(myMask_negated));
end BooleanIndexing;

The only difference is how I initialized myMask_negated.

The errors are, in OpenModelica:

[BooleanIndexing: 9:3-9:139]: Illegal subscript Modelica.Math.BooleanVectors.index({myMask_negated[1], myMask_negated[2], myMask_negated[3]}) for dimensions 3 in component myArray[Modelica.Math.BooleanVectors.index(myMask_negated)].

[BooleanIndexing: 9:3-9:139]: Variable myArray[Modelica.Math.BooleanVectors.index(myMask_negated)] not found in scope BooleanIndexing.

Error occurred while flattening model BooleanIndexing

and in Dymola2018

Translation of BooleanIndexing:

Failed to expand myArray[Modelica.Math.BooleanVectors.index(myMask)].

Errors or failure to expand the equation:
myArray[Modelica.Math.BooleanVectors.index(myMask)] = fill(myValueTrue, Modelica.Math.BooleanVectors.countTrue(myMask));
Found in class BooleanIndexing, C:/workspace/modelica_vehicle/modelica_test/BooleanIndexing.mo at line 8.

Errors or failure to expand vector or matrix expressions.

Translation aborted.

Direct boolean indexing myArray[myMask] seems not to be the solution here. I cannot see why they are failing and if there are any more elegant solutions.


Solution

  • Both of your versions do not guarantee that the correct number of equations are generated. myValueTrue and myValueTrue_negated are both parameters, so the user can change the values of the vectors to something which is not complementary.

    Hence, I would have recommended to set

    final parameter Boolean myMask_negated[3] = not myMask;
    

    but this also does not work, neither in Open Modelica nor in Dymola.

    So instead, I recommend to delete myMask_negated and use for loops instead. Either with two seperate ones:

    model BooleanIndexing
      parameter Boolean myMask[3] = {false, true, true};
      Real myArray[3];
      parameter Real myValueTrue = 3.0;
      parameter Real myValueFalse = 5.0;
    equation 
      for i in Modelica.Math.BooleanVectors.index(myMask) loop
        myArray[i] = myValueTrue;
      end for;
    
      for i in Modelica.Math.BooleanVectors.index(not myMask) loop
        myArray[i] = myValueFalse;
      end for;
    
    end BooleanIndexing;
    

    or with a single for loop using an array constructor, as shown here:

    model BooleanIndexing2
      parameter Boolean myMask[3] = {false, true, true};
      Real myArray[3];
      parameter Real myValueTrue = 3.0;
      parameter Real myValueFalse = 5.0;
    equation 
    
      myArray = {if value then myValueTrue else myValueFalse for value in myMask};
    
    end BooleanIndexing2;