Documented array printing, broadcasting, and transformations

This commit is contained in:
Neil Toronto 2012-11-28 00:43:07 -07:00
parent 7aadf33ead
commit 9249929c45
2 changed files with 167 additions and 28 deletions

View File

@ -17,7 +17,12 @@
(define old-ds (array-shape arr))
(define old-dims (vector-length old-ds))
(define new-dims (vector-length new-ds))
(define shift (assert (- new-dims old-dims) index?))
(define shift
(let ([shift (- new-dims old-dims)])
(cond [(index? shift) shift]
[else (error 'array-broadcast
"cannot broadcast to lower-dimensional array; given ~e and ~e"
arr new-ds)])))
(define old-js (make-thread-local-indexes old-dims))
(define old-f (unsafe-array-proc arr))
(unsafe-build-array

View File

@ -689,6 +689,9 @@ and @italic{no greater than} the number of axes after broadcasting.
]
This function is a left inverse of @racket[array->array-list]. (It cannot be a right inverse
because broadcasting cannot be undone.)
For a similar function that does not increase the dimension of the broadcast arrays, see
@racket[array-append*].
}
@defproc[(array->array-list [arr (Array A)] [axis Integer 0]) (Listof (Array A))]{
@ -703,10 +706,30 @@ The axis number @racket[axis] must be nonnegative and less than the number of @r
@subsection{Printing}
@;{
array-custom-printer
print-array-fields
print-array
@defparam[array-custom-printer
print-array
(All (A) ((Array A) Symbol Output-Port (U Boolean Zero One) -> Any))]{
A parameter that controls array printing.
}
(All (A) ((Array A) Symbol Output-Port (U Boolean Zero One) -> Any))
@defproc[(print-array [arr (Array A)]
[name Symbol]
[port Output-Port]
[mode (U Boolean 0 1)])
Any]{
Prints an array using @racket[array] syntax, using @racket[name] instead of @racket['array]
as the head form. This function is set as the value of @racket[array-custom-printer] when
@racketmodname[math/array] is required.
Well-behaved @racket[Array] subtypes do not call this function directly to print themselves.
They call the current @racket[array-custom-printer]:
@interaction[#:eval typed-eval
((array-custom-printer)
(array #[0 1 2 3])
'my-cool-array
(current-output-port)
#t)]
}
@section{Comprehensions and Sequences}
@ -939,12 +962,34 @@ the array arguments are eagerly evaluated. For example, this function never retu
@subsection{Broadcasting}
@defparam[array-broadcasting broadcasting? (U Boolean 'permissive)]{
@defparam[array-broadcasting broadcasting (U Boolean 'permissive)]{
Determines the rules used when broadcasting arrays for pointwise operations. See
@secref{array:broadcasting:control}.
}
@;{
array-shape-broadcast
array-broadcast
@defproc[(array-shape-broadcast [dss (Listof Indexes)]
[broadcasting (U Boolean 'permissive) (array-broadcasting)])
Indexes]{
Determines the shape of the resulting array if some number of arrays with shapes @racket[dss]
were broadcast for a pointwise operation using the given broadcasting rules. If broadcasting
fails, @racket[array-shape-broadcast] raises an error.
@examples[#:eval typed-eval
(array-shape-broadcast '())
(array-shape-broadcast (list (vector) ((inst vector Index) 10)))
(array-shape-broadcast (list ((inst vector Index) 2)
((inst vector Index) 10)))
(array-shape-broadcast (list ((inst vector Index) 2)
((inst vector Index) 10))
'permissive)]
}
@defproc[(array-broadcast [arr (Array A)] [ds Indexes]) (Array A)]{
Returns an array with shape @racket[ds] made by inserting new axes and repeating rows.
This is used for both @racket[(array-broadcasting #t)] and @racket[(array-broadcasting 'permissive)].
@examples[#:eval typed-eval
(array-broadcast (array 10) ((inst vector Index) 10))
(array-broadcast (array #[0 1]) #())
(array-broadcast (array #[0 1]) ((inst vector Index) 5))]
}
@section{Indexing and Slicing}
@ -1191,6 +1236,114 @@ Given a slice @racket[s] and an axis length @racket[dk], returns the arguments t
that would produce an equivalent slice specification.
}
@section{Transformations}
@defproc[(array-transform [arr (Array A)] [ds In-Indexes] [proc (Indexes -> In-Indexes)])
(Array A)]{
Returns an array with shape @racket[ds] and elements taken from @racket[arr], by composing
@racket[arr]'s procedure with @racket[proc].
Possibly the most useless, but simplest example of @racket[proc] disregards its input
indexes and returns constant indexes:
@interaction[#:eval typed-eval
(define arr (array #[#[0 1] #[2 'three]]))
(array-transform arr #(3 3) (λ: ([js : Indexes]) #(1 1)))]
Double an array in every dimension by duplicating elements:
@interaction[#:eval typed-eval
(define arr (index-array #(3 3)))
arr
(array-transform
arr
(vector-map (λ: ([d : Index]) (* d 2)) (array-shape arr))
(λ: ([js : Indexes])
(vector-map (λ: ([j : Index]) (quotient j 2)) js)))]
Recall that, because @racket[array-transform] returns @tech{non-strict} arrays, the above
result takes little more space than the original array.
Almost all array transformations, including those effected by @secref{array:slice-specs}, are
implemented using @racket[array-transform] or its unsafe counterpart.
}
@defproc[(array-append* [arrs (Listof (Array A))] [k Integer 0]) (Array A)]{
Appends the arrays in @racket[arrs] along axis @racket[k]. If the arrays' shapes are not
the same, they are @tech{broadcast} first.
@examples[#:eval typed-eval
(define arr (array #[#[0 1] #[2 3]]))
(define brr (array #[#['a 'b] #['c 'd]]))
(array-append* (list arr brr))
(array-append* (list arr brr) 1)
(array-append* (list arr (array 'x)))]
For an append-like operation that increases the dimension of the broadcast arrays, see
@racket[array-list->array].
}
@defproc[(array-axis-insert [arr (Array A)] [k Integer] [dk Integer 1]) (Array A)]{
Inserts an axis of length @racket[dk] before axis number @racket[k], which must be no greater
than the dimension of @racket[arr].
@examples[#:eval typed-eval
(define arr (array #[#[0 1] #[2 3]]))
(array-axis-insert arr 0)
(array-axis-insert arr 1)
(array-axis-insert arr 2)
(array-axis-insert arr 1 2)]
}
@defproc[(array-axis-ref [arr (Array A)] [k Integer] [jk Integer]) (Array A)]{
Removes an axis from @racket[arr] by keeping only row @racket[jk] in axis @racket[k], which
must be less than the dimension of @racket[arr].
@examples[#:eval typed-eval
(define arr (array #[#[0 1] #[2 3]]))
(array-axis-ref arr 0 0)
(array-axis-ref arr 0 1)
(array-axis-ref arr 1 0)]
}
@defproc[(array-axis-swap [arr (Array A)] [k0 Integer] [k1 Integer]) (Array A)]{
Returns an array like @racket[arr], but with axes @racket[k0] and @racket[k1] swapped.
In two dimensions, this is called a transpose.
@examples[#:eval typed-eval
(array-axis-swap (array #[#[0 1] #[2 3]]) 0 1)
(define arr (indexes-array #(2 2 2)))
arr
(array-axis-swap arr 0 1)
(array-axis-swap arr 1 2)]
}
@defproc[(array-axis-permute [arr (Array A)] [perm (Listof Integer)]) (Array A)]{
Returns an array like @racket[arr], but with axes permuted according to @racket[perm].
The list @racket[perm] represents a mapping from source axis numbers to destination
axis numbers: the source is the list position, the destination is the list element.
For example, the permutation @racket['(0 1)] is the identity permutation for two-dimensional
arrays, @racket['(1 0)] swaps axes @racket[0] and @racket[1], and @racket['(3 1 2 0)] swaps
axes @racket[0] and @racket[3].
The permutation must contain each integer from @racket[0] to @racket[(- (array-dims arr) 1)]
exactly once.
@examples[#:eval typed-eval
(array-axis-swap (array #[#[0 1] #[2 3]]) 0 1)
(array-axis-permute (array #[#[0 1] #[2 3]]) '(1 0))]
}
@defproc[(array-reshape [arr (Array A)] [ds In-Indexes]) (Array A)]{
Returns an array with elements in the same row-major order as @racket[arr], but with
shape @racket[ds]. The product of the indexes in @racket[ds] must be @racket[(array-size arr)].
@examples[#:eval typed-eval
(define arr (indexes-array #(2 3)))
arr
(array-reshape arr #(3 2))
(array-reshape (index-array #(3 3)) #(9))]
}
@defproc[(array-flatten [arr (Array A)]) (Array A)]{
Returns an array with shape @racket[(vector (array-size arr))], with the elements of
@racket[arr] in row-major order.
@examples[#:eval typed-eval
(array-flatten (array 10))
(array-flatten (array #[#[0 1] #[2 3]]))]
}
@section{Folds}
@;{
@ -1221,25 +1374,6 @@ array-inverse-fft
array-axis-inverse-fft
}
@section{Transformations}
@defidform[array-axis-insert]{
}
@defidform[array-axis-ref]{
}
@defidform[array-flatten]{
}
@;{
array-transform
array-axis-permute
array-axis-swap
array-append*
array-reshape
}
@section{Subtypes}
@subsection{Flonum Arrays}