Documented `math/array' folds

Refactored many of the fold functions (e.g. `array-axis-andmap' is gone,
replaced by short-cutting `array-axis-and', which is sufficient because the
result of `array-map' is non-strict; added `array-count', `array-all-fold';
removed `array-all=' and friends)

Turned common folds into macros (preserves return types better, speeds up
compilation time)

Exposed a safe variant of `unsafe-array-axis-reduce'
This commit is contained in:
Neil Toronto 2012-11-28 14:13:29 -07:00
parent 9249929c45
commit cd002d5830
7 changed files with 381 additions and 182 deletions

View File

@ -8,6 +8,7 @@
"private/array/array-transform.rkt"
"private/array/array-convert.rkt"
"private/array/array-fold.rkt"
"private/array/array-special-folds.rkt"
"private/array/array-print.rkt"
"private/array/array-fft.rkt"
"private/array/array-syntax.rkt"
@ -34,6 +35,7 @@
"private/array/array-transform.rkt"
"private/array/array-convert.rkt"
"private/array/array-fold.rkt"
"private/array/array-special-folds.rkt"
"private/array/array-print.rkt"
"private/array/array-syntax.rkt"
"private/array/array-fft.rkt"

View File

@ -1,35 +1,32 @@
#lang racket/base
(require typed/untyped-utils
(except-in "typed-array-fold.rkt"
array-axis-sum
array-axis-prod
array-axis-min
array-axis-max
array-all-sum
array-all-prod
array-all-min
array-all-max))
(require (for-syntax racket/base)
"typed-array-fold.rkt")
(require/untyped-contract
(begin (require "array-struct.rkt"))
"typed-array-fold.rkt"
[array-axis-sum (case-> ((Array Number) Integer -> (Array Number))
((Array Number) Integer Number -> (Array Number)))]
[array-axis-prod (case-> ((Array Number) Integer -> (Array Number))
((Array Number) Integer Number -> (Array Number)))]
[array-axis-min (case-> ((Array Real) Integer -> (Array Real))
((Array Real) Integer Real -> (Array Real)))]
[array-axis-max (case-> ((Array Real) Integer -> (Array Real))
((Array Real) Integer Real -> (Array Real)))]
[array-all-sum (case-> ((Array Number) -> Number)
((Array Number) Number -> Number))]
[array-all-prod (case-> ((Array Number) -> Number)
((Array Number) Number -> Number))]
[array-all-min (case-> ((Array Real) -> Real)
((Array Real) Real -> Real))]
[array-all-max (case-> ((Array Real) -> Real)
((Array Real) Real -> Real))])
;; ===================================================================================================
;; Standard folds
(define-syntax-rule (define-axis-fold name f)
(define-syntax (name stx)
(syntax-case stx ()
[(_ arr k) (syntax/loc stx (array-axis-fold arr k f))]
[(_ arr k init) (syntax/loc stx (array-axis-fold arr k f init))])))
(define-syntax-rule (define-all-fold name f)
(define-syntax (name stx)
(syntax-case stx ()
[(_ arr) (syntax/loc stx (array-all-fold arr f))]
[(_ arr init) (syntax/loc stx (array-all-fold arr f init))])))
(define-axis-fold array-axis-sum +)
(define-axis-fold array-axis-prod *)
(define-axis-fold array-axis-min min)
(define-axis-fold array-axis-max max)
(define-all-fold array-all-sum +)
(define-all-fold array-all-prod *)
(define-all-fold array-all-min min)
(define-all-fold array-all-max max)
(provide array-axis-fold
array-axis-sum
@ -37,17 +34,15 @@
array-axis-min
array-axis-max
array-axis-count
array-axis-andmap
array-axis-ormap
array-axis-and
array-axis-or
array-fold
array-all-fold
array-all-sum
array-all-prod
array-all-min
array-all-max
array-all-count
array-all-andmap
array-all-ormap
array-all-equal?
array-all-eqv?
array-all-eq?
array-all=)
array-all-and
array-all-or
array-axis-reduce
unsafe-array-axis-reduce)

View File

@ -18,7 +18,10 @@
(: print-array (All (A) ((Array A) Symbol Output-Port (U #t #f 0 1) -> Any)))
;; The logic in `print-array' causes the REPL printer to try printing an array in each layout, and
;; keep the first successful one. An overflowing line means failure.
(define (print-array arr name port mode)
(define (print-array orig-arr name port mode)
;; Try to compute each element only once
(define arr (array-lazy orig-arr))
;; Called to print array elements; may recur (e.g. printing arrays of arrays)
;; We never have to consider the `mode' argument again after defining `recur-print'
(define recur-print

View File

@ -0,0 +1,26 @@
#lang typed/racket/base
(require "array-struct.rkt"
"array-fold.rkt"
"array-pointwise.rkt")
(provide array-count)
(: array-count
(All (A B T ...)
(case-> ((A -> Any) (Array A) -> Index)
((A B T ... T -> Any) (Array A) (Array B) (Array T) ... T -> Index))))
(define array-count
(case-lambda:
[([f : (A -> Any)] [arr0 : (Array A)])
(assert (array-all-sum (inline-array-map (λ: ([a : A]) (if (f a) 1 0)) arr0)) index?)]
[([f : (A B -> Any)] [arr0 : (Array A)] [arr1 : (Array B)])
(assert
(array-all-sum (inline-array-map (λ: ([a : A] [b : B]) (if (f a b) 1 0)) arr0 arr1))
index?)]
[([f : (A B T ... T -> Any)] [arr0 : (Array A)] [arr1 : (Array B)] . [arrs : (Array T) ... T])
(assert
(array-all-sum (apply array-map
(λ: ([a : A] [b : B] . [ts : T ... T]) (if (apply f a b ts) 1 0))
arr0 arr1 arrs))
index?)]))

View File

@ -1,11 +1,11 @@
#lang typed/racket/base
(require racket/performance-hint
racket/fixnum
"../unsafe.rkt"
"array-struct.rkt"
"array-indexing.rkt"
"utils.rkt"
"for-each.rkt")
"utils.rkt")
(provide (all-defined-out))
@ -16,16 +16,32 @@
(define (check-array-axis name arr k)
(define dims (array-dims arr))
(cond
[(= dims 0) (raise-argument-error 'name "Array with at least one axis" 0 arr k)]
[(fx= dims 0) (raise-argument-error name "Array with at least one axis" 0 arr k)]
[(or (0 . > . k) (k . >= . dims))
(raise-argument-error 'name (format "Index < ~a" dims) 1 arr k)]
(raise-argument-error name (format "Index < ~a" dims) 1 arr k)]
[else k]))
(: array-axis-reduce (All (A B) ((Array A) Integer (Index (Integer -> A) -> B) -> (Array B))))
(define (array-axis-reduce arr k f)
(let ([k (check-array-axis 'array-axis-reduce arr k)])
(define ds (array-shape arr))
(define dk (unsafe-vector-ref ds k))
(define new-ds (unsafe-vector-remove ds k))
(define proc (unsafe-array-proc arr))
(unsafe-build-array
new-ds (λ: ([js : Indexes])
(define old-js (unsafe-vector-insert js k 0))
(f dk (λ: ([jk : Integer])
(cond [(or (jk . < . 0) (jk . >= . dk))
(raise-argument-error 'array-axis-reduce (format "Index < ~a" dk) jk)]
[else
(unsafe-vector-set! old-js k jk)
(proc (vector-copy-all old-js))])))))))
(: unsafe-array-axis-reduce (All (A B) ((Array A) Index (Index (Index -> A) -> B) -> (Array B))))
(begin-encourage-inline
(define (unsafe-array-axis-reduce arr k f)
(define ds (array-shape arr))
(define dims (vector-length ds))
(define dk (unsafe-vector-ref ds k))
(define new-ds (unsafe-vector-remove ds k))
(define proc (unsafe-array-proc arr))
@ -42,18 +58,18 @@
(unsafe-array-axis-reduce
arr k (λ: ([dk : Index] [proc : (Index -> A)])
(let: loop : B ([jk : Nonnegative-Fixnum 0] [acc : B init])
(cond [(jk . < . dk) (loop (+ jk 1) (f (proc jk) acc))]
(cond [(jk . fx< . dk) (loop (fx+ jk 1) (f (proc jk) acc))]
[else acc]))))))
(: array-axis-fold/no-init (All (A) ((Array A) Integer (A A -> A) -> (Array A))))
(define (array-axis-fold/no-init arr k f)
(let ([k (check-array-axis 'array-axis-fold arr k)])
(when (= (unsafe-vector-ref (array-shape arr) k) 0)
(when (fx= (unsafe-vector-ref (array-shape arr) k) 0)
(raise-argument-error 'array-axis-fold "nonzero axis" 0 arr k))
(unsafe-array-axis-reduce
arr k (λ: ([dk : Index] [proc : (Index -> A)])
(let: loop : A ([jk : Nonnegative-Fixnum 1] [acc : A (proc 0)])
(cond [(jk . < . dk) (loop (+ jk 1) (f (proc jk) acc))]
(cond [(jk . fx< . dk) (loop (fx+ jk 1) (f (proc jk) acc))]
[else acc]))))))
(: array-axis-fold (All (A B) (case-> ((Array A) Integer (A A -> A) -> (Array A))
@ -63,57 +79,33 @@
[(arr k f) (array-axis-fold/no-init arr k f)]
[(arr k f init) (array-axis-fold/init arr k f init)]))
;; ---------------------------------------------------------------------------------------------------
;; Whole-array fold
;; ===================================================================================================
;; Whole-array folds
(: array-fold (All (A) ((Array A) ((Array A) Index -> (Array A)) -> (Array A))))
(begin-encourage-inline
(: array-fold (All (A) ((Array A) ((Array A) Index -> (Array A)) -> (Array A))))
(define (array-fold arr f)
(define dims (array-dims arr))
(let loop ([#{k : Index} dims] [arr arr])
(cond [(zero? k) arr]
[else (let ([k (sub1 k)])
(loop k (f arr k)))]))))
;; ===================================================================================================
;; Standard axis folds
(define-syntax-rule (define-axis-fold name op T ...)
(begin-encourage-inline
(: name (case-> ((Array T) Integer -> (Array T)) ...
((Array T) Integer T -> (Array T)) ...))
(define name
(case-lambda
[(arr k) (array-axis-fold arr k op)]
[(arr k init) (array-axis-fold arr k op init)]))))
(define-axis-fold array-axis-sum + Float Real Float-Complex Number)
(define-axis-fold array-axis-prod * Float Real Float-Complex Number)
(define-axis-fold array-axis-min min Float Real)
(define-axis-fold array-axis-max max Float Real)
;; ===================================================================================================
;; Standard whole-array folds
(define-syntax-rule (define-fold name array-axis-op T ...)
(begin-encourage-inline
(: name (case-> ((Array T) -> T) ...
((Array T) T -> T) ...))
(define name
(case-lambda
[(arr) (array-ref (array-fold arr array-axis-op) #())]
[(arr init)
(plet: (A) ([arr : (Array A) arr]
[array-axis-op : ((Array A) Index A -> (Array A)) array-axis-op]
[init : A init])
(array-ref (array-fold arr (λ: ([arr : (Array A)] [k : Index])
(array-axis-op arr k init)))
#()))]))))
(define-fold array-all-sum array-axis-sum Float Real Float-Complex Number)
(define-fold array-all-prod array-axis-prod Float Real Float-Complex Number)
(define-fold array-all-min array-axis-min Float Real)
(define-fold array-all-max array-axis-max Float Real)
(cond [(fx= k 0) arr]
[else (let ([k (fx- k 1)])
(loop k (f arr k)))])))
(: array-all-fold (All (A) (case-> ((Array A) (A A -> A) -> A)
((Array A) (A A -> A) A -> A))))
(define array-all-fold
(case-lambda
[(arr f)
(array-ref (array-fold arr (λ: ([arr : (Array A)] [k : Index])
(array-axis-fold arr k f)))
#())]
[(arr f init)
(array-ref (array-fold arr (λ: ([arr : (Array A)] [k : Index])
(array-axis-fold arr k f init)))
#())]))
) ; begin-encourage-inline
;; ===================================================================================================
;; Count
@ -124,69 +116,38 @@
(unsafe-array-axis-reduce
arr k (λ: ([dk : Index] [proc : (Index -> A)])
(let: loop : Index ([jk : Nonnegative-Fixnum 0] [acc : Nonnegative-Fixnum 0])
(if (jk . < . dk)
(cond [(pred? (proc jk)) (loop (+ jk 1) (unsafe-fx+ acc 1))]
[else (loop (+ jk 1) acc)])
(if (jk . fx< . dk)
(cond [(pred? (proc jk)) (loop (fx+ jk 1) (unsafe-fx+ acc 1))]
[else (loop (fx+ jk 1) acc)])
(assert acc index?)))))))
(: array-all-count (All (A) ((Array A) (A -> Any) -> Index)))
(define (array-all-count arr pred?)
(define: i : (Boxof Nonnegative-Fixnum) (box 0))
(define proc (unsafe-array-proc arr))
(define ds (array-shape arr))
(for-each-array-index ds (λ (js) (when (pred? (proc js)) (set-box! i (unsafe-fx+ (unbox i) 1)))))
(assert (unbox i) index?))
;; ===================================================================================================
;; Short-cutting andmap
;; Short-cutting axis folds
(: array-axis-andmap (All (A) ((Array A) Integer (A -> Any) -> (Array Boolean))))
(define (array-axis-andmap arr k pred?)
(let ([k (check-array-axis 'array-axis-andmap arr k)])
(: array-axis-and (All (A) ((Array A) Integer -> (Array (U A Boolean)))))
(define (array-axis-and arr k)
(let ([k (check-array-axis 'array-axis-and arr k)])
(unsafe-array-axis-reduce
arr k (λ: ([dk : Index] [proc : (Index -> A)])
(let: loop : Boolean ([jk : Nonnegative-Fixnum 0])
(cond [(jk . < . dk) (if (pred? (proc jk)) (loop (+ jk 1)) #f)]
[else #t]))))))
(let: loop : (U A Boolean) ([jk : Nonnegative-Fixnum 0] [acc : (U A Boolean) #t])
(cond [(jk . fx< . dk) (define v (and acc (proc jk)))
(if v (loop (fx+ jk 1) v) v)]
[else acc]))))))
(: array-all-andmap (All (A) ((Array A) (A -> Any) -> Boolean)))
(define (array-all-andmap arr pred?)
(let/ec: return : Boolean
(define proc (unsafe-array-proc arr))
(define ds (array-shape arr))
(for-each-array-index ds (λ (js) (unless (pred? (proc js)) (return #f))))
#t))
;; ===================================================================================================
;; Short-cutting ormap
(: array-axis-ormap (All (A) ((Array A) Integer (A -> Any) -> (Array Boolean))))
(define (array-axis-ormap arr k pred?)
(let ([k (check-array-axis 'array-axis-ormap arr k)])
(: array-axis-or (All (A) ((Array A) Integer -> (Array (U A #f)))))
(define (array-axis-or arr k)
(let ([k (check-array-axis 'array-axis-or arr k)])
(unsafe-array-axis-reduce
arr k (λ: ([dk : Index] [proc : (Index -> A)])
(let: loop : Boolean ([jk : Nonnegative-Fixnum 0])
(cond [(jk . < . dk) (if (pred? (proc jk)) #t (loop (+ jk 1)))]
[else #f]))))))
(let: loop : (U A #f) ([jk : Nonnegative-Fixnum 0] [acc : (U A #f) #f])
(cond [(jk . fx< . dk) (define v (or acc (proc jk)))
(if v v (loop (fx+ jk 1) v))]
[else acc]))))))
(: array-all-ormap (All (A) ((Array A) (A -> Any) -> Boolean)))
(define (array-all-ormap arr pred?)
(let/ec: return : Boolean
(define f (unsafe-array-proc arr))
(define ds (array-shape arr))
(for-each-array-index ds (λ (js) (when (pred? (f js)) (return #t))))
#f))
(: array-all-and (All (A B) ((Array A) -> (U A Boolean))))
(define (array-all-and arr)
(array-ref ((inst array-fold (U A Boolean)) arr array-axis-and) #()))
;; ===================================================================================================
(: array-all-equal? ((Array Any) (Array Any) -> Boolean))
(define array-all-equal? equal?)
(: array-all-eqv? ((Array Any) (Array Any) -> Boolean))
(define array-all-eqv? (array-lift-comparison eqv?))
(: array-all-eq? ((Array Any) (Array Any) -> Boolean))
(define array-all-eq? (array-lift-comparison eq?))
(: array-all= ((Array Number) (Array Number) -> Boolean))
(define array-all= (array-lift-comparison =))
(: array-all-or (All (A B) ((Array A) -> (U A #f))))
(define (array-all-or arr)
(array-ref ((inst array-fold (U A #f)) arr array-axis-or) #()))

View File

@ -37,7 +37,8 @@
(vector-ref (array-shape a) 0))
(: matrix-all= : (Matrix Number) (Matrix Number) -> Boolean)
(define matrix-all= array-all=)
(define (matrix-all= arr0 arr1)
(array-all-and (array= arr0 arr1)))
(: matrix-dimensions : (Matrix Number) -> (Values Index Index))
(define (matrix-dimensions a)

View File

@ -5,9 +5,9 @@
(for-label racket/base racket/vector racket/match racket/unsafe/ops racket/string
math plot
(only-in typed/racket/base
ann inst : λ: define: make-predicate
ann inst : λ: define: make-predicate ->
Flonum Real Boolean Any Integer Index Natural Exact-Positive-Integer
Nonnegative-Real Sequenceof Fixnum Values
Nonnegative-Real Sequenceof Fixnum Values Number
All U List Vector Listof Vectorof Struct))
"utils.rkt")
@ -16,7 +16,8 @@
(require racket/match
racket/vector
racket/string
racket/sequence)]
racket/sequence
racket/list)]
@title[#:tag "arrays" #:style 'toc]{Arrays}
@(author-neil)
@ -52,6 +53,10 @@ applied to indexes to retrieve elements.
@local-table-of-contents[]
@;{==================================================================================================}
@section{Preliminaries}
@subsection{Definitions}
@ -296,6 +301,10 @@ of stretching just singleton axes:
Notice that @racket[(array #["+" "-"])] was repeated five times, and that
@racket[arr3] was repeated three full times and once partially.
@;{==================================================================================================}
@section{Types, Predicates and Accessors}
@defform[(Array A)]{
@ -433,6 +442,10 @@ Returns the number of @racket[arr]'s dimensions. Equivalent to
Returns the vector of data that @racket[arr] contains.
}
@;{==================================================================================================}
@section{Construction}
@defform[(array #[#[...] ...])]{
@ -614,6 +627,10 @@ have the value @racket[on-value]; the rest have the value @racket[off-value].
(diagonal-array 2 7 1 0)]
}
@;{==================================================================================================}
@section{Conversion}
@deftogether[(@defproc[(list->array [lst (Listof A)]) (Array A)]
@ -732,6 +749,10 @@ They call the current @racket[array-custom-printer]:
#t)]
}
@;{==================================================================================================}
@section{Comprehensions and Sequences}
Sometimes sequential processing is unavoidable, so @racket[math/array] provides loops and sequences.
@ -805,6 +826,10 @@ Returns a sequence of indexes for shape @racket[ds], in row-major order.
(indexes-array #(3 3))]
}
@;{==================================================================================================}
@section{Pointwise Operations}
Most of the operations documented in this section are simple macros that apply @racket[array-map]
@ -992,6 +1017,10 @@ This is used for both @racket[(array-broadcasting #t)] and @racket[(array-broadc
(array-broadcast (array #[0 1]) ((inst vector Index) 5))]
}
@;{==================================================================================================}
@section{Indexing and Slicing}
@defproc[(array-ref [arr (Array A)] [js In-Indexes]) A]{
@ -1236,6 +1265,10 @@ 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)])
@ -1257,8 +1290,8 @@ Double an array in every dimension by duplicating elements:
(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.
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.
@ -1314,7 +1347,7 @@ Returns an array like @racket[arr], but with axes permuted according to @racket[
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
For example, the permutation @racket['(0 1 2)] is the identity permutation for three-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].
@ -1344,36 +1377,209 @@ Returns an array with shape @racket[(vector (array-size arr))], with the element
(array-flatten (array #[#[0 1] #[2 3]]))]
}
@section{Folds}
@;{
array-axis-fold
array-fold
array-all-sum
array-all-prod
array-all-min
array-all-max
array-axis-count
array-all-count
array-axis-andmap
array-all-andmap
array-axis-ormap
array-all-ormap
array-all-eq?
array-all-equal?
array-all-eqv?
array-all=
array-axis-sum
array-axis-prod
array-axis-min
array-axis-max
array-lift-comparison
array-axis-fft
array-fft
@;{==================================================================================================}
@section{Folds and Other Axis Reductions}
@defproc*[([(array-axis-fold [arr (Array A)] [k Integer] [f (A A -> A)]) (Array A)]
[(array-axis-fold [arr (Array A)] [k Integer] [f (A B -> B)] [init B]) (Array B)])]{
Folds a binary function @racket[f] over axis @racket[k] of @racket[arr]. The result has the
shape of @racket[arr] but with axis @racket[k] removed.
The three-argument variant uses the first value of each row in axis @racket[k] as @racket[init].
It therefore requires axis @racket[k] to have positive length.
@examples[#:eval typed-eval
(define arr (index-array #(3 4)))
arr
(array-axis-fold arr 0 +)
(array-axis-fold arr 1 (inst cons Index (Listof Index)) empty)]
Notice that the second example returns an array of reversed lists.
This is therefore a left fold; see @racket[foldl].
}
@deftogether[(@defform*[((array-axis-sum arr k)
(array-axis-sum arr k init))]
@defform*[((array-axis-prod arr k)
(array-axis-prod arr k init))
#:contracts ([arr (Array Number)]
[k Integer]
[init Number])])]{
}
@deftogether[(@defform*[((array-axis-min arr k)
(array-axis-min arr k init))]
@defform*[((array-axis-max arr k)
(array-axis-max arr k init))
#:contracts ([arr (Array Real)]
[k Integer]
[init Real])])]{
Some standard per-axis folds, defined in terms of @racket[array-axis-fold]. The two-argument
variants require axis @racket[k] to have positive length.
@examples[#:eval typed-eval
(define arr (index-array #(3 4)))
arr
(array-axis-fold arr 1 +)
(array-axis-sum arr 1)
(array-axis-sum arr 0 0.0)]
}
@defproc[(array-fold [arr (Array A)] [g ((Array A) Index -> (Array A))]) (Array A)]{
Folds @racket[g] over @italic{each axis} of @racket[arr], in reverse order. The arguments
to @racket[g] are an array (initially @racket[arr]) and the current axis.
It should return an array with one fewer dimension than the array given, but does not have to.
@examples[#:eval typed-eval
(define arr (index-array #(3 4)))
arr
(array-fold arr (λ: ([arr : (Array Integer)] [k : Index])
(array-axis-sum arr k)))
(+ 0 1 2 3 4 5 6 7 8 9 10 11)
(array-fold
arr
(λ: ([arr : (Array (Listof* Index))] [k : Index])
(array-map
(inst reverse (Listof* Index))
(array-axis-fold arr k
(inst cons (Listof* Index) (Listof (Listof* Index)))
empty))))]
}
@defproc*[([(array-all-fold [arr (Array A)] [f (A A -> A)]) A]
[(array-all-fold [arr (Array A)] [f (A A -> A)] [init A]) A])]{
Folds @racket[f] over every element of @racket[arr] by folding @racket[f] over each axis in
reverse order. The two-argument variant is equivalent to
@racketblock[(array-ref (array-fold arr (λ: ([arr : (Array A)] [k : Index])
(array-axis-fold arr k f)))
#())]
and the three-argument variant is similar. The two-argument variant requires every axis to have
positive length.
@examples[#:eval typed-eval
(define arr (index-array #(3 4)))
arr
(array-all-fold arr +)
(array-all-fold (array #[]) + 0.0)]
}
@deftogether[(@defform*[((array-all-sum arr)
(array-all-sum arr init))]
@defform*[((array-all-prod arr)
(array-all-prod arr init))
#:contracts ([arr (Array Number)]
[init Number])])]{
}
@deftogether[(@defform*[((array-all-min arr)
(array-all-min arr init))]
@defform*[((array-all-max arr)
(array-all-max arr init))
#:contracts ([arr (Array Real)]
[init Real])])]{
Some standard whole-array folds, defined in terms of @racket[array-all-fold]. The one-argument
variants require each axis in @racket[arr] to have positive length.
@examples[#:eval typed-eval
(define arr (index-array #(3 4)))
arr
(array-all-fold arr +)
(array-all-sum arr)
(array-all-sum arr 0.0)]
}
@defproc[(array-axis-count [arr (Array A)] [k Integer] [pred? (A -> Any)]) (Array Index)]{
Counts the elements @racket[x] in rows of axis @racket[k] for which @racket[(pred? x)] is true.
@examples[#:eval typed-eval
(define arr (index-array #(3 3)))
arr
(array-axis-count arr 1 odd?)]
}
@defproc*[([(array-count [pred? (A -> Any)] [arr0 (Array A)]) Index]
[(array-count [pred? (A B Ts ... -> Any)]
[arr0 (Array A)]
[arr1 (Array B)]
[arrs (Array Ts)] ...)
Index])]{
The two-argument variant returns the number of elements @racket[x] in @racket[arr] for which
@racket[(pred? x)] is true. The other variant does the same with the corresponding elements from
any number of arrays. If the arrays' shapes are not the same, they are @tech{broadcast} first.
@examples[#:eval typed-eval
(array-count zero? (array #[#[0 1 0 2] #[0 3 -1 4]]))
(array-count equal?
(array #[#[0 1] #[2 3] #[0 1] #[2 3]])
(array #[0 1]))]
}
@deftogether[(@defproc[(array-axis-and [arr (Array A)] [k Integer]) (Array (U A Boolean))]
@defproc[(array-axis-or [arr (Array A)] [k Integer]) (Array (U A #f))])]{
Apply @racket[and] or @racket[or] to each row in axis @racket[k] of array @racket[arr], using
short-cut evaluation.
Consider the following array, whose second element takes 10 seconds to compute:
@interaction[#:eval typed-eval
(define arr (build-array #(2) (λ: ([js : Indexes])
(cond [(zero? (vector-ref js 0)) #f]
[else (sleep 10)
#t]))))]
Printing it takes over 10 seconds, but this returns immediately:
@interaction[#:eval typed-eval
(array-axis-and arr 0)]
}
@deftogether[(@defproc[(array-all-and [arr (Array A)]) (U A Boolean)]
@defproc[(array-all-or [arr (Array A)]) (U A #f)])]{
Apply @racket[and] or @racket[or] to each element in @racket[arr] using short-cut evaluation.
@racket[(array-all-and arr)] is defined as
@racketblock[(array-ref (array-fold arr array-axis-and) #())]
and @racket[array-all-or] is defined similarly.
@examples[#:eval typed-eval
(define arr (index-array #(3 3)))
(array-all-and (array= arr arr))
(define brr (array+ arr (array 1)))
(array-all-and (array= arr brr))
(array-all-or (array= arr (array 0)))]
}
@defproc[(array-axis-reduce [arr (Array A)] [k Integer] [h (Index (Integer -> A) -> B)]) (Array B)]{
Like @racket[array-axis-fold], but allows evaluation control (such as short-cutting @racket[and] and
@racket[or]) by moving the loop into @racket[h]. The result has the shape of @racket[arr], but with
axis @racket[k] removed.
The arguments to @racket[h] are the length of axis @racket[k] and a procedure that retrieves
elements from that axis's rows by their indexes in axis @racket[k]. It should return the elements
of the resulting array.
For example, summing the squares of the rows in axis @racket[1]:
@interaction[#:eval typed-eval
(define arr (index-array #(3 3)))
arr
(array-axis-reduce
arr 1
(λ: ([dk : Index] [proc : (Integer -> Real)])
(for/fold: ([s : Real 0]) ([jk (in-range dk)])
(+ s (sqr (proc jk))))))
(array-axis-sum (array-map sqr arr) 1)]
Every fold, including @racket[array-axis-fold], is ultimately defined using
@racket[array-axis-reduce] or its unsafe counterpart.
}
@;{==================================================================================================}
@section{Other Array Operations}
@;{array-fft
array-inverse-fft
array-axis-fft
array-axis-inverse-fft
}
@;{==================================================================================================}
@section{Subtypes}
@subsection{Flonum Arrays}
@ -1382,7 +1588,7 @@ array-axis-inverse-fft
}
@defproc[(array->flarray [arr (Array Real)]) FlArray]{
Returns an flarray that has approximately the same elements as @racket[arr].
Returns an flonum array that has approximately the same elements as @racket[arr].
The elements may lose precision during the conversion.
}
@ -1429,7 +1635,7 @@ flarray>=
}
@defproc[(array->fcarray [arr (Array Number)]) FCArray]{
Returns an fcarray that has approximately the same elements as @racket[arr].
Returns a float-complex array that has approximately the same elements as @racket[arr].
The elements may lose precision during the conversion.
}
@ -1466,6 +1672,10 @@ fcarray-asin
fcarray-atan
}
@;{==================================================================================================}
@section{Unsafe Operations}
@;{
@ -1481,6 +1691,7 @@ unsafe-build-array
unsafe-mutable-array
unsafe-flarray
unsafe-array-transform
unsafe-array-axis-reduce
}
@;{