Glish also has multi-dimensional arrays. These arrays can be manipulated much like single dimension vectors. There are operations which permit ``slices'' and ``picks'' to be taken of arrays, and most of the functions and operators work on arrays as well as one dimensional vectors.

Typically,
an *array* is created using the `array`
function. This function takes an arbitrary number of arguments.
The first argument is the initial value for the new array. The rest of the
arguments are the length of the dimensions of the array. So, to create
a cube,

cube := array(0,4,4,4)creates a three dimensional array which is initialized to all zeros. Each of the three dimensions of the cube has a length of four. The array can also be initialized with a vector:

plane := array(1:4,4,3)This creates a matrix which has two dimensions. Each of the three columns are initialized to

one := array([3,5],3,3) two := array(1:25,3,4)

Arrays
are indexed using the the `[]` operator. This operator is used with one
subscript for each dimension of the array. This operator can be used to
access a single element, a contiguous section, or elements sprinkled throughout
the array.

Access to individual elements of arrays is accomplished much like indexing one dimensional vectors. The only difference is that instead of a single subscript, multiple subscripts are used, one for each dimension. For example,

x := array([3,5],3,3) for (i in 1:3 ) x[i,i] *:= 3a three by three matrix is assigned to

Multiple elements of arrays can be accessed as well. Often, however, the result will be another array instead of a vector. For example,

cube := array([3,5],3,3,3) for (i in 1:3 ) x[1:3,1:3,i] *:= ihere

Often, all of the elements along a dimension are not selected. In this case, the elements of interest must be listed explicitly (as was done above). When all of the elements along a certain dimension are desired, as was the case above, omitting a particular subscript implies all of the elements along that dimension. The example above could be rewritten:

cube := array([3,5],3,3,3) for (i in 1:3 ) x[,,i] *:= iThe omitted subscripts imply the whole dimension. Whole array operations are permitted much as they were for vector access (see § 3.6.3).

The ability to use subscripts to access either single elements or slices of an array covers most of the operations typically performed on arrays. Sometimes, however, this is not sufficient. Suppose, for example, one wanted to access the top left corner and bottom right corner of a matrix. With the available subscript operations presented above, the best that can be done is the following:

mat := array(1:16,4,4) tlc_brc := mat[[1,4],[1,4]]This unfortunately sets

tlc_brc := mat[array([1,4],2,2)]In this example, an array is used as the single index into the array. The rows of the subscript array indicate the elements of

Arrays which are used as an array index should not be of type `boolean`
See § 3.7.4 for a discussion of boolean
array indexes.

Along with ``picks'', sometimes specifying slices with multiple subscripts doesn't work either. The situation where this may happen is when writing a function which manipulates an array of any dimensionality. In this case, use of multiple subscripts breaks down. Indexing with a subscript array solves this problem for accessing individual elements of the array, and indexing with a record solves it for accessing slices of the array.

A record can be used to specify the elements of the slice. The `length`
(see § 9.3, page ) of the record must equal the dimensionality of
the array. The field values of the record are used irrespective of the
field label, and each of the field values acts as one of the subscripts
in the slice operation. For example,

cube := array(1:27,3,3,3) one := cube[,3,] two := cube[[a=1:3,b=3,c=[]]]here

index := [=] index[1] := [] index[2] := 3 index[3] := 1:3 three := cube[index]In the example,

As was indicated above,
this is mainly of use when the shape of the array is not
known ahead of time. Functions which deal with arrays of a non-predetermined shape
can use the system defined attribute `shape` which is defined for all arrays to
determine the shape of the array at runtime. For arrays, this `shape`
attribute always contains a vector which indicates the shape of the array. In
the following,

func s( ary ) { return ary::shape }the function

As was mentioned earlier, most functions and operators will accept arrays
or vectors as parameters. All of the
arithmetic, comparison, and logical operators operate element by element
on arrays as well as vectors. This is *not* matrix arithmetic but
rather element by element array arithmetic.

It is easy for users to write functions which operate on both vectors
and arrays as well. This is a result of the fact that arrays are
implemented as a vector plus a `shape` attribute. So an array
can easily be constructed from a vector, for example

vec := [3, 4, 9, 12, 8, 2, 10, 21, 5] vec::shape := [3, 3] v := vec[3, 3]Here a vector,

vec:: := [=]Now, an attempt to use array addressing, e.g.

The underlying vector can always be accessed for any array, and the
`shape` attribute need not be cleared. For arrays, whenever a single
non-`boolean` vector value is used as a subscript, the underlying vector
is accessed. In the following,

vec := 1:9 vec::shape := [3, 3] a := vec[3, 3] b := vec[len(vec)]both array accesses are valid, and

If
the underlying vector and the `shape` of an array, do not match
errors can result. If the length of the vector is greater than the
length implicit in the shape, then there is no problem, only a portion
of the underlying vector will be use. If, however, the vector length
is less than the length implied by the `shape`, runtime errors will
be reported when accesses are attempted past the end of the vector.
If the `array` function is used, these errors cannot happen.

As was discussed above, many of the operators and functions operate element by element on arrays as well as vectors. This is how boolean indices are used with arrays. In the following,

ary := array([1, -3, -4, 7, 2, -1, 10, -6, 3],3,3) ary[ary < 0] := 0

Arithmetic operations applied to arrays are identical to the corresponding vector operations. If an arithmetic operator is applied to two arrays, their lengths must be equal, and the result is the array generated by the element by element application of the operator. In the following,

ten := array(1:9,3,3) + array(9:1,3,3) ident := array(0,4,4) ident[array(1:4,4,2)] := 1 o := array(seq(1,4,.2),4,4) r := ident * o

Logical operators also perform element by element operations. For example,

_2b := array(F,3,3) the_question := _2b | ! _2bhere