chickadee » srfi-179 » array-curry

array-curry array inner-dimensionprocedure

If array is an array whose domain is an interval $[l_0,u_0)\times\cdots\times[l_{d-1},u_{d-1})$, and inner-dimension is an exact integer strictly between $0$ and $d$, then array-curry returns an immutable array with domain $[l_0,u_0)\times\cdots\times[l_{d-\text{inner-dimension}-1},u_{d-\text{inner-dimension}-1})$, each of whose entries is in itself an array with domain $[l_{d-\text{inner-dimension}},u_{d-\text{inner-dimension}})\times\cdots\times[l_{d-1},u_{d-1})$.

For example, if A and B are defined by

(define interval (make-interval '#(10 10 10 10)))
(define A (make-array interval list))
(define B (array-curry A 1))

(define A_ (array-getter A))
(define B_ (array-getter B))
  

so

(A_ i j k l) => (list i j k l)

then B is an immutable array with domain (make-interval '#(10 10 10)), each of whose elements is itself an (immutable) array and

(equal?
 (A_ i j k l)
 ((array-getter (B_ i j k)) l)) => #t

for all multi-indices i j k l in interval.

The subarrays are immutable, mutable, or specialized according to whether the array argument is immutable, mutable, or specialized.

More precisely, if

0 < inner-dimension < (interval-dimension (array-domain array))

then array-curry returns a result as follows.

If the input array is specialized, then array-curry returns

(call-with-values
    (lambda () (interval-projections (array-domain array)
                                     inner-dimension))
  (lambda (outer-interval inner-interval)
    (make-array
     outer-interval
     (lambda outer-multi-index
       (specialized-array-share
        array
        inner-interval
        (lambda inner-multi-index
          (apply values
                 (append outer-multi-index
                         inner-multi-index))))))))

Otherwise, if the input array is mutable, then array-curry returns

(call-with-values
    (lambda () (interval-projections (array-domain array)
                                     inner-dimension))
  (lambda (outer-interval inner-interval)
    (make-array
     outer-interval
     (lambda outer-multi-index
       (make-array
        inner-interval
        (lambda inner-multi-index
          (apply (array-getter array)
                 (append outer-multi-index
                         inner-multi-index)))
        (lambda (v . inner-multi-index)
          (apply (array-setter array)
                 v
                 (append outer-multi-index
                         inner-multi-index))))))))

Otherwise, array-curry returns

(call-with-values
    (lambda () (interval-projections (array-domain array)
                                     inner-dimension))
  (lambda (outer-interval inner-interval)
    (make-array
     outer-interval
     (lambda outer-multi-index
       (make-array
        inner-interval
        (lambda inner-multi-index
          (apply (array-getter array)
                 (append outer-multi-index
                         inner-multi-index))))))))

It is an error to call array-curry if its arguments do not satisfy these conditions.

If array is a specialized array, the subarrays of the result inherit their safety and mutability from array.

Note: Let's denote by B the result of (array-curry A k). While the result of calling (array-getter B) is an immutable, mutable, or specialized array according to whether A itself is immutable, mutable, or specialized, B is always an immutable array, where (array-getter B), which returns an array, is computed anew for each call. If (array-getter B) will be called multiple times with the same arguments, it may be useful to store these results in a specialized array for fast repeated access.

Please see the note in the discussion of array-tile.

Example:

(define a (make-array (make-interval '#(10 10))
                      list))
(define a_ (array-getter a))
(a_ 3 4)  => (3 4)
(define curried-a (array-curry a 1))
(define curried-a_ (array-getter curried-a))
((array-getter (curried-a_ 3)) 4)
                    => (3 4)