Arrays¶
An array can be regarded as a collection of values, all of the same type. Modelica arrays can be multidimensional and are “rectangular,” which in the case of matrices has the consequence that all rows in a matrix have equal length, and all columns have equal length.
Each array has a certain dimensionality, i.e., number of dimensions. The degenerate case of a scalar variable is not really an array, but can be regarded as an array with zero dimensions. Vectors have one dimension, matrices have two dimensions, etc. [So-called row vectors and column vectors do not exist in Modelica and cannot be distinguished since vectors have only one dimension. If distinguishing these is desired, row matrices and column matrices are available, being the corresponding two-dimensional entities. However, in practice this is seldom needed since the usual matrix arithmetic and linear algebra operations have been defined to give the expected behavior when operating on Modelica vectors and matrices.]
Modelica is a strongly typed language, which also applies to array types. The number of dimensions of an array is fixed and cannot be changed at run-time [in order to permit strong type checking and efficient implementation.] However, the sizes of array dimensions can be computed at run-time, [allowing fairly generic array manipulation code to be written as well as interfacing to standard numeric libraries implemented in other programming languages.]
An array is allocated by declaring an array variable or calling an array
constructor. Elements of an array can be indexed by Integer
,
Boolean
, or enumeration
values.
Array Declarations¶
The Modelica type system includes scalar number, vector, matrix (number of dimensions, ndim=2), and arrays of more than two dimensions. [There is no distinguishing between a row and column vector.]
The following table shows the two possible forms of declarations and defines the terminology. C is a placeholder for any class, including the built-in type classes Real, Integer, Boolean, String, and enumeration types. The type of a dimension upper bound expression, e.g. n, m, p,… in the table below, need to be a subtype of Integer or EB for a class EB that is an enumeration type or subtype of the Boolean type. Colon (:) indicates that the dimension upper bound is unknown and is a subtype of Integer.
Upper and lower array dimension index bounds are described in .
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 as well as declaration assignments 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.
Modelica form 1 | Modelica form 2 | # dimensions | Designatio n | Explanatio n |
---|---|---|---|---|
C x; | C x; | 0 | Scalar | Scalar |
C[n] x; | C x[n]; | 1 | Vector | n – Vector |
C[EB] x; | C x[EB] | 1 | Vector | Vector index by enumeration or Boolean type EB |
C[n, m] x; | C x[n, m]; | 2 | Matrix | n x m Matrix |
C[:math:` n_1`, ,…,:mat h:n_k] x; | C x[:math:` n_1`, ,…,:math: n_k]; | k | Array | Array with k dimensions (k>=0). |
[The number of dimensions and the dimensions sizes are part of the type, and shall be checked for example at redeclarations. Declaration form 1 displays clearly the type of an array, whereas declaration form 2 is the traditional way of array declarations in languages such as Fortran, C, C++.
Real[:] v1, v2 // vectors v1 and v2 have unknown sizes. The actual sizes may be different.
It is possible to mix the two declaration forms although it might be confusing.
Real[3,2] x[4,5]; // x has type Real[4,5,3,2];
The reason for this order is given by examples such as:
type R3=Real[3];
R3 a;
R3 b[1]={a};
Real[3] c[1]=b;
Using a type for “a” and “b” in this way is normal, and substituting a type by its definition allow “c”.
A vector y indexed by enumeration values
type TwoEnums = enumeration(one,two);
Real[TwoEnums] y;
]
Zero-valued dimensions are allowed, so: C x[0]; declares an empty vector and: C x[0,3]; an empty matrix. [Special cases:
column-vectors of arrays.
Modelica form 1 Modelica form 2 # dimensions Designatio n Explanatio n C[1] x; C x[1]; 1 Vector 1 – Vector, representin g a scalar C[1,1] x; C x[1, 1]; 2 Matrix 1 x 1 – Matrix, representin g a scalar C[n,1] x; C x[n, 1]; 2 Matrix n x 1 – Matrix, representin g a column C[1,n] x; C x[1, n]; 2 Matrix 1 x n – Matrix, representin g a row
]
The type of an array of array is the multidimensional array which is constructed by taking the first dimensions from the component declaration and subsequent dimensions from the maximally expanded component type. A type is maximally expanded, if it is either one of the built-in types (Real, Integer, Boolean, String, enumeration type) or it is not a type class. Before operator overloading is applied, a type class of a variable is maximally expanded.
[Example:
type Voltage = Real(unit = "V");
type Current = Real(unit = "A");
connector Pin
Voltage v; // type class of v = Voltage, type of v = Real
flow Current i; // type class of i = Current, type of i = Real
end Pin;
type MultiPin = Pin[5];
MultiPin[4] p; // type class of p is MultiPin, type of p is Pin[4,5];
type Point = Real[3];
Point p1[10];
Real p2[10,3];
The components p1 and p2 have identical types.
p2[5] = p1[2]+ p2[4]; // equivalent to p2[5,:] = p1[2,:] + p2[4,:]
Real r[3] = p1[2]; // equivalent to r[3] = p1[2,:]
]
[Automatic assertions at simulation time:
Let A be a declared array and i be the declared maximum dimension size of the di-dimension, then an assert statement assert(i>=0, …) is generated provided this assertion cannot be checked at compile time. It is a quality of implementation issue to generate a good error message if the assertion fails.
Let A be a declared array and i be an index accessing an index of the di-dimension. Then for every such index-access an assert statement assert(i>=1 and i<=size(A,di), … ) is generated, provided this assertion cannot be checked at compile time.
For efficiency reasons, these implicit assert statement may be optionally suppressed.]
Array Dimension Lower and Upper Index Bounds¶
The lower and upper index bounds for a dimension of an array indexed by Integer, Boolean, or enumeration values are as follows:
- An array dimension indexed by integers has a lower bound of 1 and an upper bound being the size of the dimension.
- An array dimension indexed by Boolean values has the lower bound false and the upper bound true.
- An array dimension indexed by enumeration values of the type E=enumeration(e1, e2, …, en) has the lower bound E.e1 and the upper bound E.en.
Flexible Array Sizes¶
Regarding flexible array sizes and resizing of arrays in functions, see .
Built-in Array Functions¶
Modelica provides a number of built-in functions that are applicable to arrays.
The following promote function cannot be used in Modelica, but is utilized below to define other array operators and functions:
promote(A,n) | Fills dimensions of size 1 from the right to array A upto dimension n, where “n >= ndims(A)” is required. Let C = promote(A,n), with nA=ndims(A), then ndims(C) = n, size(C,j) = size(A,j) for 1 <= j <= nA, size(C,j) = 1 for nA+1 <= j <= n, C[i_1, …, i_nA, 1, …, 1] =A[i_1, …, i_nA] |
---|---|
[The function promote cannot be used in Modelica, because the number of dimensions of the returned array cannot be determined at compile time if n is a variable. Below, promote is only used for constant n.
Some examples of using the functions defined in the following to :
Real x[4,1,6];
size(x,1) = 4;
size(x); // vector with elements 4, 1, 6
size(2*x+x ) = size(x);
Real[3] v1 = fill(1.0, 3);
Real[3,1] m = matrix(v1);
Real[3] v2 = vector(m);
Boolean check[3,4] = fill(true, 3, 4);
]
Array Dimension and Size Functions¶
The following built-in functions for array dimensions and dimension sizes are provided:
Modelica | Explanation |
---|---|
ndims(A) | Returns the number of dimensions k of expression A, with k >= 0. |
size(A,i) | Returns the size of dimension i of array expression A where i shall be > 0 and <= ndims(A). |
size(A) | Returns a vector of length ndims(A) containing the dimension sizes of A. |
Dimensionality Conversion Functions¶
The following built-in conversion functions convert scalars, vectors, and arrays to scalars, vectors, or matrices by adding or removing 1-sized dimensions.
Modelica | Explanation |
---|---|
scalar(A) | Returns the single element of array A. size(A,i) = 1 is required for 1 <= i <= ndims(A). |
vector(A) | Returns a 1-vector, if A is a scalar and otherwise returns a vector containing all the elements of the array, provided there is at most one dimension size > 1. |
matrix(A) | Returns promote(A,2), if A is a scalar or vector and otherwise returns the elements of the first two dimensions as a matrix. size(A,i) = 1 is required for 2 < i <= ndims(A). |
Specialized Array Constructor Functions¶
An array constructor function constructs and returns an array computed from its arguments. Most of the constructor functions in the table below construct an array by filling in values according to a certain pattern, in several cases just giving all array elements the same value. The general array constructor with syntax array (…) or {…} is described in .
Modelica | Explanation |
---|---|
identity(n) | Returns the n x n Integer identity matrix, with ones on the diagonal and zeros at the other places. |
diagonal(v) | Returns a square matrix with the elements of vector v on the diagonal and all other elements zero. |
zeros(, ,,…) | Returns the x x x … Integer array with all elements equal to zero ( >= 0). The function need one or more arguments, that is zeros() is not legal. |
ones(,, ,…) | Return the x x x … Integer array with all elements equal to one ( >=0 ). The function need one or more arguments, that is ones() is not legal. |
fill(s,,,…) | Returns the x x x … array with all elements equal to scalar or array expression s ( >= 0). The returned array has the same type as s. Recursive definition: fill(s,,,…) = fill(fill(s,,:math :n_3, …), ,); fill(s,n)={s,s,…, s} The function needs two or more arguments; that is fill(s) is not legal. |
linspace(x1,x2,n) | Returns a Real vector with n equally spaced elements, such that v=linspace(x1,x2,n),
It is required that n >= 2. The arguments x1 and x2 shall be numeric scalar expressions. |
Reduction Functions and Operators¶
A reduction function “reduces” an array (or several scalars) to one value (normally a scalar - but the sum reduction function may give an array as result and also be applied to an operator record). Note that none of these operators (particularly min and max) generate events themselves (but arguments could generate events). The restriction on the type of the input in for reduction expressions also apply to the array elements/scalar inputs for the reduction operator with the same name.
The sum reduction function (both variants) may be applied to an operator record, provided that the operator record defines ’0’ and ’+’. It is then assumed to form an additive group.
The following reduction functions are available:
Modelica | Explanation |
---|---|
min(A) | Returns the least element of array expression A; as defined by <. |
min(x,y) | Returns the least element of the scalars x and y; as defined by <. |
for i in u, |
|
..., j in v) |
|
Returns the least value (as defined by <) of the scalar expression e(i, …, j) evaluated for all combinations of i in u, …, j in v: | |
max(A) | Returns the greatest element of array expression A; as defined by >. |
max(x,y) | Returns the greatest element of the scalars x and y; as defined by >. |
for i in u, |
|
..., j in v) |
functions and operators.
-+ |
sum(A) | |
A[1,...,1]+A[2,...,1]+....+A[en
d,...,1]+A[end,...,end] |
|
for i in u, |
|
..., j in v) |
|
Returns the sum of the expression e(i, …, j) evaluated for all combinations of i in u, …, j in v: e(u[1],… ,v[1])+e(u[2],… ,v[1])+… +e(u[end],… ,v[1])+…+e(u[end],… ,v[end]) The type of sum(e(i, …, j) for i in u, …, j in v) is the same as the type of e(i,…j). | |
product(A) | |
A[1,…,1]*A[2,…,1]*….*A[end, …,1]*A[end,…,end] | |
for i in u, |
|
..., j in v) |
|
Returns the product of the scalar expression e(i, …, j) evaluated for all combinations of i in u, …, j in v: e(u[1],...,v[1])*e(u[2],...,
nd],…,v[end]) The type of product(e(i, …, j) for i in u, …, j in v) is the same as the type of e(i,…j). |
Reduction Expressions¶
An expression:
function-name "(" expression1 for iterators ")"
is a reduction-expression. The expressions in the iterators of a reduction-expression shall be vector expressions. They are evaluated once for each reduction-expression, and are evaluated in the scope immediately enclosing the reduction-expression.
For an iterator:
IDENT in expression2
the loop-variable, IDENT, is in scope inside expression1. The loop-variable may hide other variables, as in for-clauses. The result depends on the function-name, and currently the only legal function-names are the built-in operators array, sum, product, min, and max. For array, see . If function-name is sum, product, min, or max the result is of the same type as expression1 and is constructed by evaluating expression1 for each value of the loop-variable and computing the sum, product, min, or max of the computed elements. For deduction of ranges, see ; and for using types as ranges see .
Function-name | Restriction on expression1 | Result if expression2 is empty |
---|---|---|
sum | Integer or Real | zeros(…) |
product | Scalar Integer or Real | 1 |
min | Scalar enumeration, Boolean, Integer or Real | |
( Modelica.Constants.in f for Real) | ||
max | Scalar enumeration, Boolean, Integer or Real | |
( -Modelica.Constants.i nf for Real) |
[Example:
sum(i for i in 1:10) // Gives $\sum_{i=1}^{10}i=$1+2+...+10=55
// Read it as: compute the sum of i for i in the range 1 to 10.
sum(i^2 for i in {1,3,7,6}) // Gives $\sum_{i\in \begin{Bmatrix}1&3&7&6\end{Bmatrix}}i^2=$1+9+49+36=95
{product(j for j in 1:i) for i in 0:4} // Gives {1,1,2,6,24}
max(i^2 for i in {3,7,6}) // Gives 49
]
Matrix and Vector Algebra Functions¶
The following set of built-in matrix and vector algebra functions are available. The function transpose can be applied to any matrix. The functions outerProduct, symmetric, cross and skew require Real/Integer vector(s) or matrix as input(s) and returns a Real vector or matrix:
Modelica | Explanation |
---|---|
transpose(A) | Permutes the first two dimensions of array A. It is an error, if array A does not have at least 2 dimensions. |
outerProduct(v1,v2) | Returns the outer product of vectors v1 and v2 ( = matrix(v1)*transpose( matrix(v2) ) ). |
symmetric(A) | Returns a matrix where the
diagonal elements and the
elements above the diagonal are
identical to the corresponding
elements of matrix A and where
the elements below the diagonal
are set equal to the elements
above the diagonal of A, i.e.,
B := symmetric(A) ->
B[i,j] := A[i,j], if i <= j,
B[i,j] := A[j,i], if i > j . |
cross(x,y) | Returns the cross product of the
3-vectors x and y, i.e.
cross(x,y) = vector( [ x[2]*y[3
]-x[3]*y[2]; x[3]*y[1]-x[1]*y[3]
; x[1]*y[2]-x[2]*y[1] ] ); |
skew(x) | Returns the 3 x 3 skew symmetric matrix associated with a 3-vector, i.e., ``cross(x,y) = skew(x)*y; skew(x)
]; -x[2], x[1], 0];`` |
Vector, Matrix and Array Constructors¶
The constructor function array(A,B,C,…) constructs an array from its arguments according to the following rules:
- Size matching: All arguments must have the same sizes, i.e., size(A)=size(B)=size(C)=…
- All arguments must be type compatible expressions () giving the type of the elements. The data type of the result array is the maximally expanded type of the arguments. Real and Integer subtypes can be mixed resulting in a Real result array where the Integer numbers have been transformed to Real numbers.
- Each application of this constructor function adds a one-sized dimension to the left in the result compared to the dimensions of the argument arrays, i.e., ndims(array(A,B,C)) = ndims(A) + 1 = ndims(B) + 1, …
- {A, B, C, …} is a shorthand notation for array(A, B, C, …).
- There must be at least one argument [i.e., array() or {} is not defined].
[Examples:
{1,2,3} !\emph{is a 3-vector of type Integer}.!
{{11,12,13}, {21,22,23}} !\emph{is a 2x3 matrix of type Integer}!
{{{1.0, 2.0, 3.0}}} !\emph{is a 1x1x3 array of type Real}.!
Real[3] v = array(1, 2, 3.0);
type Angle = Real(unit="rad");
parameter Angle alpha = 2.0; // type of alpha is Real.
// array(alpha, 2, 3.0) or {alpha, 2, 3.0} is a 3-vector of type Real.
Angle[3] a = {1.0, alpha, 4}; // type of a is Real[3].
]
Array Constructor with Iterators¶
An expression:
"{" expression for iterators "}"
or
array "(" expression for iterators ")"
is an array constructor with iterators. The expressions inside the iterators of an array constructor shall be vector expressions. They are evaluated once for each array constructor, and are evaluated in the scope immediately enclosing the array constructor.
For an iterator:
IDENT in array_expression
the loop-variable, IDENT, is in scope inside expression in the array construction. The loop-variable may hide other variables, as in for-clauses. The loop-variable has the same type as the type of the elements of array_expression; and can be simple type as well as a record type. The loop-variable will have the same type for the entire loop - i.e. for an array_expression {1,3.2} the iterator will have the type of the type-compatible expression (Real) for all iterations. For deduction of ranges, see ; and for using types as range see .
Array Constructor with One Iterator¶
If only one iterator is used, the result is a vector constructed by evaluating expression for each value of the loop-variable and forming an array of the result.
[Example:
array(i for i in 1:10)
// Gives the vector 1:10={1,2,3,...,10}
{r for r in 1.0 : 1.5 : 5.5}
// Gives the vector 1.0:1.5:5.5={1.0, 2.5, 4.0, 5.5}
{i^2 for i in {1,3,7,6}}
// Gives the vector {1, 9, 49, 36}
Array Constructor with Several Iterators¶
The notation with several iterators is a shorthand notation for nested array constructors. The notation can be expanded into the usual form by replacing each ’,’ by ’} for’ and prepending the array constructor with a ’{’.
[Example:
Real hilb[:,:]= { 1/(i+j-1) for i in 1:n, j in 1:n};
Real hilb2[:,:]={{ 1/(i+j-1) for j in 1:n} for i in 1:n};
Array Concatenation¶
The function cat(k,A,B,C,…) concatenates arrays A,B,C,… along dimension k according to the following rules:
- Arrays A, B, C, … must have the same number of dimensions, i.e., ndims(A) = ndims(B) = …
- Arrays A, B, C, … must be type compatible expressions () giving the type of the elements of the result. The maximally expanded types should be equivalent. Real and Integer subtypes can be mixed resulting in a Real result array where the Integer numbers have been transformed to Real numbers.
- k has to characterize an existing dimension, i.e., 1 <= k <= ndims(A) = ndims(B) = ndims(C); k shall be an integer number.
- Size matching: Arrays A, B, C, … must have identical array sizes with the exception of the size of dimension k, i.e., size(A,j) = size(B,j), for 1 <= j <= ndims(A) and j <> k.
[Examples:
Real[2,3] r1 = cat(1, {{1.0, 2.0, 3}}, {{4, 5, 6}});
Real[2,6] r2 = cat(2, r1, 2*r1);
]
Concatenation is formally defined according to:
!Let! R = cat(k,A,B,C,...)!, and let! n = ndims(A) = ndims(B) = ndims(C) =
....!, then!
size(R,k) = size(A,k) + size(B,k) + size(C,k) + ...
size(R,j) = size(A,j) = size(B,j) = size(C,j) = ...., for 1 <=j <= n and j <> k.
R[i_1, ..., i_k, ..., i_n] = A[i_1, ..., i_k, ..., i_n], for i_k <= size(A,k),
R[i_1, ..., i_k, ..., i_n] = B[i_1, ..., i_k - size(A,i), ..., i_n], for i_k <= size(A,k) + size(B,k),
....
where 1 <= i_j <= size(R,j) for 1 <= j <= n.
Array Concatenation along First and Second Dimensions¶
For convenience, a special syntax is supported for the concatenation along the first and second dimensions.
- Concatenation along first dimension:
[A; B; C; ...] = cat(1, promote(A,n), promote(B,n), promote(C,n), ...)
wheren = max(2, ndims(A), ndims(B), ndims(C), ....)
. If necessary, 1-sized dimensions are added to the right of A, B, C before the operation is carried out, in order that the operands have the same number of dimensions which will be at least two. - Concatenation along second dimension:
[A, B, C, ...] = cat(2, promote(A,n), promote(B,n), promote(C,n), ...)
wheren = max(2, ndims(A), ndims(B), ndims(C), ....)
. If necessary, 1-sized dimensions are added to the right of A, B, C before the operation is carried out, especially that each operand has at least two dimensions. The two forms can be mixed.
[...,...]
has higher precedence than[...;...]
, e.g.,[a, b; c, d]
is parsed as[[a,b];[c,d]]
.[A] = promote(A,max(2,ndims(A)))
, i.e.,[A] = A
, if A has 2 or more dimensions, and it is a matrix with the elements of A, if A is a scalar or a vector.There must be at least one argument (i.e.
[]
is not defined)
[Examples:
Real s1, s2, v1[n1], v2[n2], M1[m1,n],
M2[m2,n], M3[n,m1], M4[n,m2], K1[m1,n,k],
K2[m2,n,k];
[v1;v2] is a (n1+n2) x 1 matrix
[M1;M2] is a (m1+m2) x n matrix
[M3,M4] is a n x (m1+m2) matrix
[K1;K2] is a (m1+m2) x n x k array
[s1;s2] is a 2 x 1 matrix
[s1,s1] is a 1 x 2 matrix
[s1] is a 1 x 1 matrix
[v1] is a n1 x 1 matrix
Real[3] v1 = array(1, 2, 3);
Real[3] v2 = {4, 5, 6};
Real[3,2] m1 = [v1, v2];
Real[3,2] m2 = [v1, [4;5;6]]; // m1 = m2
Real[2,3] m3 = [1, 2, 3; 4, 5, 6];
Real[1,3] m4 = [1, 2, 3];
Real[3,1] m5 = [1; 2; 3];
]
Vector Construction¶
Vectors can be constructed with the general array constructor, e.g.,
Real[3] v = {1,2,3}.
The range vector operator or colon operator of simple-expression can be used instead of or in combination with this general constructor to construct Real, Integer, Boolean or enumeration type vectors. Semantics of the colon operator:
- j : k is the Integer vector {j, j+1, …, k}, if j and k are of type Integer.
- j : k is the Real vector {j, j+1.0, … n}, with n = floor(k-j), if j and/or k are of type Real.
- j : k is a Real, Integer, Boolean, or enumeration type vector with zero elements, if j > k.
- j : d : k is the Integer vector {j, j+d, …, j+n*d}, with n = div(k – j, d), if j, d, and k are of type Integer.
- j : d : k is the Real vector {j, j+d, …, j+n*d}, with n = floor((k-j)/d), if j, d, or k are of type Real. In order to avoid rounding issues for the length it is recommended to use {j+d*i for i in 0:n} or linspace(j, k, n+1) – if the number of elements are known.
- j : d : k is a Real or Integer vector with zero elements, if d > 0 and j > k or if d < 0 and j < k.
- false : true is the Boolean vector {false, true}.
- j:j is {j} if j is Real, Integer, Boolean, or enumeration type.
- E.ei : E.ej is the enumeration type vector { E.ei, … E.ej} where E.ej> E.ei, and ei and ej belong to some enumeration type E=enumeration(…ei,…ej,…).
[Examples:
Real v1[5] = 2.7 : 6.8;
Real v2[5] = {2.7, 3.7, 4.7, 5.7, 6.7}; // = same as v1
Boolean b1[2] = false:true;
Colors = enumeration (red,blue,green);
Colors ec[3] = Colors.red : Colors.green;
]
Array Indexing¶
The array indexing operator name[…] is used to access array elements for retrieval of their values or for updating these values. An indexing operation is subject to upper and lower array dimension index bounds (). [An indexing operation is assumed to take constant time, i.e., largely independent of the size of the array.] The indexing operator takes two or more operands, where the first operand is the array to be indexed and the rest of the operands are index expressions:
arrayname[indexexpr1, indexexpr2, …]
A colon is used to denote all indices of one dimension. 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. If the number of index arguments is smaller than the number of dimensions of the array, the trailing indices will use “:”.
It is also possible to use the array access operator to assign to element/elements of an array in algorithm sections. If the index is an array the assignments take place in the order given by the index array. For assignments to arrays and elements of arrays, the entire right-hand side and the index on the left-hand side are evaluated before any element is assigned a new value.
[Examples:
a[:, j] !\emph{is a vector of the j-th column of a,}!
a[j] !\emph{is a vector of the j-th row of a:}! a[j, :]
a[j : k] is {[a[j], a[j+1], ... , a[k]}
a[:,j : k] is [a[:,j], a[:,j+1], ... , a[:,k]],
v[2:2:8] = v[ {2,4,6,8} ] .
v[{j,k}]:={2,3}; // Same as v[j]:=2; v[k]:=3;
v[{1,1}]:={2,3}; // Same as v[1]:=3;
if x is a vector, x[1] is a scalar, but the slice x[1:5] is a vector (a vector-valued or colon index expression causes a vector to be returned).
]
[Examples given the declaration x[n,m], v[k], z[i,j,p]:
index.
Expression # dimensions Type of value x[1, 1] 0 Scalar x[:, 1] 1 n – Vector x[1, :] or x[1] 1 m – Vector v[1:p] 1 p – Vector x[1:p, :] 2 p x m – Matrix x[1:1, :] 2 1 x m - “row” matrix x[{1, 3, 5}, :] 2 3 x m – Matrix x[: , v] 2 n x k – Matrix z[: , 3, :] 2 i x p – Matrix x[scalar([1]), :] 1 m – Vector x[vector([1]), :] 2 1 x m - “row” matrix
]
Indexing with Boolean or Enumeration Values¶
Arrays can be indexed using values of enumeration types or the Boolean type, not only by integers. The type of the index should correspond to the type used for declaring the dimension of the array.
[Example:
type ShirtSizes = enumeration(small, medium, large, xlarge);
Real[ShirtSizes] w;
Real[Boolean] b2;
algorithm
w[ShirtSizes.large] := 2.28; // Assign a value to an element of w
b2[true] := 10.0;
b2[ShirtSizes.medium] := 4; // Error, b2 was declared with Boolean dimension
w[1] := 3; // Error, w was declared with ShirtSizes dimension
]
Indexing with end¶
The expression end may only appear inside array subscripts, and if used in the i:th subscript of an array expression A it is equivalent to size(A,i) provided indices to A are a subtype of Integer. If used inside nested array subscripts it refers to the most closely nested array.
[Examples:
A[end -1,end] is A[size(A,1)-1,size(A,2)]
A[v[end ],end] is A[v[size(v,1)],size(A,2)] // !\emph{since the first}! end !\emph{is referring to end of v.}!
]
Scalar, Vector, Matrix, and Array Operator Functions¶
The mathematical operations defined on scalars, vectors, and matrices are the subject of linear algebra.
In all contexts that require an expression which is a subtype of Real, an expression which is a subtype of Integer can also be used; the Integer expression is automatically converted to Real.
The term numeric or numeric class is used below for a subtype of the Real or Integer type classes.
Equality and Assignment¶
Equality a=b and assignment a:=b of scalars, vectors, matrices, and arrays is defined element-wise and require both objects to have the same number of dimensions and corresponding dimension sizes. The operands need to be type equivalent. This is legal for the simple types and all types satisfying the requirements for a record, and is in the latter case applied to each component-element of the records.
Type of a | Type of b | Result of a = b | Operation (j=1:n, k=1:m) |
---|---|---|---|
Scalar | Scalar | Scalar | a = b |
Vector[n] | Vector[n] | Vector[n] | a[j] = b[j] |
Matrix[n, m] | Matrix[n, m] | Matrix[n, m] | a[j, k] = b[j, k] |
Array[n, m, …] | Array[n, m, …] | Array[n, m, …] | a[j, k, …] = b[j, k, …] |
Array Element-wise Addition, Subtraction, and String Concatenation¶
Addition a+b and subtraction a-b of numeric scalars, vectors, matrices, and arrays is defined element-wise and require size(a)=size(b) and a numeric type for a and b. Unary plus and minus are defined element-wise. Addition a+b of string scalars, vectors, matrices, and arrays is defined as element-wise string concatenation of corresponding elements from a and b, and require size(a)=size(b).
Type of a | Type of b | Result of a +/- b | Operation c := a +/- b (j=1:n, k=1:m) |
---|---|---|---|
Scalar | Scalar | Scalar | c := a +/- b |
Vector[n] | Vector[n] | Vector[n] | c[j] := a[j] +/- b[j] |
Matrix[n, m] | Matrix[n, m] | Matrix[n, m] | c[j, k] := a[j, k] +/- b[j, k] |
Array[n, m, …] | Array[n, m, …] | Array[n, m, …] | c [j, k, …] := a[j, k, …] +/- b[j, k, …] |
Element-wise addition a.+b and subtraction a.-b of numeric scalars, vectors, matrices or arrays a and b requires a numeric type class for a and b and either size(a) = size(b) or scalar a or scalar b. Element-wise addition a.+b of string scalars, vectors, matrices, and arrays is defined as element-wise string concatenation of corresponding elements from a and b, and require either size(a) = size(b) or scalar a or scalar b.
concatenation.
Type of a Type of b Result of a .+/.- b Operation c := a .+/.- b (j=1:n, k=1:m) Scalar Scalar Scalar c := a +/- b Scalar Array[n, m, …] Array[n, m, …] c[j, k, …] := a +/- b[j, k, …] Array[n, m, …] Scalar Array[n, m, …] c[j, k, …] := a[j, k, …] +/- b Array[n, m, …] Array[n, m, …] Array[n, m, …] c [j, k, …] := a[j, k, …] +/- b[j, k, …]
operators give the same results.
Type of a Result of +/- a Operation c := +/- a (j=1:n, k=1:m) Scalar Scalar c := +/- a Array[n, m, …] Array[n, m, …] c[j, k, …] := +/-a[j, k, …]
Array Element-wise Multiplication¶
Scalar multiplication s*a or a*s with numeric scalar s and numeric scalar, vector, matrix or array a is defined element-wise:
Type of s | Type of a | Type of s* a and a*s | Operation c := s*a or c := a*s (j=1:n, k=1:m) |
---|---|---|---|
Scalar | Scalar | Scalar | c := s * a |
Scalar | Vector [n] | Vector [n] | c[j] := s* a[j] |
Scalar | Matrix [n, m] | Matrix [n, m] | c[j, k] := s* a[j, k] |
Scalar | Array[n, m, …] | Array [n, m, …] | c[j, k, …] := s*a[j, k, …] |
[tab:product] |
Element-wise multiplication a.*b of numeric scalars, vectors, matrices or arrays a and b requires a numeric type class for a and b and either size(a) = size(b) or scalar a or scalar b.
Type of a | Type of b | Type of a .* b | Operation c:=a .* b (j=1:n, k=1:m) |
---|---|---|---|
Scalar | Scalar | Scalar | c := a * b |
Scalar | Array[n, m, …] | Array[n, m, …] | c[j, k, …] := a* b[j, k, …] |
Array[n, m, …] | Scalar | Array[n, m, …] | c[j, k, …] := a[j, k, …]* b |
Array[n, m, …] | Array[n, m, …] | Array [n, m, …] | c[j, k, …] := a[j, k, …]* b[j, k, …] |
Matrix and Vector Multiplication of Numeric Arrays¶
Multiplication a*b of numeric vectors and matrices is defined only for the following combinations:
elements.
Type of a Type of b Type of a* b Operation c := a*b Vector [n] Vector [n] Scalar c := (a[k]*b[k]), k=1:n Vector [n] Matrix [n, m] Vector [m] c[j] := (a[k]*b[k, j]), j=1:m, k=1:n Matrix [n, m] Vector [m] Vector [n] c[j] := (a[j, k]*b[k]) Matrix [n, m] Matrix [m, p] Matrix [n, p] c[i, j] = (a[i, k]*b[k, j]), i=1:n, k=1:m, j=1:p
[Example:
Real A[3,3], x[3], b[3], v[3];
A*x = b;
x*A = b; // same as transpose([x])*A*b
[v]*transpose([v]) // outer product
v*A*v // scalar
tranpose([v])*A*v // vector with one element
]
Division of Scalars or Numeric Arrays by Numeric Scalars¶
Division a/s of numeric scalars, vectors, matrices, or arrays a and numeric scalars s is defined element-wise. The result is always of real type. In order to get integer division with truncation use the function div.
Type of a | Type of s | Result of a / s | Operation c := a / s (j=1:n, k=1:m) |
---|---|---|---|
Scalar | Scalar | Scalar | c := a / s |
Vector[n] | Scalar | Vector[n] | c[k] := a[k] / s |
Matrix[n, m] | Scalar | Matrix[n, m] | c[j, k] := a[j, k] / s |
Array[n, m, …] | Scalar | Array[n, m, …] | c[j, k, …] := a[j, k, …] / s |
Array Element-wise Division¶
Element-wise division a./b of numeric scalars, vectors, matrices or arrays a and b requires a numeric type class for a and b and either size(a) = size(b) or scalar a or scalar b. The result is always of real type. In order to get integer division with truncation use the function div.
Type of a | Type of b | Type of a ./ b | Operation c:=a ./ b (j=1:n, k=1:m) |
---|---|---|---|
Scalar | Scalar | Scalar | c := a / b |
Scalar | Array[n, m, …] | Array[n, m, …] | c[j, k, …] := a / b[j, k, …] |
Array[n, m, …] | Scalar | Array[n, m, …] | c[j, k, …] := a[j, k, …] / b |
Array[n, m, …] | Array[n, m, …] | Array [n, m, …] | c[j, k, …] := a[j, k, …] / b[j, k, …] |
[Element-wise division by scalar (./) and division by scalar (/) are identical: a./s = a/s.
Example:
2./[1,2;3,4] // error, since 2.0/[1,2;3,4]
2 ./[1,2;3,4] // fine, element-wise division
This is a consequence of the parsing rules, since 2. is a lexical unit. Using a space after the literal solves the problem.]
Exponentiation of Scalars of Numeric Elements¶
Exponentiation “a^b” is defined as pow(double a,double b) in the ANSI C library if both “a” and “b” are Real scalars. A Real scalar value is returned. If “a” or “b” are Integer scalars, they are automatically promoted to “Real”. Consequences of exceptional situations, such as (a==0.0 and b<=0.0, a<0 and b is not an integer) or overflow are undefined
Element-wise exponentiation a.^b of numeric scalars, vectors, matrices, or arrays a and b requires a numeric type class for a and b and either size(a) = size(b) or scalar a or scalar b.
Type of a | Type of b | Type of a .^ b | Operation c:=a .^ b (j=1:n, k=1:m) |
---|---|---|---|
Scalar | Scalar | Scalar | c := a ^ b |
Scalar | Array[n, m, …] | Array[n, m, …] | c[j, k, …] := a ^ b[j, k, …] |
Array[n, m, …] | Scalar | Array[n, m, …] | c[j, k, …] := a[j, k, …] ^ b |
Array[n, m, …] | Array[n, m, …] | Array [n, m, …] | c[j, k, …] := a[j, k, …] ^ b[j, k, …] |
[Example:
2.^[1,2;3,4] // error, since 2.0^[1,2;3,4]
2 .^[1,2;3,4] // fine, element wise exponentiation
This is a consequence of the parsing rules, i.e. since 2. could be a lexical unit it seen as a lexical unit; using a space after literals solves the problem.]
Scalar Exponentiation of Square Matrices of Numeric Elements¶
Exponentiation a^s is defined if a is a square numeric matrix and s is a scalar as a subtype of Integer with s>=0. The exponentiation is done by repeated multiplication
(e.g.:
a^3 = a*a*a; a^0 = identity(size(a,1));
assert(size(a,1)==size(a,2),"Matrix must be square");
a^1 = a;
[Non-Integer exponents are forbidden, because this would require computing the eigenvalues and eigenvectors of “a” and this is no longer an elementary operation].
Slice Operation¶
The following holds for slice operations:
- If a is an array containing scalar components and m is a component of
those components, the expression a.m is interpreted as a slice
operation. It returns the array of components
{a{[1].m, ...}
. - If m is also an array component, the slice operation is valid only if
size(a[1].m)=size(a[2].m)=...
- The slicing operation can be combined with indexing, e.g.
a.m[1]
. It returns the array of components{a[1].m[1], a[2].m[1], ...}
, and does not require thatsize(a[1].m)=size(a[2].m)
. The number of subscripts on m must not be greater than the number of array dimension for m (the number can be smaller, in which case the missing trailing indices are assumed to be “:”), and is only valid ifsize(a[1].m[...])=size(a[2].m[...])
..
[Example: The size-restriction on the operand is only applicable if the indexing on the second operand uses vectors or colon as in the example:
constant Integer m=3;
Modelica.Blocks.Continuous.LowpassButterworth tf[m](n=2:(m+1));
Real y[m];
Real y2,y3;
equation
// Extract the x1 slice even though different x1's have different lengths
y=tf.x1[1] ; // Legal, ={tf[1].x1[1], tf[2].x1[1],
... tf[m].x1[1]};
y2=sum(tf.x1[:]); // Illegal to extract all elements since they have
// different lengths. Does not satisfy:
// size(tf[1].x1[:])=size(tf[2].x1[:])=...=size(tf[m].x1[:])
y3=sum(tf.x1[1:2]); // Legal.
// Since x1 has at least 2 elements in all tf, and
// size(tf[1].x1[1:2])=size(tf[2].x1[1:2])=...=size(tf[m].x1[1:2])={2}
In this example the different x1 vectors have different lengths, but it is still possible to perform some operations on them.]
Relational Operators¶
Relational operators <, <=, >, >=, ==, <>, are only defined for scalar operands of simple types, not for arrays, see
Boolean Operators¶
The operators, and and or take expressions of Boolean type, which are either scalars or arrays of matching dimensions. The operator not takes an expression of Boolean type, which is either scalar or an array. The result is the element-wise logical operation. For short-circuit evaluation of and and or see .
Vectorized Calls of Functions¶
See .
Empty Arrays¶
Arrays may have dimension sizes of 0. E.g.
Real x[0]; // an empty vector
Real A[0, 3], B[5, 0], C[0, 0]; // empty matrices
Empty matrices can be constructed with the fill function. E.g.
Real A[:,:] = fill(0.0, 0, 1); // a Real 0 x 1 matrix
Boolean B[:, :, :] = fill(false, 0, 1, 0); // a Boolean 0 x 1 x 0 matrix
It is not possible to access an element of an empty matrix, e.g.
v[j,k]
cannot be evaluated if v=[]
because the assertion fails
that the index must be bigger than one.
Size-requirements of operations, such as +, -, have also to be fulfilled if a dimension is zero. E.g.
Real[3,0] A, B;
Real[0,0] C;
A + B // fine, result is an empty matrix
A + C // error, sizes do not agree
Multiplication of two empty matrices results in a zero matrix of corresponding numeric type if the result matrix has no zero dimension sizes, i.e.,
Real[0,m]*Real[m,n] = Real[0,n] (empty matrix)
Real[m,n]*Real[n,0] = Real[m,0] (empty matrix)
Real[m,0]*Real[0,n] = fill(0.0, m, n) (non-empty matrix, with zero elements).
[Example:
Real u[p], x[n], y[q], A[n,n], B[n,p], C[q,n],
D[q,p];
der(x) = A*x + B*u
y = C*x + D*u
Assume n=0, p>0, q>0: Results in y = D*u
]