6.13 Folds, Reductions and Expansions
6.13.1 Axis Folds
Folds a binary function f over axis k of arr. The result has the
shape of arr but with axis k removed.
The three-argument variant uses the first value of each row in axis k as init.
It therefore requires axis k to have positive length.
Examples: |
> (define arr (index-array #(3 4))) | | > arr | eval:256:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr51 | in: arr | > (array-axis-fold arr 0 +) | eval:257:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr51 | in: + | > (array-axis-fold arr 1 (inst cons Index (Listof Index)) empty) | eval:258:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr51 | in: empty |
|
Notice that the second example returns an array of reversed lists.
This is therefore a left fold; see
foldl.
If you need control over the order of evaluation in axis k’s rows, see
array-axis-reduce.
Some standard per-axis folds, defined in terms of
array-axis-fold. The two-argument
variants require axis
k to have positive length.
Examples: |
> (define arr (index-array #(3 4))) | | > arr | eval:260:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr52 | in: arr | > (array-axis-fold arr 1 +) | eval:261:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr52 | in: + | > (array-axis-sum arr 1) | eval:262:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr52 | in: 1 | > (array-axis-sum arr 0 0.0) | eval:263:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr52 | in: 0.0 |
|
Counts the elements x in rows of axis k for which (pred? x) is true.
Examples: |
> (define arr (index-array #(3 3))) | | > arr | eval:265:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr53 | in: arr | > (array-axis-count arr 1 odd?) | eval:266:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr53 | in: odd? |
|
Apply
and or
or to each row in axis
k of array
arr.
Evaluation is short-cut as with the
and and
or macros, which is only observable
if
arr is
nonstrict.
In the following example, computing the second array element sets second? to #t:
> (define second? (ann #f Boolean)) |
|
|
eval:268:0: Type Checker: missing type for top-level identifier; | either undefined or missing a type annotation | identifier: second?54 | in: #t | context...: | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/utils/tc-utils.rkt:123:0: report-all-errors | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt:515:0: tc-toplevel-form | fail-to-succeed | fail-to-succeed | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/tc-setup.rkt:39:0: tc-setup | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typed-racket.rkt:24:4 | /Users/mflatt/build/macro/racket/collects/racket/private/more-scheme.rkt:148:2: call-with-break-parameterization | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/sandbox-lib/racket/sandbox.rkt:837:5: loop | eval:268:0: Type Checker: type mismatch; | mutation only allowed with compatible types | expected: Nothing | given: True | in: #t | context...: | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/utils/tc-utils.rkt:123:0: report-all-errors | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt:515:0: tc-toplevel-form | fail-to-succeed | fail-to-succeed | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/tc-setup.rkt:39:0: tc-setup | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typed-racket.rkt:24:4 | /Users/mflatt/build/macro/racket/collects/racket/private/more-scheme.rkt:148:2: call-with-break-parameterization | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/sandbox-lib/racket/sandbox.rkt:837:5: loop |
|
Type Checker: Summary: 2 errors encountered |
Printing
arr causes
(set! second? #t) to be evaluated, but applying
array-axis-and does not:
> (array-axis-and arr 0) |
eval:269:0: Type Checker: missing type for top-level |
identifier; |
either undefined or missing a type annotation |
identifier: arr53 |
in: 0 |
> second? |
eval:270:0: Type Checker: missing type for top-level |
identifier; |
either undefined or missing a type annotation |
identifier: second?54 |
in: second? |
However, if
arr were strict,
(set! second? #t) would be evaluated when
arr
was created.
6.13.2 Whole-Array Folds
Folds g over each axis of arr, in reverse order. The arguments
to g are an array (initially arr) and the current axis.
It should return an array with one fewer dimension than the array given, but does not have to.
Examples: |
> (define arr (index-array #(3 4))) | | > arr | eval:272:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr56 | in: arr | | eval:273:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr56 | in: k | > (apply + (array->list arr)) | eval:274:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr56 | in: arr | | eval:275:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr56 | in: #() |
|
Folds f over every element of arr by folding f over each axis in
reverse order. The two-argument variant is equivalent to
and the three-argument variant is similar. The two-argument variant requires every axis to have
positive length.
Examples: |
> (define arr (index-array #(3 4))) | | > arr | eval:277:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr57 | in: arr | > (array-all-fold arr +) | eval:278:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr57 | in: + | > (array-all-fold (array #[]) + 0.0) | - : Flonum [more precisely: Nonnegative-Flonum] | 0.0 |
|
Because f is folded over the last axis first, it receives arr’s elements (as its
first argument) in row-major order.
Some standard whole-array folds, defined in terms of
array-all-fold. The one-argument
variants require each axis in
arr to have positive length.
Examples: |
> (define arr (index-array #(3 4))) | | > arr | eval:281:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr58 | in: arr | > (array-all-fold arr +) | eval:282:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr58 | in: + | > (array-all-sum arr) | eval:283:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr58 | in: arr | > (array-all-sum arr 0.0) | eval:284:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr58 | in: 0.0 |
|
Apply
and or
or to
arr’s elements using short-cut evaluation in row-major
order.
Examples: |
> (define arr (index-array #(3 3))) | | > (array-all-and (array= arr arr)) | eval:286:0: Type Checker: missing type for top-level identifier; | either undefined or missing a type annotation | identifier: arr59 | in: arr | context...: | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/utils/tc-utils.rkt:123:0: report-all-errors | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt:515:0: tc-toplevel-form | fail-to-succeed | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/tc-setup.rkt:39:0: tc-setup | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typed-racket.rkt:24:4 | /Users/mflatt/build/macro/racket/collects/racket/private/more-scheme.rkt:148:2: call-with-break-parameterization | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/sandbox-lib/racket/sandbox.rkt:837:5: loop | eval:286:0: Type Checker: missing type for top-level identifier; | either undefined or missing a type annotation | identifier: arr59 | in: arr | context...: | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/utils/tc-utils.rkt:123:0: report-all-errors | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt:515:0: tc-toplevel-form | fail-to-succeed | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/tc-setup.rkt:39:0: tc-setup | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typed-racket.rkt:24:4 | /Users/mflatt/build/macro/racket/collects/racket/private/more-scheme.rkt:148:2: call-with-break-parameterization | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/sandbox-lib/racket/sandbox.rkt:837:5: loop |
| Type Checker: Summary: 2 errors encountered | > (define brr (array+ arr (array 1))) | eval:287:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr59 | in: 1 | > (array-all-and (array= arr brr)) | eval:288:0: Type Checker: missing type for top-level identifier; | either undefined or missing a type annotation | identifier: arr59 | in: brr | context...: | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/utils/tc-utils.rkt:123:0: report-all-errors | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt:515:0: tc-toplevel-form | fail-to-succeed | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/tc-setup.rkt:39:0: tc-setup | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typed-racket.rkt:24:4 | /Users/mflatt/build/macro/racket/collects/racket/private/more-scheme.rkt:148:2: call-with-break-parameterization | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/sandbox-lib/racket/sandbox.rkt:837:5: loop | eval:288:0: Type Checker: missing type for top-level identifier; | either undefined or missing a type annotation | identifier: brr46 | in: brr | context...: | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/utils/tc-utils.rkt:123:0: report-all-errors | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typecheck/tc-toplevel.rkt:515:0: tc-toplevel-form | fail-to-succeed | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/tc-setup.rkt:39:0: tc-setup | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/typed-racket-lib/typed-racket/typed-racket.rkt:24:4 | /Users/mflatt/build/macro/racket/collects/racket/private/more-scheme.rkt:148:2: call-with-break-parameterization | /Users/mflatt/build/macro/build/user/6.2.900.4/pkgs/sandbox-lib/racket/sandbox.rkt:837:5: loop |
| Type Checker: Summary: 2 errors encountered | > (array-all-or (array= arr (array 0))) | eval:289:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr59 | in: 0 |
|
When given one array
arr, returns the number of elements
x in
arr for
which
(pred? x) is true.
When given multiple arrays,
array-count does the same with the corresponding elements from
any number of arrays.
If the arrays’ shapes are not the same, they are
broadcast first.
Examples: |
> (array-count zero? (array #[#[0 1 0 2] #[0 3 -1 4]])) | - : Integer [more precisely: Index] | 3 | | - : Integer [more precisely: Index] | 4 |
|
but does not create intermediate (strict) arrays, and always returns an
Index.
Like
andmap and
ormap, but for arrays.
Evaluation is short-cut, in row-major order.
If the arrays’ shapes are not the same, they are
broadcast first.
Determining whether each row is equal to
(array #[0 1]):
Determining whether any row has 0 as its first element or 1 as its second:
Determining whether any row is equal to
(array #[0 1]):
6.13.3 General Reductions and Expansions
Like
array-axis-fold, but allows evaluation control (such as short-cutting
and and
or) by moving the loop into
h. The result has the shape of
arr, but with
axis
k removed.
The arguments to h are the length of axis k and a procedure that retrieves
elements from that axis’s rows by their indexes in axis k. It should return the elements
of the resulting array.
For example, summing the squares of the rows in axis 1:
> (define arr (index-array #(3 3))) |
|
> arr |
eval:296:0: Type Checker: missing type for top-level |
identifier; |
either undefined or missing a type annotation |
identifier: arr61 |
in: arr |
|
eval:297:0: Type Checker: missing type for top-level |
identifier; |
either undefined or missing a type annotation |
identifier: arr61 |
in: jk |
> (array-axis-sum (array-map sqr arr) 1) |
eval:298:0: Type Checker: missing type for top-level |
identifier; |
either undefined or missing a type annotation |
identifier: arr61 |
in: 1 |
|
eval:299:0: Type Checker: missing type for top-level |
identifier; |
either undefined or missing a type annotation |
identifier: arr61 |
in: empty |
> (array-axis-reduce arr 1 (inst build-list Index)) |
eval:300:0: Type Checker: missing type for top-level |
identifier; |
either undefined or missing a type annotation |
identifier: arr61 |
in: Index |
Every fold, including array-axis-fold, is ultimately defined using
array-axis-reduce or its unsafe counterpart.
Inserts a new axis number k of length dk, using g to generate values;
k must be no greater than the dimension of arr, and dk must be
nonnegative.
Conceptually, g is applied dk times to each element in each row of axis k,
once for each nonnegative index jk < dk.
> (define arr (array #['#(a b c) '#(d e f) '#(g h i)])) |
|
> (array-axis-expand arr 1 3 vector-ref) |
eval:302:0: Type Checker: missing type for top-level |
identifier; |
either undefined or missing a type annotation |
identifier: arr62 |
in: vector-ref |
This function is a dual of array-axis-reduce in that it can be used to invert applications
of array-axis-reduce.
To do so, g should be a destructuring function that is dual to the constructor passed to
array-axis-reduce.
Example dual pairs are vector-ref and build-vector, and list-ref and
build-list.
(Do not pass list-ref to array-axis-expand if you care about performance, though.
See list-array->array for a more efficient solution.)
Returns an array of lists, computed as if by applying
list to the elements in each row of
axis
k.
Examples: |
> (define arr (index-array #(3 3))) | | > arr | eval:305:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr63 | in: arr | > (array->list-array arr 1) | eval:306:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr63 | in: 1 | > (array-ref (array->list-array (array->list-array arr 1) 0) #()) | eval:307:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr63 | in: #() |
|
Returns an array in which the list elements of
arr comprise a new axis
k.
Equivalent to
(array-axis-expand arr k n list-ref) where
n is the
length of the lists in
arr, but with O(1) indexing.
Examples: |
> (define arr (array->list-array (index-array #(3 3)) 1)) | | > arr | eval:309:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr64 | in: arr | > (list-array->array arr 1) | eval:310:0: Type Checker: missing type for top-level | identifier; | either undefined or missing a type annotation | identifier: arr64 | in: 1 |
|
For fixed k, this function and array->list-array are mutual inverses with respect
to their array arguments.