modelica / ModelicaSpecification

Specification of the Modelica Language
https://specification.modelica.org
Creative Commons Attribution Share Alike 4.0 International
98 stars 41 forks source link

Type for array subscripting #3410

Open HansOlsson opened 1 year ago

HansOlsson commented 1 year ago

The specification has integer subscripts (which is the default), but also enumeration and Boolean subscripts https://specification.modelica.org/master/arrays.html#boolean-or-enumeration-indices

The latter two are not well-supported, and looking more closely array declarations explicitly states that:

An array indexed by Boolean or enumeration type can only be used in the following ways:

  • Subscripted using expressions of the appropriate type (i.e., Boolean or the enumerated type).
  • Binding equations of the form x1 = x2 are allowed for arrays independent of whether the index types of dimensions are subtypes of Integer, Boolean, or enumeration types.

We could generalize it (to support general subscripting), and then we have the following issues:

Note that enumeration and Boolean subscripts for arrays are not used much. It can be used to define "truth-tables" for 9 and 4-valued logic as in Modelica.Electrical.Digital.Tables; but I don't know many additional uses.

henrikt-ma commented 1 year ago

The latter two are not well-supported, and looking more closely array declarations explicitly states that:

I find it unbelievable that the intention of the specification would be to really make them that useless. For example, should users really expect that one cannot assign one enumeration-indexed array to another, or that one cannot pass an enumeration-indexed array in a function call? I suggest that we fill this gap in the specification by making them more useful. In general, it should be a matter of making sure we don't impose unnecessary restriction to integer-indexed arrays.

To begin with, I don't see any issues with non-integer indexed arrays in the following contexts:

I'd like to explicitly mention that non-integer indexed arrays are not allowed in:

As we have already noted in recent discussions, some design work is also needed in some cases:

(For array slicing with : it would seem natural to keep the type of the index, whereas it would seem natural that array slicing with vectors always result in an integer-indexed dimension.)

Anything else one would need to cover to make non-integer indexed arrays first class citizens of Modelica? Any of the above that doesn't would seem hard to implement if it's not already working in tools?

perost commented 1 year ago

Anything else one would need to cover to make non-integer indexed arrays first class citizens of Modelica?

HansOlsson commented 1 year ago

The latter two are not well-supported, and looking more closely array declarations explicitly states that:

I find it unbelievable that the intention of the specification would be to really make them that useless. For example, should users really expect that one cannot assign one enumeration-indexed array to another, or that one cannot pass an enumeration-indexed array in a function call? I suggest that fill this gap in the specification by making them more useful. In general, it should be a matter of making sure we don't impose unnecessary restriction to integer-indexed arrays

To begin with, I don't see any issues with non-integer indexed arrays in the following contexts:

  • Equality and assignment
  • Function calls
  • Addition, subtraction, and string concatenation
  • Array multiplication
  • Division by numeric scalar
  • Element-wise division
  • Element-wise exponentiation
  • Boolean operators

I don't have a major objection for these, but:

I'd like to explicitly mention that non-integer indexed arrays are not allowed in:

  • Scalar exponentiation of matrices

I don't see why they should be special, but clearly it relates to the handling of identity(...). If the matrix gives transition probabilities in a Markov-chain I could see that indexing with an enumeration for the states makes sense, and exponentiation also makes sense to compute probabilities after n steps. However, as in general I don't see that anyone actually does that.

HansOlsson commented 1 year ago

Anything else one would need to cover to make non-integer indexed arrays first class citizens of Modelica?

  • Function calls with flexible array sizes. What happens if you do e.g.:
    
    function f
    input Real x[:];
    input Integer i;
    output Real y;
    algorithm
    y := x[i];  // Is this allowed if the function argument has a non-integer indexed dimension?
    end f;

Yes, that would be one of the challenges. The current specification handles that by requiring a matrix defined as x[:] is indexed with integers. What we might do is clarify that f(x2) is part of the "Binding equations of the form x1 = x2 are allowed for arrays independent of whether the index types of dimensions are subtypes of Integer, Boolean, or enumeration types." exception.

model M type E = enumeration(a, b, c); Real y[E]; Real z = f(y, 1); end M;


* What is the size of a non-integer indexed dimension? This applies to both the `size` operator as well as any use of "dimension size" in the specification. I'm not sure if having the size be anything other than the number of elements, i.e. an integer, makes much sense, but it has implications for e.g. type compatibility which is defined in terms of `size`.

I would say that size returning an integer is the only useful one, even if not indexed with integers. If we want to generate all indices for the vector we should have lowerBound(x) and upperBound(x) as separate functions, but I'm not sure it will cover all cases, and I doubt that we should prioritize that.

henrikt-ma commented 1 year ago

I'd like to explicitly mention that non-integer indexed arrays are not allowed in:

  • Scalar exponentiation of matrices

I don't see why they should be special, but clearly it relates to the handling of identity(...). If the matrix gives transition probabilities in a Markov-chain I could see that indexing with an enumeration for the states makes sense, and exponentiation also makes sense to compute probabilities after n steps. However, as in general I don't see that anyone actually does that.

Right, scalar exponentiation of matrices should work as long as the two array dimension specifications agree, which should follow naturally from the interpretation as repeated multiplication. It would also provide an interesting way to create the identity matrix for Real[MyEnum, MyEnnum] (making an assumption about how one would define size to work for the enumeration-indexed dimension):

  Real[MyEnum, MyEnum] dummy = fill(1.0, size(dummy, 1), size(dummy, 2));
  Real[MyEnum, MyEnum] id = dummy^0;
henrikt-ma commented 1 year ago

I think we lost focus on the real problem here, which is how to interpret this:

An array indexed by Boolean or enumeration type can only be used in the following ways:

  • Subscripted using expressions of the appropriate type (i.e., Boolean or the enumerated type).

In particular, there has been some confusion about this case:

  type E = enumeration(a, b, c);
  Real[E] x;
  Integer sz = size(x[E.a : E.c]);

Maybe we just need to add some clarifications in https://specification.modelica.org/master/arrays.html#array-indexing ?

For example, this could say more clearly that the resulting array dimension is always integer-indexed (and avoid the strange use of reduced by):

A vector expression can be used to pick out selected rows, columns and elements of vectors, matrices, and arrays. The number of dimensions of the expression is reduced by the number of scalar index arguments.

I suppose the most controversial part is what to say about taking a full slice using the : operator:

Real[E, 3] x;
Real[E] x2 = x[:, 2];

I propose that taking a full slice preserves the original array dimension so that the above declaration equation does not involve any array dimension coercion.

henrikt-ma commented 1 year ago

Coming from #3395, I also realize that we need the current issue to also cover the following even though it is not exactly array subscripting.

I would like us to discuss the possibility of unintentional consequences of just referring to https://specification.modelica.org/master/statements-and-algorithm-sections.html#types-as-iteration-ranges when describing array construction.

My gut feeling is that these two are different:

type E = enumeration(a, b, c);
{ 1.0 for i in E.min : E.max } /* Needs to be array of type Real[3] */
{ 1.0 for i in E } /* Would like this to be array of type Real[E] */

Whatever way we resolve this, I think it would deserve special mention in https://specification.modelica.org/master/arrays.html#array-constructor-with-iterators.