racket/collects/math/tests/array-tests.rkt
Neil Toronto 986e695bd5 Made arrays strict by default; please merge to release
* Added parameter `array-strictness', default #t

* Added `array-default-strict!' and `array-default-strict', which act
  like the functions without "default" in the name when
  `array-strictness' is #t; otherwise they do nothing

* Lots of small changes to existing array functions, mostly to ensure
  computations are done using nonstrict arrays, but return values are
  strict when `array-strictness' is #t

* Added strictness tests

* Added tests to ensure untyped code can use `math/array'

* Rewrote `array-map' exported to untyped code using untyped Racket

* Rearranged a lot of `math/array' documentation
2013-01-15 13:53:28 -07:00

1010 lines
42 KiB
Racket

#lang typed/racket
(require racket/flonum
math/array
(rename-in
(except-in typed/rackunit check-eq?)
[check-equal? old:check-equal?])
math/private/array/utils)
(define-predicate listof-index? (Listof Index))
(define-predicate listof-flonum? (Listof Float))
(define-predicate undefined? Undefined)
;; This gets around the fact that typed/rackunit can no longer test higher-order values for equality,
;; since TR has firmed up its rules on passing `Any' types in and out of untyped code
(define-syntax-rule (check-equal? a b . message)
(check-true (equal? a b) . message))
(define-syntax-rule (check-eq? a b . message)
(check-equal? (eq-hash-code a) (eq-hash-code b) . message))
(define-syntax-rule (array-axis-andmap arr k pred?)
(array-axis-and (array-map pred? arr) k))
(define-syntax-rule (array-axis-ormap arr k pred?)
(array-axis-or (array-map pred? arr) k))
;; ---------------------------------------------------------------------------------------------------
;; array-mutable
(: make-indexes-vector (Integer Integer -> (Vectorof (Vectorof Integer))))
(define (make-indexes-vector n dims)
(list->vector
((inst map (Vectorof Integer) (Listof Integer))
list->vector
(let: loop : (Listof (Listof Integer)) ([n : Integer n])
(cond [(= n 0) (list null)]
[else (define lsts (loop (- n 1)))
(append* (for/list: : (Listof (Listof (Listof Integer))) ([k (in-range dims)])
(map (λ: ([lst : (Listof Integer)]) (cons k lst)) lsts)))])))))
(check-equal? (make-indexes-vector 2 3)
#(#(0 0) #(0 1) #(0 2) #(1 0) #(1 1) #(1 2) #(2 0) #(2 1) #(2 2)))
(let ([arr (vector->array #(4) #(a b c d))])
(check-eq? arr (array-strict arr)))
(let ([arr (build-array #() (λ (js) 'foo))])
(check-equal? (mutable-array-data (array->mutable-array arr))
#(foo)))
(let ([arr ((inst build-array Float) #(4) (λ (js) (exact->inexact (vector-ref js 0))))])
(check-equal? (mutable-array-data (array->mutable-array arr))
#(0.0 1.0 2.0 3.0)))
(let ([arr ((inst build-array Float) #(0) (λ (js) (exact->inexact (vector-ref js 0))))])
(check-equal? (mutable-array-data (array->mutable-array arr))
#()))
(let ([arr (build-array #(3 3) (λ (js) js))])
(check-equal? (mutable-array-data (array->mutable-array arr))
(make-indexes-vector 2 3)))
(let ([arr (build-array #(2 2 2) (λ (js) js))])
(check-equal? (mutable-array-data (array->mutable-array arr))
(make-indexes-vector 3 2)))
(let ([arr (build-array #(2 2 2 2) (λ (js) js))])
(check-equal? (mutable-array-data (array->mutable-array arr))
(make-indexes-vector 4 2)))
(let ([arr (build-array #(2 2 2 2 2) (λ (js) js))])
(check-equal? (mutable-array-data (array->mutable-array arr))
(make-indexes-vector 5 2)))
(let ([arr (build-array #(2 2 2 2 2 2) (λ (js) js))])
(check-equal? (mutable-array-data (array->mutable-array arr))
(make-indexes-vector 6 2)))
;; ---------------------------------------------------------------------------------------------------
;; list*->array
(check-equal? (list*->array 1.0 flonum?)
(vector->array #() #(1.0)))
(check-equal? (list*->array '[] flonum?)
(vector->array #(0) #()))
(check-equal? (list*->array '[[]] flonum?)
(vector->array #(1 0) #()))
(check-equal? (list*->array '[1.0] flonum?)
(vector->array #(1) #(1.0)))
(check-equal? (list*->array '[[1.0]] flonum?)
(vector->array #(1 1) #(1.0)))
(check-equal? (list*->array '[[[1.0]]] flonum?)
(vector->array #(1 1 1) #(1.0)))
(check-equal? (list*->array '() listof-flonum?)
(vector->array #() #(())))
(check-equal? (list*->array '[()] listof-flonum?)
(vector->array #(1) #(())))
(check-equal? (list*->array '[(1.0) (2.0)] listof-flonum?)
(vector->array #(2) #((1.0) (2.0))))
(check-equal? (list*->array '[((1.0)) ((2.0))] listof-flonum?)
(vector->array #(2 1) #((1.0) (2.0))))
;; ---------------------------------------------------------------------------------------------------
;; array->list*
(let ([arr (build-array #() (λ (js) 'foo))])
(check-equal? (array->list* arr) 'foo)
(check-equal? arr (list*->array (array->list* arr) symbol?)))
(let ([arr ((inst build-array Float) #(4) (λ (js) (exact->inexact (vector-ref js 0))))])
(check-equal? (array->list* arr) '[0.0 1.0 2.0 3.0])
(check-equal? arr (list*->array (array->list* arr) flonum?)))
(let ([arr (build-array #(3 3) (inst vector->list Index))])
(check-equal? (array->list* arr) '[[(0 0) (0 1) (0 2)]
[(1 0) (1 1) (1 2)]
[(2 0) (2 1) (2 2)]])
(check-equal? arr (list*->array (array->list* arr) listof-index?)))
(let ([arr (build-array #(2 2 2) (inst vector->list Index))])
(check-equal? (array->list* arr)
'[[[(0 0 0) (0 0 1)] [(0 1 0) (0 1 1)]]
[[(1 0 0) (1 0 1)] [(1 1 0) (1 1 1)]]])
(check-equal? arr (list*->array (array->list* arr) listof-index?)))
(let ([arr (build-array #(2 2 2 2) (inst vector->list Index))])
(check-equal? (array->list* arr)
'[[[[(0 0 0 0) (0 0 0 1)] [(0 0 1 0) (0 0 1 1)]]
[[(0 1 0 0) (0 1 0 1)] [(0 1 1 0) (0 1 1 1)]]]
[[[(1 0 0 0) (1 0 0 1)] [(1 0 1 0) (1 0 1 1)]]
[[(1 1 0 0) (1 1 0 1)] [(1 1 1 0) (1 1 1 1)]]]])
(check-equal? arr (list*->array (array->list* arr) listof-index?)))
(check-equal? (array->list* (list*->array '[1.0 2.0] flonum?))
'[1.0 2.0])
(check-equal? (array->list* (list*->array '[[1.0 2.0] [3.0 4.0]] flonum?))
'[[1.0 2.0] [3.0 4.0]])
;; ---------------------------------------------------------------------------------------------------
;; vector*->array
(check-equal? (vector*->array 1.0 flonum?)
(vector->array #() #(1.0)))
(check-equal? ((inst vector*->array Float) #() flonum?)
(vector->array #(0) #()))
(check-equal? ((inst vector*->array Float) #(#()) flonum?)
(vector->array #(1 0) #()))
(check-equal? ((inst vector*->array Float) #(1.0) flonum?)
(vector->array #(1) #(1.0)))
(check-equal? ((inst vector*->array Float) #(#(1.0)) flonum?)
(vector->array #(1 1) #(1.0)))
(check-equal? ((inst vector*->array Float) #(#(#(1.0))) flonum?)
(vector->array #(1 1 1) #(1.0)))
;; ---------------------------------------------------------------------------------------------------
;; array->vector
(let ([arr (build-array #() (λ (js) 'foo))])
(check-equal? (array->vector* arr) 'foo)
(check-equal? arr (vector*->array (array->vector* arr) symbol?)))
(let ([arr ((inst build-array Float) #(4) (λ (js) (exact->inexact (vector-ref js 0))))])
(check-equal? (array->vector* arr) #(0.0 1.0 2.0 3.0))
(check-equal? arr (vector*->array (array->vector* arr) flonum?)))
(let ([arr (build-array #(3 3) (inst vector->list Index))])
(check-equal? (array->vector* arr) #[#[(0 0) (0 1) (0 2)]
#[(1 0) (1 1) (1 2)]
#[(2 0) (2 1) (2 2)]])
(check-equal? arr (vector*->array (array->vector* arr) listof-index?)))
(let ([arr (build-array #(2 2 2) (inst vector->list Index))])
(check-equal? (array->vector* arr)
#[#[#[(0 0 0) (0 0 1)] #[(0 1 0) (0 1 1)]]
#[#[(1 0 0) (1 0 1)] #[(1 1 0) (1 1 1)]]])
(check-equal? arr (vector*->array (array->vector* arr) listof-index?)))
(let ([arr (build-array #(2 2 2 2) (inst vector->list Index))])
(check-equal? (array->vector* arr)
#[#[#[#[(0 0 0 0) (0 0 0 1)] #[(0 0 1 0) (0 0 1 1)]]
#[#[(0 1 0 0) (0 1 0 1)] #[(0 1 1 0) (0 1 1 1)]]]
#[#[#[(1 0 0 0) (1 0 0 1)] #[(1 0 1 0) (1 0 1 1)]]
#[#[(1 1 0 0) (1 1 0 1)] #[(1 1 1 0) (1 1 1 1)]]]])
(check-equal? arr (vector*->array (array->vector* arr) listof-index?)))
(check-equal? (array->vector* ((inst vector*->array Flonum) #[1.0 2.0] flonum?))
#[1.0 2.0])
(check-equal? (array->vector* ((inst vector*->array Flonum) #[#[1.0 2.0] #[3.0 4.0]] flonum?))
#[#[1.0 2.0] #[3.0 4.0]])
;; ---------------------------------------------------------------------------------------------------
;; Array syntax
(check-equal? (array 1.0)
(list*->array 1.0 flonum?))
(check-equal? (array #[])
(list*->array '[] flonum?))
(check-equal? (array #[#[]])
(list*->array '[[]] flonum?))
(check-equal? (array #[1.0])
(list*->array '[1.0] flonum?))
(check-equal? (array #[#[1.0]])
(list*->array '[[1.0]] flonum?))
(check-equal? (array #[#[#[1.0]]])
(list*->array '[[[1.0]]] flonum?))
(check-equal? (mutable-array 1.0)
(list*->array 1.0 flonum?))
(check-equal? (mutable-array #[])
(list*->array '[] flonum?))
(check-equal? (mutable-array #[#[]])
(list*->array '[[]] flonum?))
(check-equal? (mutable-array #[1.0])
(list*->array '[1.0] flonum?))
(check-equal? (mutable-array #[#[1.0]])
(list*->array '[[1.0]] flonum?))
(check-equal? (mutable-array #[#[#[1.0]]])
(list*->array '[[[1.0]]] flonum?))
;; ---------------------------------------------------------------------------------------------------
;; Other constructors
(check-equal? (make-array #(3 3) 0)
(build-array #(3 3) (λ (js) 0)))
(check-equal? (axis-index-array #(3 3) 0)
(build-array #(3 3) (λ: ([js : Indexes]) (vector-ref js 0))))
(check-exn exn? (λ () (axis-index-array #(3 3) -1)))
(check-exn exn? (λ () (axis-index-array #() 0)))
(check-equal? (index-array #()) (array 0))
(check-equal? (index-array #(4)) (array #[0 1 2 3]))
(check-equal? (index-array #(2 2)) (array #[#[0 1] #[2 3]]))
(check-equal? (indexes-array #(3 3))
(build-array #(3 3) (λ: ([js : Indexes]) (vector-copy js))))
(check-equal? (diagonal-array 0 0 1.0 0.0)
(array 1.0))
(check-equal? (diagonal-array 1 0 1.0 0.0)
(array #[]))
(check-equal? (diagonal-array 1 1 1.0 0.0)
(array #[1.0]))
(check-equal? (diagonal-array 2 1 1.0 0.0)
(array #[#[1.0]]))
(check-equal? (diagonal-array 2 2 1.0 0.0)
(array #[#[1.0 0.0] #[0.0 1.0]]))
(check-equal? (diagonal-array 3 2 1.0 0.0)
(array #[#[#[1.0 0.0] #[0.0 0.0]]
#[#[0.0 0.0] #[0.0 1.0]]]))
;; ---------------------------------------------------------------------------------------------------
;; Pointwise
;; Not much to test here because most pointwise ops are defined by the same two lifts
(check-equal? (array-sqrt (array #[1.0 4.0 9.0 16.0]))
(array #[1.0 2.0 3.0 4.0]))
(check-equal? (array+ (array #[1.0 2.0])
(array #[10.0 20.0]))
(array #[11.0 22.0]))
(check-equal? (array-map inexact->exact (array #[1.0 2.0]))
(array #[1 2]))
(check-equal? (array-map (inst cons Float Float)
(array #[1.0 2.0])
(array #[10.0 20.0]))
(vector->array #(2) #[(1.0 . 10.0) (2.0 . 20.0)]))
;; ---------------------------------------------------------------------------------------------------
;; Fold
(let ([arr (array #[#[ 1.0 4.0 9.0 16.0]
#[-1.0 -4.0 -9.0 -16.0]])])
(check-equal? (array-axis-sum arr 0) (array #[0.0 0.0 0.0 0.0]))
(check-equal? (array-axis-prod arr 0) (array #[-1.0 -16.0 -81.0 -256.0]))
(check-equal? (array-axis-min arr 0) (array #[-1.0 -4.0 -9.0 -16.0]))
(check-equal? (array-axis-max arr 0) (array #[ 1.0 4.0 9.0 16.0]))
(check-equal? (array-axis-fold arr 0 (inst cons Float (Listof Float)) null)
(list*->array '[[-1.0 1.0] [-4.0 4.0] [-9.0 9.0] [-16.0 16.0]]
listof-flonum?))
(check-equal? (array-axis-sum arr 1) (array #[30.0 -30.0]))
(check-equal? (array-axis-prod arr 1) (array #[576.0 576.0]))
(check-equal? (array-axis-min arr 1) (array #[1.0 -16.0]))
(check-equal? (array-axis-max arr 1) (array #[16.0 -1.0]))
(check-equal? (array-axis-fold arr 1 (inst cons Float (Listof Float)) null)
(list*->array '[[ 16.0 9.0 4.0 1.0]
[-16.0 -9.0 -4.0 -1.0]]
listof-flonum?))
(check-equal? (array-all-sum arr) 0.0)
(check-equal? (array-all-prod arr) (* 576.0 576.0))
(check-equal? (array-all-min arr) -16.0)
(check-equal? (array-all-max arr) 16.0))
(let ([arr (make-array #(3 0) 0)])
(check-equal? (array-axis-sum arr 0) (array #[]))
(check-equal? (array-axis-prod arr 0) (array #[]))
(check-equal? (array-axis-min arr 0) (array #[]))
(check-equal? (array-axis-max arr 0) (array #[]))
(check-exn exn? (λ () (array-axis-sum arr 1)))
(check-exn exn? (λ () (array-axis-prod arr 1)))
(check-exn exn? (λ () (array-axis-min arr 1)))
(check-exn exn? (λ () (array-axis-max arr 1)))
(check-equal? (array-axis-sum arr 1 0) (array #[0 0 0]))
(check-equal? (array-axis-min arr 1 +inf.0) (array #[+inf.0 +inf.0 +inf.0]))
(check-equal? (array-axis-max arr 1 -inf.0) (array #[-inf.0 -inf.0 -inf.0]))
(check-equal? (array-axis-prod arr 1 1) (array #[1 1 1]))
(check-exn exn? (λ () (array-all-sum arr)))
(check-exn exn? (λ () (array-all-prod arr)))
(check-exn exn? (λ () (array-all-min arr)))
(check-exn exn? (λ () (array-all-max arr)))
(check-equal? (array-all-sum arr 0) 0)
(check-equal? (array-all-prod arr 1) 1)
(check-equal? (array-all-min arr +inf.0) +inf.0)
(check-equal? (array-all-max arr -inf.0) -inf.0))
(let ([arr (make-array #() 0)])
(check-exn exn? (λ () (array-axis-sum arr 0)))
(check-exn exn? (λ () (array-axis-prod arr 0)))
(check-exn exn? (λ () (array-axis-min arr 0)))
(check-exn exn? (λ () (array-axis-max arr 0)))
(check-equal? (array-all-sum arr) 0)
(check-equal? (array-all-prod arr) 0)
(check-equal? (array-all-min arr) 0)
(check-equal? (array-all-max arr) 0))
(let ([arr (array #[#[1.0 1.0 2.0 3.0] #[0.0 -1.0 2.0 3.0]])])
(check-equal? (array-axis-count arr 0 positive?) (array #[1 1 2 2]))
(check-equal? (array-axis-count arr 1 positive?) (array #[4 2]))
(check-equal? (array-count positive? arr) 6))
(let ([arr (array #[#[1.0 1.0 2.0 3.0] #[0.0 -1.0 2.0 3.0]])])
(check-equal? (array-axis-andmap arr 0 positive?) (array #[#f #f #t #t]))
(check-equal? (array-axis-andmap arr 1 positive?) (array #[#t #f]))
(check-equal? (array-andmap positive? arr) #f))
(let ([arr (array #[#[1.0 1.0 2.0 3.0] #[2.0 3.0 2.0 3.0]])])
(check-equal? (array-axis-andmap arr 0 positive?) (array #[#t #t #t #t]))
(check-equal? (array-axis-andmap arr 1 positive?) (array #[#t #t]))
(check-equal? (array-andmap positive? arr) #t))
(let ([arr (array #[#[-1.0 -1.0 -2.0 -3.0] #[0.0 -1.0 2.0 3.0]])])
(check-equal? (array-axis-ormap arr 0 positive?) (array #[#f #f #t #t]))
(check-equal? (array-axis-ormap arr 1 positive?) (array #[#f #t]))
(check-equal? (array-ormap positive? arr) #t))
(let ([arr (array #[#[-1.0 -1.0 -2.0 -3.0] #[-2.0 -3.0 -2.0 -3.0]])])
(check-equal? (array-axis-ormap arr 0 positive?) (array #[#f #f #f #f]))
(check-equal? (array-axis-ormap arr 1 positive?) (array #[#f #f]))
(check-equal? (array-ormap positive? arr) #f))
(let ([arr (make-array #() 0.0)])
(check-equal? (array-count positive? arr) 0)
(check-equal? (array-andmap positive? arr) #f)
(check-equal? (array-ormap positive? arr) #f))
(let ([arr (make-array #() 1.0)])
(check-equal? (array-count positive? arr) 1)
(check-equal? (array-andmap positive? arr) #t)
(check-equal? (array-ormap positive? arr) #t))
(let ([arr (make-array #(4 0) 0.0)])
(check-equal? (array-axis-count arr 0 positive?) (array #[]))
(check-equal? (array-axis-andmap arr 0 positive?) (array #[]))
(check-equal? (array-axis-ormap arr 0 positive?) (array #[]))
(check-equal? (array-axis-count arr 1 positive?) (array #[0 0 0 0]))
(check-equal? (array-axis-andmap arr 1 positive?) (array #[#t #t #t #t]))
(check-equal? (array-axis-ormap arr 1 positive?) (array #[#f #f #f #f]))
(check-equal? (array-count positive? arr) 0)
(check-equal? (array-andmap positive? arr) #t)
(check-equal? (array-ormap positive? arr) #f))
;; ---------------------------------------------------------------------------------------------------
;; FFT
(check-exn exn? (λ () (array-fft (make-array #() 1))))
(check-exn exn? (λ () (array-fft (make-array #(0) 1))))
(check-exn exn? (λ () (array-fft (make-array #(3) 1))))
(let ([arr (make-array #(4) 1)])
(check-true (array-all-and (array= (array-fft arr) (array #[4 0 0 0]))))
(check-true (array-all-and (array= (array-inverse-fft (array-fft arr)) arr))))
(let ([arr (make-array #(2 2) 1)])
(check-true (array-all-and (array= (array-fft arr) (array #[#[4 0] #[0 0]]))))
(check-true (array-all-and (array= (array-inverse-fft (array-fft arr)) arr))))
;; ---------------------------------------------------------------------------------------------------
;; Unsafe ref
(check-equal? (unsafe-array-ref (make-array #() 0) (vector)) 0)
(let* ([arr (indexes-array #(2))])
(check-equal? (unsafe-array-ref arr ((inst vector Index) 0)) #(0))
(check-equal? (unsafe-array-ref arr ((inst vector Index) 1)) #(1)))
(let* ([arr (indexes-array #(2 2))])
(check-equal? (unsafe-array-ref arr ((inst vector Index) 0 0)) #(0 0))
(check-equal? (unsafe-array-ref arr ((inst vector Index) 1 1)) #(1 1)))
;; ---------------------------------------------------------------------------------------------------
;; Unsafe set!
(let* ([arr ((inst array->mutable-array Byte) (make-array #() 0))]
[idxs (vector)])
(unsafe-array-set! arr (vector) 1)
(check-equal? (unsafe-array-ref arr #()) 1)
(unsafe-array-set! arr #() 2)
(check-equal? (unsafe-array-ref arr #()) 2)
(unsafe-array-set! arr idxs 3)
(check-equal? (unsafe-array-ref arr #()) 3))
(let* ([arr (array->mutable-array (indexes-array #(2)))]
[idxs0 ((inst vector Index) 0)]
[idxs1 ((inst vector Index) 1)])
(unsafe-array-set! arr idxs0 ((inst vector Index) 6))
(unsafe-array-set! arr idxs1 ((inst vector Index) 7))
(check-equal? (unsafe-array-ref arr idxs0) #(6))
(check-equal? (unsafe-array-ref arr idxs1) #(7)))
(let* ([arr (array->mutable-array (indexes-array #(2 2)))]
[idxs0 ((inst vector Index) 0 0)]
[idxs1 ((inst vector Index) 1 1)])
(unsafe-array-set! arr idxs0 ((inst vector Index) 6 6))
(unsafe-array-set! arr idxs1 ((inst vector Index) 7 7))
(check-equal? (unsafe-array-ref arr idxs0) #(6 6))
(check-equal? (unsafe-array-ref arr idxs1) #(7 7)))
;; ---------------------------------------------------------------------------------------------------
;; Safe ref
(let* ([l-arr (make-array #() 0)]
[s-arr (array->mutable-array l-arr)]
[idxs #()]
[bad-idxs #(1)])
(check-equal? (array-ref l-arr (vector)) 0)
(check-equal? (array-ref s-arr (vector)) 0)
(check-equal? (array-ref l-arr #()) 0)
(check-equal? (array-ref s-arr #()) 0)
(check-equal? (array-ref l-arr idxs) 0)
(check-equal? (array-ref s-arr idxs) 0)
(check-exn exn? (λ () (array-ref l-arr (vector 1))))
(check-exn exn? (λ () (array-ref s-arr (vector 1))))
(check-exn exn? (λ () (array-ref l-arr #(1))))
(check-exn exn? (λ () (array-ref s-arr #(1))))
(check-exn exn? (λ () (array-ref l-arr bad-idxs)))
(check-exn exn? (λ () (array-ref s-arr bad-idxs))))
(let* ([l-arr (indexes-array #(2))]
[s-arr (array->mutable-array l-arr)]
[idxs0 #(0)]
[idxs1 #(1)]
[bad-idxs0 #(0 0)]
[bad-idxs1 #(-1)]
[bad-idxs2 #( 2)])
(check-equal? (array-ref l-arr (vector 0)) #(0))
(check-equal? (array-ref s-arr (vector 0)) #(0))
(check-equal? (array-ref l-arr (vector 1)) #(1))
(check-equal? (array-ref s-arr (vector 1)) #(1))
(check-equal? (array-ref l-arr #(0)) #(0))
(check-equal? (array-ref s-arr #(0)) #(0))
(check-equal? (array-ref l-arr #(1)) #(1))
(check-equal? (array-ref s-arr #(1)) #(1))
(check-equal? (array-ref l-arr idxs0) #(0))
(check-equal? (array-ref s-arr idxs0) #(0))
(check-equal? (array-ref l-arr idxs1) #(1))
(check-equal? (array-ref s-arr idxs1) #(1))
(check-exn exn? (λ () (array-ref l-arr (vector 0 0))))
(check-exn exn? (λ () (array-ref s-arr (vector 0 0))))
(check-exn exn? (λ () (array-ref l-arr (vector -1))))
(check-exn exn? (λ () (array-ref s-arr (vector -1))))
(check-exn exn? (λ () (array-ref l-arr (vector 2))))
(check-exn exn? (λ () (array-ref s-arr (vector 2))))
(check-exn exn? (λ () (array-ref l-arr #(0 0))))
(check-exn exn? (λ () (array-ref s-arr #(0 0))))
(check-exn exn? (λ () (array-ref l-arr #(-1))))
(check-exn exn? (λ () (array-ref s-arr #(-1))))
(check-exn exn? (λ () (array-ref l-arr #(2))))
(check-exn exn? (λ () (array-ref s-arr #(2))))
(check-exn exn? (λ () (array-ref l-arr bad-idxs0)))
(check-exn exn? (λ () (array-ref s-arr bad-idxs0)))
(check-exn exn? (λ () (array-ref l-arr bad-idxs1)))
(check-exn exn? (λ () (array-ref s-arr bad-idxs1)))
(check-exn exn? (λ () (array-ref l-arr bad-idxs2)))
(check-exn exn? (λ () (array-ref s-arr bad-idxs2))))
(let* ([l-arr (indexes-array #(2 2))]
[s-arr (array->mutable-array l-arr)]
[idxs0 #(0 0)]
[idxs1 #(1 1)])
(check-equal? (array-ref l-arr (vector 0 0)) #(0 0))
(check-equal? (array-ref s-arr (vector 0 0)) #(0 0))
(check-equal? (array-ref l-arr (vector 1 1)) #(1 1))
(check-equal? (array-ref s-arr (vector 1 1)) #(1 1))
(check-equal? (array-ref l-arr #(0 0)) #(0 0))
(check-equal? (array-ref s-arr #(0 0)) #(0 0))
(check-equal? (array-ref l-arr #(1 1)) #(1 1))
(check-equal? (array-ref s-arr #(1 1)) #(1 1))
(check-equal? (array-ref l-arr idxs0) #(0 0))
(check-equal? (array-ref s-arr idxs0) #(0 0))
(check-equal? (array-ref l-arr idxs1) #(1 1))
(check-equal? (array-ref s-arr idxs1) #(1 1)))
;; ---------------------------------------------------------------------------------------------------
;; Safe set!
(let* ([arr ((inst array->mutable-array Byte) (make-array #() 0))]
[idxs #()]
[bad-idxs #(1)])
(array-set! arr (vector) 1)
(check-equal? (array-ref arr #()) 1)
(array-set! arr #() 2)
(check-equal? (array-ref arr #()) 2)
(array-set! arr idxs 3)
(check-equal? (array-ref arr #()) 3)
(check-exn exn? (λ () (array-set! arr (vector 1) 2)))
(check-exn exn? (λ () (array-set! arr #(1) 2)))
(check-exn exn? (λ () (array-set! arr bad-idxs 2))))
(let* ([arr (array->mutable-array (indexes-array #(2)))]
[idxs0 #(0)]
[idxs1 #(1)]
[bad-idxs0 #(0 0)]
[bad-idxs1 #(-1)]
[bad-idxs2 #(2)]
[one ((inst vector Index) 1)])
(array-set! arr (vector 0) ((inst vector Index) 2))
(array-set! arr (vector 1) ((inst vector Index) 3))
(check-equal? (array-ref arr #(0)) #(2))
(check-equal? (array-ref arr #(1)) #(3))
(array-set! arr #(0) ((inst vector Index) 4))
(array-set! arr #(1) ((inst vector Index) 5))
(check-equal? (array-ref arr #(0)) #(4))
(check-equal? (array-ref arr #(1)) #(5))
(array-set! arr idxs0 ((inst vector Index) 6))
(array-set! arr idxs1 ((inst vector Index) 7))
(check-equal? (array-ref arr #(0)) #(6))
(check-equal? (array-ref arr #(1)) #(7))
(check-exn exn? (λ () (array-set! arr (vector 0 0) one)))
(check-exn exn? (λ () (array-set! arr (vector -1) one)))
(check-exn exn? (λ () (array-set! arr (vector 2) one)))
(check-exn exn? (λ () (array-set! arr #(0 0) one)))
(check-exn exn? (λ () (array-set! arr #(-1) one)))
(check-exn exn? (λ () (array-set! arr #(2) one)))
(check-exn exn? (λ () (array-set! arr bad-idxs0 one)))
(check-exn exn? (λ () (array-set! arr bad-idxs1 one)))
(check-exn exn? (λ () (array-set! arr bad-idxs2 one))))
(let* ([arr (array->mutable-array (indexes-array #(2 2)))]
[idxs0 #(0 0)]
[idxs1 #(1 1)])
(array-set! arr (vector 0 0) ((inst vector Index) 2 2))
(array-set! arr (vector 1 1) ((inst vector Index) 3 3))
(check-equal? (array-ref arr #(0 0)) #(2 2))
(check-equal? (array-ref arr #(1 1)) #(3 3))
(array-set! arr #(0 0) ((inst vector Index) 4 4))
(array-set! arr #(1 1) ((inst vector Index) 5 5))
(check-equal? (array-ref arr #(0 0)) #(4 4))
(check-equal? (array-ref arr #(1 1)) #(5 5))
(array-set! arr idxs0 ((inst vector Index) 6 6))
(array-set! arr idxs1 ((inst vector Index) 7 7))
(check-equal? (array-ref arr #(0 0)) #(6 6))
(check-equal? (array-ref arr #(1 1)) #(7 7)))
;; ---------------------------------------------------------------------------------------------------
;; Indexing
(let ([arr (mutable-array #[#[0 1 2 3 4 5]
#[1 2 3 4 5 6]
#[2 3 4 5 6 7]
#[3 4 5 6 7 8]]
: (U Integer Symbol))]
[idxs (array #['#(0 0) '#(1 1) '#(1 2) '#(2 3) '#(3 4) '#(3 5)])]
[vals (array #['a 'b 'c 'd 'e 'f])]
[slices (list (:: 0 4 2) (:: 2 -1 -2))])
(check-equal? (array-indexes-ref arr idxs)
(array #[0 2 3 5 7 8]))
(check-equal? (array-indexes-ref arr (array-slice-ref (indexes-array (array-shape arr)) slices))
(array-slice-ref arr slices))
(array-indexes-set! arr idxs vals)
(check-equal? arr (array #[#['a 1 2 3 4 5]
#[1 'b 'c 4 5 6]
#[2 3 4 'd 6 7]
#[3 4 5 6 'e 'f]])))
(check-equal? (array-slice-ref (indexes-array #()) (list (::new 2)))
(make-array #(2) #()))
(let ([arr (indexes-array #(2))])
(check-equal? (array-slice-ref arr (list (::) (::new 2)))
(array #[#['#(0) '#(0)] #['#(1) '#(1)]]))
(check-equal? (array-slice-ref arr (list (::new 2) (::)))
(array #[#['#(0) '#(1)] #['#(0) '#(1)]]))
(check-equal? (array-slice-ref arr (list (::)))
arr)
(check-equal? (array-slice-ref arr (list ::...))
arr))
(let ([arr (index-array #(10))])
(check-equal? (array-slice-ref arr (list (:: 0 10 2)))
(array #[0 2 4 6 8]))
(check-equal? (array-slice-ref arr (list (:: #f 10 2)))
(array #[0 2 4 6 8]))
(check-equal? (array-slice-ref arr (list (:: 0 #f 2)))
(array #[0 2 4 6 8]))
(check-equal? (array-slice-ref arr (list (:: #f #f 2)))
(array #[0 2 4 6 8]))
(check-equal? (array-slice-ref arr (list (:: 9 -1 -2)))
(array #[9 7 5 3 1]))
(check-equal? (array-slice-ref arr (list (:: 9 #f -2)))
(array #[9 7 5 3 1]))
(check-equal? (array-slice-ref arr (list (:: #f -1 -2)))
(array #[9 7 5 3 1]))
(check-equal? (array-slice-ref arr (list (:: #f #f -2)))
(array #[9 7 5 3 1]))
(check-equal? (array-slice-ref arr (list 4))
(array 4))
(check-exn exn? (λ () (array-slice-ref arr (list -1))))
(check-exn exn? (λ () (array-slice-ref arr (list 10))))
(check-exn exn? (λ () (array-slice-ref arr (list (:: 0 11 2)))))
(check-exn exn? (λ () (array-slice-ref arr (list (:: -1 10 2)))))
(check-exn exn? (λ () (array-slice-ref arr (list (:: 10 -1 -2)))))
(check-exn exn? (λ () (array-slice-ref arr (list (:: 9 -2 -2))))))
(let ([arr (index-array #(4 4))])
(check-equal? (array-slice-ref arr (list ::...))
arr)
(check-equal? (array-slice-ref arr (list (:: 0 4 2) (:: 0 4 2)))
(array #[#[0 2] #[8 10]]))
(check-equal? (array-slice-ref arr (list (:: 0 4 2) ::...))
(array #[#[0 1 2 3] #[8 9 10 11]]))
(check-equal? (array-slice-ref arr (list ::... (:: 0 4 2)))
(array #[#[0 2] #[4 6] #[8 10] #[12 14]]))
(check-equal? (array-slice-ref arr (list (:: 0 4 2) 0))
(array #[0 8]))
(check-equal? (array-slice-ref arr (list 0 (:: 0 4 2)))
(array #[0 2]))
(check-equal? (array-slice-ref arr (list (::new 0) ::...))
(make-array #(0 4 4) 0))
(check-equal? (array-slice-ref arr (list (::new 1) ::...))
(array-axis-insert arr 0 1))
(check-equal? (array-slice-ref arr (list (::) (::new 1) (::)))
(array-axis-insert arr 1 1))
(check-equal? (array-slice-ref arr (list (::) (::) (::new 1)))
(array-axis-insert arr 2 1)))
;; ---------------------------------------------------------------------------------------------------
;; Transforms
(check-equal? (array-transform (indexes-array #(4 2))
#(2 4) (λ: ([js : (Vectorof Index)])
(match-define (vector j0 j1) js)
(vector j1 j0)))
(array #[#['#(0 0) '#(1 0) '#(2 0) '#(3 0)]
#['#(0 1) '#(1 1) '#(2 1) '#(3 1)]]))
(check-exn exn? (λ () (array-strict (array-transform (indexes-array #(2 2)) #(3 3) identity))))
(check-exn exn? (λ () (array-strict (array-transform (indexes-array #(2 2)) #(2) identity))))
(check-equal? (unsafe-array-transform (indexes-array #(4 2))
((inst vector Index) 2 4)
(λ: ([js : (Vectorof Index)])
(match-define (vector j0 j1) js)
((inst vector Index) j1 j0)))
(array #[#['#(0 0) '#(1 0) '#(2 0) '#(3 0)]
#['#(0 1) '#(1 1) '#(2 1) '#(3 1)]]))
;; Permutation
(let ([arr (make-array #() 0)])
(check-equal? (array-axis-permute arr '())
(array 0))
(check-exn exn? (λ () (array-axis-permute arr '(0)))))
(let ([arr (indexes-array #(4))])
(check-exn exn? (λ () (array-axis-permute arr '())))
(check-equal? (array-axis-permute arr '(0)) arr)
(check-exn exn? (λ () (array-axis-permute arr '(1)))))
(let ([arr (indexes-array #(2 2))])
(check-exn exn? (λ () (array-axis-permute arr '())))
(check-equal? (array-axis-permute arr '(0 1)) arr)
(check-equal? (array-axis-permute arr '(1 0))
(array #[#['#(0 0) '#(1 0)]
#['#(0 1) '#(1 1)]])))
;; Transposition
(let ([arr (indexes-array #(4))])
(check-exn exn? (λ () (array-axis-swap arr 0 1)))
(check-equal? (array-axis-swap arr 0 0) arr))
(let ([arr (indexes-array #(2 2))])
(check-exn exn? (λ () (array-axis-swap arr 0 2)))
(check-equal? (array-axis-swap arr 0 0) arr)
(check-equal? (array-axis-swap arr 1 0)
(array #[#['#(0 0) '#(1 0)]
#['#(0 1) '#(1 1)]])))
(check-equal? (array-axis-swap (indexes-array #(2 2 2)) 1 2)
(array #[#[#['#(0 0 0) '#(0 1 0)]
#['#(0 0 1) '#(0 1 1)]]
#[#['#(1 0 0) '#(1 1 0)]
#['#(1 0 1) '#(1 1 1)]]]))
;; Adding axes
(let ([arr (indexes-array #())])
(check-exn exn? (λ () (array-axis-insert arr 1 1)))
(check-equal? (array-axis-insert arr 0 2)
(array #['#() '#()])))
(let ([arr (indexes-array #(4))])
(check-equal? (array-axis-insert arr 0 2)
(array #[#['#(0) '#(1) '#(2) '#(3)]
#['#(0) '#(1) '#(2) '#(3)]]))
(check-equal? (array-axis-insert arr 1 2)
(array #[#['#(0) '#(0)]
#['#(1) '#(1)]
#['#(2) '#(2)]
#['#(3) '#(3)]])))
;; Removing axes
(let ([arr (indexes-array #())])
(check-exn exn? (λ () (array-axis-ref arr 0 0))))
(let ([arr (indexes-array #(4))])
(check-exn exn? (λ () (array-axis-ref arr 1 0)))
(check-equal? (array-axis-ref arr 0 2)
(array '#(2))))
(let ([arr (indexes-array #(2 2))])
(check-equal? (array-axis-ref arr 0 0)
(array #['#(0 0) '#(0 1)]))
(check-equal? (array-axis-ref arr 1 0)
(array #['#(0 0) '#(1 0)])))
;; Reshape, flatten
(let ([arr (indexes-array #())])
(check-exn exn? (λ () (array-reshape arr #(0))))
(check-equal? (array-reshape arr #(1))
(array #['#()]))
(check-equal? (array-flatten arr)
(array #['#()])))
(let ([arr (array-map (λ: ([js : Indexes]) (vector-ref js 0))
(indexes-array #(4)))])
(check-exn exn? (λ () (array-reshape arr #())))
(check-equal? (array-reshape arr #(2 2))
(array #[#[0 1] #[2 3]]))
(check-equal? (array-flatten arr)
(array #[0 1 2 3])))
;; Append
(check-exn exn? (λ () (array-append* (list))))
(check-exn exn? (λ () (array-append* (list (array 0) (array 1)))))
(check-equal? (array-append* (list (array #[0])))
(array #[0]))
(check-equal? (array-append* (list (array #[0]) (array #[1])))
(array #[0 1]))
(check-equal? (array-append* (list (array #[0]) (array 1)))
(array #[0 1]))
(check-equal? (array-append* (list (array 0) (array #[1])))
(array #[0 1]))
(check-equal? (array-append* (list (array #[0 1 2]) (array #[3 4 5])))
(array #[0 1 2 3 4 5]))
(check-exn exn? (λ () (array-append* (list (array #[0]) (array #[1])) 1)))
(check-equal? (array-append* (list (array #[#[0 1] #[2 3]]) (array #[#[4 5] #[6 7]])))
(array #[#[0 1] #[2 3] #[4 5] #[6 7]]))
(check-equal? (array-append* (list (array #[#[0 1] #[2 3]]) (array #[#[4 5] #[6 7]])) 1)
(array #[#[0 1 4 5] #[2 3 6 7]]))
(check-equal? (array-append* (list (array #[#[0 1] #[2 3]]) (array 0)) 0)
(array #[#[0 1] #[2 3] #[0 0]]))
(check-equal? (array-append* (list (array #[#[0 1] #[2 3]]) (array 0)) 1)
(array #[#[0 1 0] #[2 3 0]]))
(check-equal? (array-append* (list (array #[#[0 1 2] #[3 4 5]]) (array #[0 1])) 1)
(array #[#[0 1 2 0 1] #[3 4 5 0 1]]))
(check-exn exn? (λ () (array-append* (list (array #[#[0 1 2] #[3 4 5]]) (array #[0 1])) 0)))
;; ---------------------------------------------------------------------------------------------------
;; Comprehensions
(check-equal? (for/array: #:shape #() () : Integer 3)
(mutable-array 3))
(check-equal? (for/array: #:shape #() () : Symbol 'foo)
(mutable-array 'foo))
(check-equal? (for/array: #:shape #(2) ([x (in-naturals)]) : Integer x)
(mutable-array #[0 1]))
(check-equal? (for/array: #:shape #(2 3) ([i (in-range 0 6)]) : (Vectorof Integer)
(vector (quotient i 3) (remainder i 3)))
(indexes-array #(2 3)))
(check-equal? (for*/array: #:shape #() () : Integer 3)
(mutable-array 3))
(check-equal? (for*/array: #:shape #() () : Symbol 'foo)
(mutable-array 'foo))
(check-equal? (for*/array: #:shape #(2) ([x (in-naturals)]) : Integer x)
(mutable-array #[0 1]))
(check-equal? (for*/array: #:shape #(2 3) ([i (in-range 0 2)]
[j (in-range 0 3)]
) : (Vectorof Integer)
(vector i j))
(indexes-array #(2 3)))
(check-equal? (for*/array: #:shape #() () : Integer 3)
(for*/array: #:shape #() () : Integer 3))
(check-equal? (for*/array: #:shape #() () : Symbol 'foo)
(for*/array: #:shape #() () : Symbol 'foo))
(check-equal? (for*/array: #:shape #(2) ([x (in-naturals)]) : Integer x)
(for*/array: #:shape #(2) ([x (in-naturals)]) : Integer x))
(check-equal? (for*/array: #:shape #(2 3) ([i (in-range 0 2)]
[j (in-range 0 3)]
) : (Listof Integer)
(list i j))
(for*/array: #:shape #(2 3) ([i (in-range 0 2)]
[j (in-range 0 3)]
) : (Listof Integer)
(list i j)))
;; ---------------------------------------------------------------------------------------------------
;; Sequences
(check-equal? (for/list: : (Listof Number) ([x (in-array (array #[#[1 2 3] #[4 5 6]]))]) x)
'(1 2 3 4 5 6))
(check-equal? (for/list: : (Listof Indexes) ([js (in-array (indexes-array #()))]) js)
'(#()))
(check-equal? (for/list: : (Listof Indexes) ([js (in-array (indexes-array #(0)))]) js)
'())
(check-equal? (for/list: : (Listof Indexes) ([js (in-array (indexes-array #(2 2)))]) js)
'(#(0 0) #(0 1) #(1 0) #(1 1)))
(check-equal? (sequence->list (in-array (indexes-array #())))
'(#()))
(check-equal? (sequence->list (in-array (indexes-array #(0))))
'())
(check-equal? (sequence->list (in-array (indexes-array #(2 2))))
'(#(0 0) #(0 1) #(1 0) #(1 1)))
(check-equal? (for/list: : (Listof Indexes) ([js (in-array-indexes #())]) js)
'(#()))
(check-equal? (for/list: : (Listof Indexes) ([js (in-array-indexes #(0))]) js)
'())
(check-equal? (for/list: : (Listof Indexes) ([js (in-array-indexes #(2 2))]) js)
'(#(0 0) #(0 1) #(1 0) #(1 1)))
(check-equal? (sequence->list (in-array-indexes #()))
'(#()))
(check-equal? (sequence->list (in-array-indexes #(0)))
'())
(check-equal? (sequence->list (in-array-indexes #(2 2)))
'(#(0 0) #(0 1) #(1 0) #(1 1)))
(check-equal? (for/list: : (Listof Indexes) ([js (in-unsafe-array-indexes #(2 2))]) js)
'(#(0 0) #(0 0) #(0 0) #(0 0)))
(check-equal? (for/list: : (Listof Indexes) ([js (in-unsafe-array-indexes #())]) (vector-copy js))
'(#()))
(check-equal? (for/list: : (Listof Indexes) ([js (in-unsafe-array-indexes #(0))]) (vector-copy js))
'())
(check-equal? (for/list: : (Listof Indexes) ([js (in-unsafe-array-indexes #(2 2))]) (vector-copy js))
'(#(0 0) #(0 1) #(1 0) #(1 1)))
(check-equal? (sequence->list (in-unsafe-array-indexes #()))
'(#()))
(check-equal? (sequence->list (in-unsafe-array-indexes #(0)))
'())
(check-equal? (sequence->list (in-unsafe-array-indexes #(2 2)))
'(#(0 0) #(0 1) #(1 0) #(1 1)))
(let ([arr (indexes-array #(4 5))])
(check-equal? (for/list: : (Listof (Listof Indexes)) ([brr (in-array-axis arr 0)])
(for/list: : (Listof Indexes) ([js (in-array brr)])
js))
(array->list* arr))
(check-equal? (for/list: : (Listof (Listof Indexes)) ([brr (in-array-axis arr 1)])
(for/list: : (Listof Indexes) ([js (in-array brr)])
js))
(array->list* (array-axis-swap arr 0 1))))
(check-equal? (array-list->array empty 0)
(array #[]))
(check-exn exn? (λ () (array-list->array empty 1)))
(check-equal? (array-list->array (list (array 0) (array 1) (array 2)) 0)
(array #[0 1 2]))
(check-exn exn? (λ () (array-list->array (list (array 0) (array 1) (array 2)) 1)))
(check-equal? (array-list->array (list (array #[0 1]) (array #[2 3])) 0)
(array #[#[0 1] #[2 3]]))
(check-equal? (array-list->array (list (array #[0 1]) (array #[2 3])) 1)
(array #[#[0 2] #[1 3]]))
(check-equal? (array-list->array (list (array #[0 1 2]) (array 0)) 0)
(array #[#[0 1 2] #[0 0 0]]))
(check-equal? (array-list->array (list (array #[0 1 2]) (array 0)) 1)
(array #[#[0 0] #[1 0] #[2 0]]))
(check-exn exn? (λ () (array-list->array (list (array #[0 1 2]) (array 0)) 2)))
(check-equal? (array-list->array (list (array #[#[0 1] #[2 3]]) (array 0)) 0)
(array #[#[#[0 1] #[2 3]] #[#[0 0] #[0 0]]]))
(check-equal? (array->array-list (array-list->array empty 0) 0)
empty)
(check-exn exn? (λ () (array->array-list (array-list->array empty 0) 1)))
(check-equal? (array->array-list (array-list->array (list (array 0) (array 1) (array 2)) 0) 0)
(list (array 0) (array 1) (array 2)))
(check-equal? (array->array-list (array-list->array (list (array #[0 1]) (array #[2 3])) 0) 0)
(list (array #[0 1]) (array #[2 3])))
(check-equal? (array->array-list (array-list->array (list (array #[0 1]) (array #[2 3])) 1) 1)
(list (array #[0 1]) (array #[2 3])))
(check-equal? (array->array-list (array-list->array (list (array #[0 1 2]) (array 0)) 0) 0)
(list (array #[0 1 2]) (array #[0 0 0])))
(check-equal? (array->array-list (array-list->array (list (array #[0 1 2]) (array 0)) 1) 1)
(list (array #[0 1 2]) (array #[0 0 0])))
(check-equal? (array->array-list (array-list->array (list (array #[#[0 1] #[2 3]]) (array 0)) 0) 0)
(list (array #[#[0 1] #[2 3]]) (array #[#[0 0] #[0 0]])))
;; ---------------------------------------------------------------------------------------------------
;; Conditionals
(let ([arr (build-array #(10 10) (λ: ([js : Indexes]) (apply + (vector->list js))))])
(check-equal? (array-if (array< arr (array 5))
(array 0)
(array 1))
(array-map (λ: ([v : Integer]) (if (v . < . 5) 0 1)) arr))
(check-equal? (array-or (array< arr (make-array #(10 10) 9))
(array> arr (make-array #(10 10) 9)))
(array-map (λ: ([v : Integer]) (or (< v 9) (> v 9))) arr))
(check-equal? (array-and (array< arr (make-array #(10 10) 10))
(array> arr (make-array #(10 10) 8)))
(array-map (λ: ([v : Integer]) (= v 9)) arr)))
;; ---------------------------------------------------------------------------------------------------
;; Lazy arrays
(define (make-lazy-arr)
(: arr (Array Integer))
(define arr
(array-lazy
(build-simple-array
#(12 12)
(λ: ([js : Indexes])
(match-define (vector j0 j1) js)
(cond [(or (= j0 0) (= j1 0)) 1]
[(undefined? arr) (error 'undefined)]
[else (+ (array-ref arr (vector (- j0 1) j1))
(array-ref arr (vector j0 (- j1 1))))])))))
arr)
(define (make-mutable-arr)
(define: arr : (Mutable-Array Integer)
(array->mutable-array
(build-array
#(12 12)
(λ: ([js : Indexes])
(match-define (vector j0 j1) js)
(cond [(or (= j0 0) (= j1 0)) 1]
[else 0])))))
(for*: ([j0 (in-range 1 12)]
[j1 (in-range 1 12)])
(array-set! arr (vector j0 j1)
(+ (array-ref arr (vector (- j0 1) j1))
(array-ref arr (vector j0 (- j1 1))))))
arr)
(check-equal? (make-lazy-arr)
(make-mutable-arr))
(check-equal? (array-lazy (array-axis-swap (indexes-array #(4 4)) 0 1))
(array-axis-swap (indexes-array #(4 4)) 0 1))