Arrays are heterogeneous data structures that generaize vectors to multiple indexes or dimensions. Instead of a single integer index, there are multiple indexes: An index is a vector of integers; the length of a valid index sequence is the rank or the number of dimensions of an array.

Kawa multi-dimensional arrays follows the by SRFI-25 specification, with additions from Racket’s math.array package and other sources.

An array whose rank is 1, and where the (single) lower bound is 0
is a sequence.
Furthermore, if such an array is simple (not created by `share-array`

)
it will be implemented using a `<vector>`

.
Uniform vectors and strings are also arrays in Kawa.

A rank-0 array has a single value. It is essentially a box for that value. Functions that require arrays may treat non-arrays as a rank-0 array containing that value.

An array of rank 2 is frequently called a *matrix*.

Note that Kawa arrays are distinct from Java (native) arrays. The latter is a simpler one-dimensional vector-like data structure, which is used to implement Kawa arrays and vectors.

Returns

`#t`

ifis an array, otherwise returns`obj`

`#f`

.

The *shape* of an array consists of bounds for each index.

The lower bound * b* and the upper bound

`e`

`(<= ``b`

`e`

)

. A valid index along the
dimension is an exact integer `i`

`(<= ``b`

`i`

)

and `(< ``i`

`e`

)

.
The length of the array along the dimension is the difference
`(- ``e`

`b`

)

.
The size of an array is the product of the lengths of its dimensions.
There is no separate data type for a shape. The canonical representation for a shape (a *canonical shape*) is a rank-2 array where the first index
is the dimension (zero-based), and the second index is 0 or 1:
Elements (* i* 0) and (

`i`

`i`

For convenience, the procedures that require a shape can accept a
* shape-specifier*, as if converted by the procedure

`->shape`

.
For example `(array-reshape ``array`

`shape`

)

is equivalent to
`(array-reshape ``array`

(->shape `shape`

))

.
Convert the shape specifier

to a canonical shape. The`specifier`

must be either a canonical shape, or vector with one element for each dimension, as described below. We use as examples a 2*3 array with lower bounds 0 and a 3*4 array with lower bounds 1.`specifier`

A vector of simple integers. Each integer

is an upper bound, with a zero lower bound. Equivalent to the range`e`

`[0 <:`

.]`e`

A specifier for the first examples is

`#(2 3)`

, and the second is not expressible.A vector of lists of length 2. The first element of each list is the lower bound, and the second is the upper bound.

Examples:

`#((0 2) (0 3))`

and`#((1 3) (1 4))`

.A vector of simple ranges, one for each dimension, all of who are bounded (finite), consist of integer values, and have a

of 1. Each range, which is usually written as`step`

`[`

, expresses the bounds of the corresponding dimension For the first example you can use<:`b`

]`e`

`[[0 <: 2] [0 <=: 2]]`

; for the second you can use`[[1 <: 3] [1 size: 4]]`

.A vector consisting of a mix of integers, length-2 lists, and ranges.

Examples:

`#(2 (0 3))`

and`['(1 3) [1 size: 4]]`

.A canonical shape: A rank-2 array

whose own shape is`S`

`[`

. For each dimension2]`r`

(where`k`

`(<=`

and0)`k`

`(<`

), the lower bound`k`

)`r`

is`b`

_{k}`(S`

, and the upper bound0)`k`

is`e`

_{k}`(S`

.1)`k`

Examples:

`#2a((0 2) (0 3))`

and`#2a((1 3) (1 4))`

.

Returns a shape. The sequence

... must consist of an even number of exact integers that are pairwise not decreasing. Each pair gives the lower and upper bound of a dimension. If the shape is used to specify the dimensions of an array and`bound`

... is the sequence`bound`

`b0`

...`e0`

`bk`

... of`ek`

pairs of bounds, then a valid index to the array is any sequence`n`

...`j0`

... of`jk`

exact integers where each`n`

satisfies`jk`

`(<=`

and`bk`

)`jk`

`(<`

.`jk`

)`ek`

The shape of a

-dimensional array is a`d`

* 2 array where the element at`d`

contains the lower bound for an index along dimension`k 0`

and the element at`k`

contains the corresponding upper bound, where`k 1`

satisfies`k`

`(<= 0`

and)`k`

`(<`

.`k`

)`d`

`(shape @`

is equivalent to:)`bounds`

`(array [2 (/ (length`

) 2)] @`bounds`

)`bounds`

Return the shape of

in the canonical (r 2) form. It is an error to attempt to modify the shape array.`array`

Returns the number of dimensions of

.`array`

(array-rank (make-array (shape 1 2 3 4)))Returns 2.

Procedure: `array-start`

`array`

`k`

Returns the lower bound (inclusive) for the index along dimension

. This is most commonly 0.`k`

Returns the upper bound for the index along dimension

. The bound is exclusive - i.e. the first integer higher than the last legal index.`k`

Return the total number of elements of

. This is the product of`array`

`(- (array-end`

for every valid`array`

) (array-start`k`

`array`

))`k`

.`k`

The type

`array`

matches all array values. The type`array`

, where`N`

is an integer matches array of rank`N`

. For example`N`

`array2`

matches rank-2 array - i.e. matrixes.You can optionally specify the element type

. This can be a primitive type. For example a`etype`

`array2[double]`

is a rank-2 array whose elements are`double`

values.

An array literal starts with `#`

followed by its rank,
followed by a tag that describes the underlying vector (by default `a`

),
optionally followed by information about its shape,
and finally followed by the cells, organized into dimensions using parentheses.

For example, `#2a((11 12 13) (21 22 23))`

is a rank-2 array (a matrix)
whose shape is `[2 3]`

or equivalently `[[0 <: 2] [0 <: 3]]`

.
It is pretty-printed as:

╔#2a:2:3═╗ ║11│12│13║ ╟──┼──┼──╢ ║21│22│23║ ╚══╧══╧══╝

`array-literal`

`::=`

`array-literal-header`

`datum`

`array-literal-header`

`::=`

**#**`rank`

`vectag`

`array-bound`

^{*}

`array-bound`

`::=`

[**@*** lower*]

**:**

`length`

**@**

`lower`

`vectag`

`::=`

**a**

| `uniform-tag`

The * vectag* specifies the type of the elements of the array.

Following the * vectag* you can optionally include information
about the shape: For each dimension you can optionally specify
the lower bounds (after the character

`"@"`

),
followed by the length of the dimension (after the character `":"`

).
The shape information is required if a lower bound is non-zero,
or any length is zero.
The * datum* contains the elements in a nested-list format:
a rank-1 array (i.e. vector) uses a single list,
a rank-2 array uses a list-of-lists, and so on.
The elements are in lexicographic order.

A uniform u32 array of rank 2 with index ranges 2..3 and 3..4:

#2u32@2@3((1 2) (2 3))

This syntax follows Common Lisp with Guile extensions. (Note that Guile prints rank-0 arrays with an extra set of parentheses. Kawa follows Common Lisp in not doing so.)

When an array is printed with the `write`

function,
the result is an `array-literal`

.
Printing with `display`

formats the array in a rectangular grid
using the `format-array`

procedure.
(Note that `format-array`

is only used when the output is in column 0,
because Kawa has very limited support for printing rectangles.)

Procedure: `format-array`

* value* [

`port`

`element-format`

Produce a nice “pretty” display for

, which is usually an array.`value`

If

is an output port, the formatted output is written into that port. Otherwise,`port`

must be a boolean (one of`port`

`#t`

or`#f`

). If the port is`#t`

, output is to the`(current-output-port)`

. If the port is`#f`

or no port is specified, the output is returned as a string. If the port is specified and is`#t`

or an output-port, the result of the`format-array`

procedure is unspecified. (This convention matches that of the`format`

procedure.)The top line includes an

`array-literal-header`

. The lower bound are only printed if non-zero. The dimension lengths are printed if there is room, or if one of them is zero.#|kawa:34|##|.....35|#`(! arr (array [[1 <=: 2] [1 <=: 3]]`

#|.....36|#`#2a((1 2) (3 4)) 9 #2a((3 4) (5 6))`

#|kawa:37|#`[42 43] #2a:1:3((8 7 6)) #2a((90 91) (100 101))))`

╔#2a@1:2@1:3════╤═════════╗ ║#2a═╗ │ 9│#2a═╗ ║ ║║1│2║ │ │║3│4║ ║ ║╟─┼─╢ │ │╟─┼─╢ ║ ║║3│4║ │ │║5│6║ ║ ║╚═╧═╝ │ │╚═╧═╝ ║ ╟───────┼───────┼─────────╢ ║╔#1a:2╗│#2a:1:3│╔#2a:2:2╗║ ║║42│43║│║8│7│6║│║ 90│ 91║║ ║╚══╧══╝│╚═╧═╧═╝│╟───┼───╢║ ║ │ │║100│101║║ ║ │ │╚═══╧═══╝║ ╚═══════╧═══════╧═════════╝`arr`

If

is specified, it is a format string used for format each non-array:`element-format`

#|kawa:38|#╔#2a@1:2@1:3══╤════════════════╤═══════════════╗ ║╔#2a:2:2══╗ │ 9.00│╔#2a:2:2══╗ ║ ║║1.00│2.00║ │ │║3.00│4.00║ ║ ║╟────┼────╢ │ │╟────┼────╢ ║ ║║3.00│4.00║ │ │║5.00│6.00║ ║ ║╚════╧════╝ │ │╚════╧════╝ ║ ╟─────────────┼────────────────┼───────────────╢ ║╔#1a:2╤═════╗│╔#2a:1:3══╤════╗│╔#2a:2:2══════╗║ ║║42.00│43.00║│║8.00│7.00│6.00║│║ 90.00│ 91.00║║ ║╚═════╧═════╝│╚════╧════╧════╝│╟──────┼──────╢║ ║ │ │║100.00│101.00║║ ║ │ │╚══════╧══════╝║ ╚═════════════╧════════════════╧═══════════════╝`(format-array arr "~4,2f")`

If the rank is more than 2, then each “layer” is printed separated by double lines.

#|kawa:42|#╔#3a:3:2:4══╗ ║ 1│ 2│ 3│ 4║ ╟──┼──┼──┼──╢ ║ 5│ 6│ 7│ 8║ ╠══╪══╪══╪══╣ ║ 9│10│11│12║ ╟──┼──┼──┼──╢ ║13│14│15│16║ ╠══╪══╪══╪══╣ ║17│18│19│20║ ╟──┼──┼──┼──╢ ║21│22│23│24║ ╚══╧══╧══╧══╝`(array-reshape [1 <=: 24] [3 2 4])`

See also `array-reshape`

Procedure: `array`

`shape`

`obj`

`...`

Returns a new array whose shape is given by

and the initial contents of the elements are`shape`

... in row major order. The array does not retain a reference to`obj`

.`shape`

Procedure: `make-array`

`shape`

`value...`

Returns a newly allocated array whose shape is given by

. If`shape`

is provided, then each element is initialized to it. If there is more than one`value`

, they are used in order, starting over when the`value`

s are exhausted. If there is no`value`

, the initial contents of each element is unspecified. (Actually, it is the`value`

`#!null`

.) The array does not retain a reference to.`shape`

#|kawa:16|#╔#2a:2:4╗ ║1│2│3│4║ ╟─┼─┼─┼─╢ ║5│1│2│3║ ╚═╧═╧═╧═╝`(make-array [2 4] 1 2 3 4 5)`

Compatibility:Guile has an incompatible`make-array`

procedure.

Procedure: `build-array`

`shape`

* getter* [

`setter`

Construct a “virtual array” of the given

, which uses no storage for the elements. Instead, elements are calculated on-demand by calling`shape`

, which takes a single argument, an index vector.`getter`

There is no caching or memoization.

#|kawa:1|##|....:2|#`(build-array [[10 <: 12] 3]`

#|....:3|#`(lambda (ind)`

#|....:4|#`(let ((x (ind 0)) (y (ind 1)))`

#2a@10:2:3 ║10│ 9│8║ ╟──┼──┼─╢ ║11│10│9║ ╚══╧══╧═╝`(- x y))))`

The resulting array is mutable if a

is provided. The`setter`

takes two arguments: An index vector, and the new value for the specified element. Below is a simple and space-efficient (but slow) implementation of sparse arrays: Most element have a default initial value, but you can override specific elements.`setter`

(define (make-sparse-array shape default-value) (let ((vals '())) ;; association list of (INDEX-VECTOR . VALUE) (build-array shape (lambda (I) (let ((v (assoc I vals))) (if v (cdr v) default-value))) (lambda (I newval) (let ((v (assoc I vals))) (if v (set-cdr! v newval) (set! vals (cons (cons I newval) vals))))))))

Return a new immutable array of the specified

where each element is the corresponding row-major index. Same as`shape`

`(array-reshape [0 <:`

where]`size`

)`shape`

is the`size`

`array-size`

of the resulting array.#|kawa:1|##2a@1:2@2:4 ║0│1│2│3║ ╟─┼─┼─┼─╢ ║4│5│6│7║ ╚═╧═╧═╧═╝`(index-array [[1 <: 3] [2 <: 6]])`

If you “call” an array as it it were a function,
it is equivalent to using `array-index-ref`

,
which is generalization of `array-ref`

.
For example, given a rank-2 array * arr* with integer indexes

`i`

`j`

`arr`

`[``i`

`j`

]

.
(`arr`

`i`

) (array-index-ref`j`

`arr`

`i`

) (array-ref`j`

`arr`

`i`

) (array-ref`j`

[`arr`

`i`

])`j`

Using function-call notation or `array-index-ref`

(but not plain `array-ref`

) you can do generalized APL-style
slicing and indirect indexing.
See under `array-index-ref`

for examples.

Procedure: `array-ref`

`array`

`k`

`...`

Procedure: `array-ref`

`array`

`index`

Returns the contents of the element of

at index`array`

.... The sequence`k`

... must be a valid index to`k`

. In the second form,`array`

must be either a vector (a 0-based 1-dimensional array) containing`index`

....`k`

(array-ref (array [2 3] 'uno 'dos 'tres 'cuatro 'cinco 'seis) 1 0)Returns

`cuatro`

.(let ((a (array (shape 4 7 1 2) 3 1 4))) (list (array-ref a 4 1) (array-ref a (vector 5 1)) (array-ref a (array (shape 0 2) 6 1))))Returns

`(3 1 4)`

.

Procedure: `array-index-ref`

`array`

`index`

`...`

Generalized APL-style array indexing, where each

can be either an array or an integer.`index`

If each

is an integer, then the result is the same as`index`

`array-ref`

.Otherwise, the result is an immutable array whose rank is the sum of the ranks of each

. An integer is treated as rank-0 array.`index`

If

is the result of`marr`

`(array-index-ref`

then:`arr`

`M`

_{1}...)`M`

_{2}(`marr`

`i`

_{11}...`i`

_{12}`i`

_{21}...)`i`

_{22}is defined as:

((`arr`

`M`

_{1}`i`

_{11}...) (`i`

_{12}`M`

_{2}`i`

_{21}...) ...)`i`

_{22}Each

gets as many indexes as its rank. If`M`

_{k}is an integer, then it we use it directly without any indexing.`M`

_{k}Here are some examples, starting with simple indexing.

#|kawa:1|##|.....2|#`(define arr (array #2a((1 4) (0 4))`

#|kawa:3|#`10 11 12 13 20 21 22 23 30 31 32 33))`

╔#2a@1:3:4══╗ ║10│11│12│13║ ╟──┼──┼──┼──╢ ║20│21│22│23║ ╟──┼──┼──┼──╢ ║30│31│32│33║ ╚══╧══╧══╧══╝ #|kawa:4|#`arr`

23`(arr 2 3)`

If one index is a vector and the rest are scalar integers, then the result is a vector:

#|kawa:5|##(23 21)`(arr 2 [3 1])`

You can select a “sub-matrix” when all indexes are vectors:

#|kawa:6|#╔#2a:2:3═╗ ║23│21│23║ ╟──┼──┼──╢ ║13│11│13║ ╚══╧══╧══╝`(arr [2 1] [3 1 3])`

Using ranges for index vectors selects a rectangular sub-matrix.

#|kawa:7|#╔#2a:2:3═╗ ║11│12│13║ ╟──┼──┼──╢ ║21│22│23║ ╚══╧══╧══╝`(arr [1 <: 3] [1 <: 4])`

You can add new dimensions:

#|kawa:8|##3a╤══╗ ║23│21║ ╟──┼──╢ ║23│22║ ╠══╪══╣ ║13│11║ ╟──┼──╢ ║13│12║ ╚══╧══╝`(arr [2 1] #2a((3 1) (3 2)))`

The pseudo-range

`[<:]`

can be used to select all the indexes along a dimension. To select row 2 (1-origin):#|kawa:9|##(20 21 22 23)`(arr 2 [<:])`

To reverse the order use

`[>:]`

:#|kawa:10|##(23 22 21 20)`(arr 2 [>:])`

To select column 3:

#|kawa:11|##(13 23 33)`(arr [<:] 3)`

If you actually want a column matrix (i.e. with shape

`[3 1]`

you can place the index in a single-element vector:#|kawa:12|##2a╗ ║13║ ╟──╢ ║23║ ╟──╢ ║33║ ╚══╝`(arr [<:] [3])`

To expand that column to 5 colums you can repeat the column index:

#|kawa:13|##(3 3 3 3 3) #|kawa:14|#`[3 by: 0 size: 5]`

╔#2a:3:5═╤══╤══╗ ║13│13│13│13│13║ ╟──┼──┼──┼──┼──╢ ║23│23│23│23│23║ ╟──┼──┼──┼──┼──╢ ║33│33│33│33│33║ ╚══╧══╧══╧══╧══╝`(arr [<:] [3 by: 0 size: 5])`

You can use `set!`

to modify one or multiple elements.
To modify a single element:

(set! (`arr`

...)`index`

)`new-value`

is equivalent to

(array-set!`arr`

...`index`

)`new-value`

You can set a slice (or all of the elements). In that case:

(set! (`arr`

...)`index`

)`new-array`

is equivalent to:

(array-copy! (array-index-share`arr`

...)`index`

)`new-array`

Procedure: `array-set!`

`array`

`k`

`...`

`obj`

Procedure: `array-set!`

`array`

`index`

`obj`

Stores

in the element of`obj`

at index`array`

.... Returns the void value. The sequence`k`

... must be a valid index to`k`

. In the second form,`array`

must be either a vector or a 0-based 1-dimensional array containing`index`

....`k`

(let ((a (make-array (shape 4 5 4 5 4 5)))) (array-set! a 4 4 4 "huuhkaja") (array-ref a 4 4 4))Returns

`"huuhkaja"`

.

Compatibility:SRFI-47, Guile and Scheme-48 have`array-set!`

with a different argument order.

Procedure: `array-copy!`

`dst`

`src`

Compatibility:Guile has a`array-copy!`

with the reversed argument order.

Procedure: `array-fill!`

`array`

`value`

Set all the values

to`array`

.`value`

A view or transform of an array is an array * a*
whose elements come from some other array

`a`_{1}

`T`

`a`_{2}

`a`_{1}

`(array-ref ``a`_{2}

`indexes`

)

is `(array-ref ``a`_{1}

(`T`

`indexes`

))

.
Modifying `a`_{2}

`a`_{1}

`a`_{1}

`a`_{2}

`a`_{2}

`a`_{1}

Procedure: `array-transform`

`array`

`shape`

`transform`

This is a general mechanism for creating a view. The result is a new array with the given

. Accessing this new array is implemented by calling the`shape`

function on the index vector, which must return a new index vector valid for indexing the original`transform`

. Here is an example (using the same`array`

`arr`

as in the`array-index-ref`

example):#|kawa:1|##|.....2|#`(define arr (array #2a((1 4) (0 4))`

#|kawa:14|#`10 11 12 13 20 21 22 23 30 31 32 33))`

#|.....15|#`(array-transform arr #2a((0 3) (1 3) (0 2))`

#|.....16|#`(lambda (ix) (let ((i (ix 0)) (j (ix 1)) (k (ix 2)))`

#|.....17|#`[(+ i 1)`

#3a:3@1:2:2 ║10│11║ ╟──┼──╢ ║12│13║ ╠══╪══╣ ║20│21║ ╟──┼──╢ ║22│23║ ╠══╪══╣ ║30│31║ ╟──┼──╢ ║32│33║ ╚══╧══╝`(+ (* 2 (- j 1)) k)])))`

The

`array-transform`

is generalization of`share-array`

, in that it does not require theto be affine. Also note the different calling conversions for the`transform`

:`tranform`

`array-transform`

takes a single argument (a vector of indexes), and returns a single result (a vector of indexes);`share-array`

takes one argument for each index, and returns one value for each index. The difference is historical.

Procedure: `array-index-share`

`array`

`index`

`...`

This does the same generalized APL-style indexing as

`array-index-ref`

. However, the resulting array is a modifiable view into the argument.`array`

Procedure: `array-reshape`

`array`

`shape`

Creates a new array

of the given`narray`

, such that`shape`

`(array->vector`

and)`array`

`(array->vector`

are equivalent. I.e. the)`narray`

’th element in row-major-order of`i`

is the`narray`

’th element in row-major-order of`i`

. Hence`array`

`(array-size`

(as specied from the)`narray`

) must be equal to`shape`

`(array-size`

. The resulting)`array`

is a view such that modifying`narray`

also modifies`array`

and vice versa.`narray`

Procedure: `share-array`

`array`

`shape`

`proc`

Returns a new array of

shape that shares elements of`shape`

through`array`

. The procedure`proc`

must implement an affine function that returns indices of`proc`

when given indices of the array returned by`array`

`share-array`

. The array does not retain a reference to.`shape`

(define i_4 (let* ((i (make-array (shape 0 4 0 4) 0)) (d (share-array i (shape 0 4) (lambda (k) (values k k))))) (do ((k 0 (+ k 1))) ((= k 4)) (array-set! d k 1)) i))Note: the affinity requirement for

means that each value must be a sum of multiples of the arguments passed to`proc`

, plus a constant.`proc`

Implementation note: arrays have to maintain an internal index mapping from indices

...`k1`

to a single index into a backing vector; the composition of this mapping and`kd`

can be recognised as`proc`

`(`

by setting each index in turn to 1 and others to 0, and all to 0 for the constant term; the composition can then be compiled away, together with any complexity that the user introduced in their procedure.(*`+ n0`

`n1`

) ... (*`k1`

`nd`

))`kd`

Here is an example where the

is a uniform vector:`array`

(share-array (f64vector 1.0 2.0 3.0 4.0 5.0 6.0) (shape 0 2 0 3) (lambda (i j) (+ (* 2 i) j))) ⇒ #2f64((1.0 2.0 3.0) (4.0 5.0 6.0))

Procedure: `array-flatten`

`array`

Procedure: `array->vector`

`array`

Return a vector consisting of the elements of the

in row-major-order.`array`

The result of

`array-flatten`

is fresh (mutable) copy, not a view. The result of`array->vector`

is a view: Ifis mutable, then modifying`array`

changes the flattened result and vice versa.`array`

If

is “simple”,`array`

`array->vector`

returns the original vector. Specifically, ifis a vector then:`vec`

(eq?(array->vector (array-reshape`vec`

`vec`

)))`shape`