3.4 Composite Data Types
3.4.1 Arrays
Arrays are specified with curly brackets, e.g., "{1, 2, 3}" is an array of int, while "{"x", "y", "z"}" is an array of string. The types are denoted "{int}" and "{string}" respectively. An array is an ordered list of tokens of any type, with the only constraint being that the elements all have the same type. If an array is given with mixed types, the expression evaluator will attempt to losslessly convert the elements to a common type. Thus, for example,
{1, 2.3}has value
{1.0, 2.3}Its type is {double}. The elements of the array can be given by expressions, as in the example "{2*pi, 3*pi}." Arrays can be nested; for example, "{{1, 2}, {3, 4, 5}}" is an array of arrays of integers. The elements of an array can be accessed as follows:
>> {1.0, 2.3}(1) 2.3which yields 2.3. Note that indexing begins at 0. Of course, if name is the name of a variable in scope whose value is an array, then its elements may be accessed similarly, as shown in this example:
>> x = {1.0, 2.3} {1.0, 2.3} >> x(0) 1.0Arithmetic operations on arrays are carried out element-by-element, as shown by the following examples:
>> {1, 2}*{2, 2} {2, 4} >> {1, 2}+{2, 2} {3, 4} >> {1, 2}-{2, 2} {-1, 0} >> {1, 2}^2 {1, 4} >> {1, 2}%{2, 2} {1, 0}
An array can be checked for equality with another array as follows:
>> {1, 2}=={2, 2} false >> {1, 2}!={2, 2} trueFor other comparisons of arrays, use the compare() function (see Table 5 on page 119). As with scalars, testing for equality using the == or != operators tests the values, independent of type. For example,
>> {1, 2}=={1.0, 2.0} trueYou can extract a subarray by invoking the subarray() method as follows:
>> {1, 2, 3, 4}.subarray(2, 2) {3, 4}The first argument is the starting index of the subarray, and the second argument is the length.
You can also extract non-contiguous elements from an array using the extract() method. This method has two forms. The first form takes a boolean array of the same length as the original array which indicates which elements to extract, as in the following example:
>> {"red","green","blue"}.extract({true,false,true}) {"red", "blue"}The second form takes an array of integers giving the indices to extract, as in the following example:
>> {"red","green","blue"}.extract({2,0,1,1}) {"blue", "red", "green", "green"}3.4.2 Matrices
In Ptolemy II, arrays are ordered sets of tokens. Ptolemy II also supports matrices, which are more specialized than arrays. They contain only certain primitive types, currently boolean, complex, double, fixedpoint, int, and long. Currently unsignedByte matrices are not supported. Matrices cannot contain arbitrary tokens, so they cannot, for example, contain matrices. They are intended for data intensive computations.
Matrices are specified with square brackets, using commas to separate row elements and semicolons to separate rows. E.g., "[1, 2, 3; 4, 5, 5+1]" gives a two by three integer matrix (2 rows and 3 columns). Note that an array or matrix element can be given by an expression. A row vector can be given as "[1, 2, 3]" and a column vector as "[1; 2; 3]". Some MATLAB-style array constructors are supported. For example, "[1:2:9]" gives an array of odd numbers from 1 to 9, and is equivalent to "[1, 3, 5, 7, 9]." Similarly, "[1:2:9; 2:2:10]" is equivalent to "[1, 3, 5, 7, 9; 2, 4, 6, 8, 10]." In the syntax "[p:q:r]", p is the first element, q is the step between elements, and r is an upper bound on the last element. That is, the matrix will not contain an element larger than r. If a matrix with mixed types is specified, then the elements will be converted to a common type, if possible. Thus, for example, "[1.0, 1]" is equivalent to "[1.0, 1.0]," but "[1.0, 1L]" is illegal (because there is no common type to which both elements can be converted losslessly).
Reference to elements of matrices have the form "matrix(n, m)" or "name(n, m)" where name is the name of a matrix variable in scope, n is the row index, and m is the column index. Index numbers start with zero, as in Java, not 1, as in MATLAB. For example,
>> [1, 2; 3, 4](0,0) 1 >> a = [1, 2; 3, 4] [1, 2; 3, 4] >> a(1,1) 4Matrix multiplication works as expected. For example, as seen in the expression evaluator (see figure 3.1),
>> [1, 2; 3, 4]*[2, 2; 2, 2] [6, 6; 14, 14]Of course, if the dimensions of the matrix don't match, then you will get an error message. To do element wise multiplication, use the multipyElements() function (see Table 6 on page 121). Matrix addition and subtraction are element wise, as expected, but the division operator is not supported. Element wise division can be accomplished with the divideElements() function, and multiplication by a matrix inverse can be accomplished using the inverse() function (see Table 6 on page 121). A matrix can be raised to an int or unsignedByte power, which is equivalent to multiplying it by itself some number of times. For instance,
>> [3, 0; 0, 3]^3 [27, 0; 0, 27]A matrix can also be multiplied or divided by a scalar, as follows:
>> [3, 0; 0, 3]*3 [9, 0; 0, 9]A matrix can be added to a scalar. It can also be subtracted from a scalar, or have a scalar subtracted from it. For instance,
>> 1-[3, 0; 0, 3] [-2, 1; 1, -2]A matrix can be checked for equality with another matrix as follows:
>> [3, 0; 0, 3]!=[3, 0; 0, 6] true >> [3, 0; 0, 3]==[3, 0; 0, 3] trueFor other comparisons of matrices, use the compare() function (see Table 5 on page 119). As with scalars, testing for equality using the == or != operators tests the values, independent of type. For example,
>> [1, 2]==[1.0, 2.0] trueTo get type-specific equality tests, use the equals() method, as in the following examples:
>> [1, 2].equals([1.0, 2.0]) false >> [1.0, 2.0].equals([1.0, 2.0]) true >>3.4.3 Records
A record token is a composite type containing named fields, where each field has a value. The value of each field can have a distinct type. Records are delimited by curly braces, with each field given a name. For example, "{a=1, b="foo"}" is a record with two fields, named "a" and "b", with values 1 (an integer) and "foo" (a string), respectively. The value of a field can be an arbitrary expression, and records can be nested (a field of a record token may be a record token).
Fields may be accessed using the period operator. For example,
{a=1,b=2}.ayields 1. You can optionally write this as if it were a method call:
{a=1,b=2}.a()The arithmetic operators +, -, *, /, and % can be applied to records. If the records do not have identical fields, then the operator is applied only to the fields that match, and the result contains only the fields that match. Thus, for example,
{foodCost=40, hotelCost=100} + {foodCost=20, taxiCost=20}yields the result
{foodCost=60}You can think of an operation as a set intersection, where the operation specifies how to merge the values of the intersecting fields. You can also form an intersection without applying an operation. In this case, using the intersect() function, you form a record that has only the common fields of two specified records, with the values taken from the first record. For example,
>> intersect({a=1, c=2}, {a=3, b=4}) {a=1}Records can be joined (think of a set union) without any operation being applied by using the merge() function. This function takes two arguments, both of which are record tokens. If the two record tokens have common fields, then the field value from the first record is used. For example,
merge({a=1, b=2}, {a=3, c=3})yields the result {a=1, b=2, c=3}.
Records can be compared, as in the following examples:
>> {a=1, b=2}!={a=1, b=2} false >> {a=1, b=2}!={a=1, c=2} trueNote that two records are equal only if they have the same field labels and the values match. As with scalars, the values match irrespective of type. For example:
>> {a=1, b=2}=={a=1.0, b=2.0+0.0i} trueThe order of the fields is irrelevant. Hence
>> {a=1, b=2}=={b=2, a=1} trueMoreover, record fields are reported in alphabetical order, irrespective of the order in which they are defined. For example,
>> {b=2, a=1} {a=1, b=2}To get type-specific equality tests, use the equals() method, as in the following examples:
>> {a=1, b=2}.equals({a=1.0, b=2.0+0.0i}) false >> {a=1, b=2}.equals({b=2, a=1}) true >>
![]() |
![]() |
![]() |