Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type for array subscripting #3410

Open
HansOlsson opened this issue Sep 4, 2023 · 7 comments
Open

Type for array subscripting #3410

HansOlsson opened this issue Sep 4, 2023 · 7 comments
Labels
enhancement New feature or request
Milestone

Comments

@HansOlsson
Copy link
Collaborator

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.

@HansOlsson HansOlsson added the enhancement New feature or request label Sep 4, 2023
@henrikt-ma
Copy link
Collaborator

henrikt-ma commented Sep 7, 2023

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:

  • 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'd like to explicitly mention that non-integer indexed arrays are not allowed in:

  • Scalar exponentiation of matrices

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

  • Array slicing with :
  • Array slicing with vectors (including vectors constructed from ranges)

(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
Copy link
Collaborator

perost commented Sep 7, 2023

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;
    
    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.

@HansOlsson
Copy link
Collaborator Author

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:

  • It should be a separate PR, and not block this one.
  • It doesn't seem that useful. The use in MSL is just using them for constant arrays that we index to get tables for various operations (like AND, OR, ... with 4 and 9-valued logic). Are there other important use-cases in practice? If not I don't think we should prioritize this.
  • It will take time to ensure that all cases are covered consistently. Currently you can write A*ones(size(A,2)) to sum along the rows, should ones be "polymorphic" in terms of indexing, should we allow matrix multiplication with non-matched dimensions, or should we have some explicit conversion operator? Similar considerations apply for many other operations.

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
Copy link
Collaborator Author

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
Copy link
Collaborator

henrikt-ma commented Sep 7, 2023

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
Copy link
Collaborator

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
Copy link
Collaborator

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.

@HansOlsson HansOlsson added this to the Phone 2023-5 milestone Nov 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants