gauche.array
- Arrays ¶This module provides multi-dimensional array data type and operations. The primitive API follows SRFI-25. Besides a generic SRFI-25 array that can store any Scheme objects, this module also provides array classes that stores numeric objects efficiently, backed up by homogeneous numeric vectors (see Uniform vectors). An external representation of arrays, using SRFI-10 mechanism, is also provided.
Each element of an N-dimensional array can be accessed
by N integer indices,
[ i_0 i_1 … i_N-1 ]
.
An array has associated shape that knows lower-bound s_k and
upper-bound e_k of index of each dimension, where
s_k <= e_k, and the index i_k must satisfy
s_k <= i_k < e_k.
(Note: it is allowed to have s_k == e_k, but such array can’t
store any data. It is also allowed to have zero-dimensional array,
that can store a single data.).
The shape itself is a [ D x 2 ] array, where D is the
dimension of the array which the shape represents.
You can pass index(es) to array access primitives in a few ways; each index can be passed as individual argument, or can be ’packed’ in a vector or one-dimensional array. In the latter case, such a vector or an array is called an "index object". Using a vector is efficient in Gauche when you iterate over the elements by changing the vector elements, for it won’t involve memory allocation.
Arrays can be compared by the equal?
procedure.
Equal?
returns #t
if two arrays have the same
shape and their corresponding elements are the same
in the sense of equal?
.
Internally, an array consists of a backing storage and a mapping procedure. A backing storage is an object of aggregate type that can be accessed by an integer index. A mapping procedure takes multi-dimensional indices (or index object) and returns a scalar index into the backing storage.
{gauche.array
}
An abstract base class of array types, that implements generic operations
on the array. To create an array instance,
you should use one of the following concrete array classes.
{gauche.array
}
Concrete array classes. The <array>
class implements SRFI-25
compatible array, i.e. an array that can store any Scheme objects.
The <u8array>
class through <f64array>
classes uses
a <u8vector>
through <f64vector>
as a backing storage,
and can only store a limited range of integers or inexact real numbers,
but they are space efficient.
#,(<array> shape obj …)
¶An array is written out in this format. (Substitute <array>
for
<u8array>
if the array is <u8array>
, etc.)
shape is a list
of even number of integers, and each 2n-th integer
and 2n+1-th integer specifies the
inclusive lower-bound and exclusive upper-bound of n-th dimension,
respectively. The following obj … are the values in the array
listed in row-major order.
When read back, this syntax is read as an array with the same shape
and content, so it is equal?
to the original array.
; an array such that: ; 8 3 4 ; 1 5 9 ; 6 7 2 #,(<array> (0 3 0 3) 8 3 4 1 5 9 6 7 2) ; a 4x4 identity matrix #,(<array> (0 4 0 4) 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1)
[SRFI-25]{gauche.array
}
Returns #t
if obj is an array, #f
otherwise.
It is equivalent to (is-a? obj <array-base>)
.
[SRFI-25]{gauche.array
}
Creates an array of shape shape.
Shape must be a [ D x 2 ] array, and for each k
(0 <= k < D), the [ k 0 ] element must be less than or
equal to the [ k 1] element.
If init is given, all the elements are initialized by it.
Otherwise, the initial value of the elements are undefined.
(make-array (shape 0 2 0 2 0 2) 5) ⇒ #,(<array> (0 2 0 2 0 2) 5 5 5 5 5 5 5 5)
{gauche.array
}
Like make-array
, but creates and returns an uniform numeric array.
{gauche.array
}
Returns a copy of array, with the same class, shape and
content.
[SRFI-25]{gauche.array
}
Takes even number of exact integer arguments, and returns
a two-dimensional array that is suitable for representing the shape
of an array.
(shape 0 2 1 3 3 5) ⇒ #,(<array> (0 3 0 2) 0 2 1 3 3 5) (shape) ⇒ #,(<array> (0 0 0 2))
[SRFI-25]{gauche.array
}
Creates an array of shape shape, initializing its elements by
init ….
(array (shape 0 2 1 3) 'a 'b 'c 'd) ⇒ #,(<array> (0 2 1 3) a b c d)
{gauche.array
}
Like array
, but creates and returns an uniform numeric array
initialized by init ….
(u8array (shape 0 2 0 2) 1 2 3 4) ⇒ #,(<u8array> (0 2 0 2) 1 2 3 4)
[SRFI-25]{gauche.array
}
Returns the number of dimensions of an array array.
(array-rank (make-array (shape 0 2 0 2 0 2))) ⇒ 3 (array-rank (make-array (shape))) ⇒ 0
{gauche.array
}
Returns a shape array of array.
[SRFI-25+]{gauche.array
}
Array-start
returns the inclusive lower bound of index of
dim-th dimension of an array array.
Array-end
returns the exclusive upper bound.
And array-length
returns the difference between two.
Array-start
and array-end
are defined in SRFI-25.
(define a (make-array (shape 1 5 0 2))) (array-start a 0) ⇒ 1 (array-end a 0) ⇒ 5 (array-length a 0) ⇒ 4 (array-start a 1) ⇒ 0 (array-end a 1) ⇒ 2 (array-length a 1) ⇒ 2
{gauche.array
}
Returns the total number of elements in the array array.
(array-size (make-array (shape 5 9 1 3))) ⇒ 8 (array-size (make-array (shape))) ⇒ 1 (array-size (make-array (shape 0 0 0 2))) ⇒ 0
[SRFI-25]{gauche.array
}
Gets the element of array array
. In the first form,
the element is specified by indices k ….
In the second form, the element is specified by an index object
index, which must be a vector or an one-dimensional array.
[SRFI-25]{gauche.array
}
Sets the element of array array to value. In the first form,
the element is specified by indices k ….
In the second form, the element is specified by an index object
index, which must be a vector or an one-dimensional array.
[SRFI-25]{gauche.array
}
Creates and returns a new array of shape shape, that shares
the backing storage with the given array array.
The procedure proc maps the indices of the new array to
the indices to the original array, i.e. proc must be a n-ary
procedure that returns m values, where n is the dimension
of the new array and m is the one of the original array.
Furthermore, proc must be an affine function; each mapping
has to be a linear combination of input arguments plus optional constant.
(Share-array
optimizes the mapping function based on the affinity
assumption, so proc won’t be called every time the new array
is accessed).
{gauche.array
}
Calls proc with every index of array.
If no index argument is provided, proc is called
as (proc i j k …)
, in which
(i,j,k,…) walks over the index.
It begins from the least index value of each dimension, and
latter dimension is incremented faster.
gosh> (define a (array (shape 0 2 0 2) 1 2 3 4)) a gosh> a #,(<array> (0 2 0 2) 1 2 3 4) gosh> (array-for-each-index a (^(i j) (print i","j))) 0,0 0,1 1,0 1,1
This form of passing indexes is simple but not very efficient, though. For better performance, you can pass an index object to an optional argument index, which is modified for each index and passed to proc. The index object must be mutable, and either a vector, an one-dimensional array, an s8vector, an s16vector or an s32vector. The length of the index object must match the rank of the array. Using index object is efficient since the loop won’t allocate. Don’t forget that the index object is destructively modified within the loop.
gosh> (array-for-each-index a (cut format #t "~s\n" <>) (vector 0 0)) #(0 0) #(0 1) #(1 0) #(1 1) gosh> (array-for-each-index a (cut format #t "~s\n" <>) (s8vector 0 0)) #s8(0 0) #s8(0 1) #s8(1 0) #s8(1 1)
The procedure returns an unspecified value.
{gauche.array
}
Calls proc with all possible indexes represented by the shape
shape.
The optional index argument works the same
way as array-for-each-index
. Returns an unspecified value.
gosh> (shape-for-each (shape 0 2 0 2) (^(i j) (print i","j))) 0,0 0,1 1,0 1,1
{gauche.array
}
Calls proc over each index represented by the shape shape,
and creates an array from the result of proc. The optional
index object can be used in the same way as array-for-each-index
.
The following example creates an identity matrix of the given shape:
(tabulate-array (shape 0 3 0 3) (^(i j) (if (= i j) 1 0))) ⇒ #,(<array> (0 3 0 3) 1 0 0 0 1 0 0 0 1)
{gauche.array
}
Calls proc over each index of the given array, and
modifies the array’s element by the returned value of proc.
The optional index object can be used in
the same way as array-for-each-index
.
The second form takes a shape; it must match
the array’s shape. It is redundant, but may allow some
optimization in future in case shape is a literal.
Returns an unspecified value.
{gauche.array
}
The arguments array0, array1, … must be arrays
with the same shape. For each set of corresponding elements of
the input arrays, proc is called, and a new array of the
same shape is created by the returned values.
The second form takes a shape argument, which must match the
shape of input array(s). It is redundant, but may allow some
optimization in future in case shape is a literal.
(array-map - (array (shape 0 2 0 2) 1 2 3 4)) ⇒ #,(<array> (0 2 0 2) -1 -2 -3 -4)
{gauche.array
}
Like array-map
, but the results of proc are stored by the
given array, whose shape must match the shape of input array(s).
Returns unspecified value.
{gauche.array
}
Returns a fresh vector or a fresh list of all elements in array.
(array->vector (tabulate-array (shape 1 3 1 4) (^(i j) (+ (* 10 i) j)))) ⇒ #(11 12 13 21 22 23)
{gauche.array
}
Concatenates arrays at the specified dimension. The sizes of the
specified dimension of two arrays must match, although the shapes
can be different. Arrays can be of any ranks, but two ranks must
match.
;; [a b] [a b] ;; [c d] (+) => [c d] ;; [e f] [e f] (array-concatenate (array (shape 0 2 0 2) 'a 'b 'c 'd) (array (shape 0 1 0 2) 'e 'f)) ⇒ #,(<array> (0 3 0 2) a b c d e f) ;; [a b] [e] [a b e] ;; [c d] (+) [f] => [c d f] (array-concatenate (array (shape 0 2 0 2) 'a 'b 'c 'd) (array (shape 0 2 0 1) 'e 'f) 1) ⇒ #,(<array> (0 2 0 3) a b e c d f) ;; The index range can differ, as far as the sizes match (array-concatenate (array (shape 0 2 0 2) 'a 'b 'c 'd) (array (shape 1 3 0 1) 'e 'f) 1) ⇒ #,(<array> (0 2 0 3) a b e c d f)
{gauche.array
}
The given array must have a rank greater than or equal to 2.
Transpose the array’s dim1-th dimension and
dim2-th dimension. The default is 0 and 1.
{gauche.array
}
The given array must have a rank greater than or equal to 2.
We regard the array as a matrix with dim1-th dimension
as rows and dim2-th dimension as columns, and returns
a fresh array whose content is filled by rotating
array 90 degree clockwise. The defaults of
dim1 and dim2 are 0 and 1, respectively.
;; [1 2 3] [4 1] ;; [4 5 6] => [5 2] ;; [6 3] (array-rotate-90 (array (shape 0 2 0 3) 1 2 3 4 5 6)) ⇒ #,(<array> (0 3 0 2) 4 1 5 2 6 3)
If array has a rank greater than 2, the array is treated as a matrix of subarrays.
{gauche.array
}
Flips the content of the array across the dimension-th dimension.
(default is 0). array-flip!
modifies the content of array
and return it. array-flip
doesn’t modify array but creates
a fresh array with the flipped content and returns it.
;; [1 2 3] => [4 5 6] ;; [4 5 6] [1 2 3] (array-flip (array (shape 0 2 0 3) 1 2 3 4 5 6)) ⇒ #,(<array> (0 2 0 3) 4 5 6 1 2 3) ;; [1 2 3] => [3 2 1] ;; [4 5 6] [6 5 4] (array-flip (array (shape 0 2 0 3) 1 2 3 4 5 6) 1) ⇒ #,(<array> (0 2 0 3) 3 2 1 6 5 4)
{gauche.array
}
Returns a fresh identity array of rank 2, with the given dimension.
You can pass one of array classes to class to make the result
the instance of the class; the default class is <array>
.
(identity-array 3) ⇒ #,(<array> (0 3 0 3) 1 0 0 0 1 0 0 0 1) (identity-array 3 <f32array>) ⇒ #,(<f32array> (0 3 0 3) 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0)
{gauche.array
}
Regards the array as a matrix, and returns its inverse matrix;
array must be 2-dimensional, and must have square shape. If
array doesn’t satisfy these conditions, an error is thrown.
If array isn’t a regular matrix, #f
is returned.
{gauche.array
}
Regards the array as a matrix, and calculates its determinant;
array must be 2-dimensional, and must have square shape. If
array doesn’t satisfy these conditions, an error is thrown.
determinant!
destructively modifies the given array during
calculation. It is faster than determinant
, which copies
array before calculation to preserve it.
{gauche.array
}
Arrays a and b must be rank 2. Regarding them
as matrices, multiply them together. The number of rows of a
and the number of columns of b must match.
;; [6 5] ;; [1 2 3] x [4 3] => [20 14] ;; [4 5 6] [2 1] [56 41] (array-mul (array (shape 0 2 0 3) 1 2 3 4 5 6) (array (shape 0 3 0 2) 6 5 4 3 2 1)) ⇒ #,(<array> (0 2 0 2) 20 14 56 41)
{gauche.array
}
Raises array to the power of pow; array must be
a square matrix, and pow must be a nonnegative exact integer.
{gauche.array
}
Inverse of array-mul
; array-div-left
returns a matrix M
such that (array-mul B M)
equals to A
, and array-div-right
returns
a matrix M
such that (array-mul M B)
equals to A
.
A and B must be a 2-dimensional square matrix.
If B
isn’t regular, an error is thrown.
{gauche.array
}
Element-wise arithmetics. The second argument and after must
be an array of the same shape of the first argument, or a number;
if it is a number, it is interpreted as an array of the same shape
of the first argument, and each element of which is the given number.
Returns an array of the same shape of the first argument, where each element is the result of addition, subtraction, multiplication or division of the corresponding elements of the arguments.
The linear-update version (procedures whose name ends with !
)
may reuse the storage of the first array to calculate the result.
The first array must be mutable. The caller must still use the returned
value instead of counting on the side effects.
(array-add-elements (array (shape 0 2 0 2) 1 2 3 4) (array (shape 0 2 0 2) 5 6 7 8) 10) ⇒ #,(<array> (0 2 0 2) 16 18 20 22) (array-div-elements (array (shape 0 2 0 2) 1 3 5 7) 100 (array (shape 0 2 0 2) 2 4 6 8)) ⇒ #,(<array> (0 2 0 2) 1/200 3/400 1/120 7/800)
If only one argument is passed, these procedures returns the argument itself.
You can mix different types of arrays as long as their shapes are the same. The result is the same type as the first argument.
(array-mul-elements (make-u8array (shape 0 2 0 2) 3) (array (shape 0 2 0 2) 1 3 5 7)) ⇒ #,(<u8array> (0 2 0 2) 3 9 15 21)
Returns an array with the same type of the shape of array, but each element is a negation of the corresponding elements in the original array.
(array-negate-elements (array (shape 0 2 0 2) 1 2 3 4)) ⇒ #,(<array> (0 2 0 2) -1 -2 -3 -4)
Returns an array with the same type of the shape of array, but each element is a reciprocal of the corresponding elements in the original array.
(array-reciprocate-elements (array (shape 0 2 0 2) 1 2 3 4)) ⇒ #,(<array> (0 2 0 2) 1 1/2 1/3 1/4)