1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
;;;;"subarray.scm" Scheme array accessory procedures.
; Copyright (C) 2002 Aubrey Jaffer and Radey Shouman
;
;Permission to copy this software, to modify it, to redistribute it,
;to distribute modified versions, and to use it for any purpose is
;granted, subject to the following restrictions and understandings.
;
;1. Any copy made of this software must include this copyright notice
;in full.
;
;2. I have made no warranty or representation that the operation of
;this software will be error-free, and I am under no obligation to
;provide any services, by way of maintenance, update, or otherwise.
;
;3. In conjunction with products arising from the use of this
;material, there shall be no use of my name in any advertising,
;promotional, or sales literature without prior written consent in
;each case.
(require 'array)
;;@code{(require 'subarray)}
;;@ftindex subarray
;;@body
;;selects a subset of an array. For @1 of rank n, there must be at least
;;n @2 arguments. For 0 <= @i{j} < n, @2@i{j} is either an integer, a
;;list of two integers within the range for the @i{j}th index, or #f.
;;
;;When @2@i{j} is a list of two integers, then the @i{j}th index is
;;restricted to that subrange in the returned array.
;;
;;When @2@i{j} is #f, then the full range of the @i{j}th index is
;;accessible in the returned array. An elided argument is equivalent to #f.
;;
;;When @2@i{j} is an integer, then the rank of the returned array is
;;less than @1, and only elements whose @i{j}th index equals @2@i{j} are
;;shared.
;;
;;@example
;;> (define ra '#2A((a b c) (d e f)))
;;#<unspecified>
;;> (subarray ra 0 #f)
;;#1A(a b c)
;;> (subarray ra 1 #f)
;;#1A(d e f)
;;> (subarray ra #f 1)
;;#1A(b e)
;;> (subarray ra '(0 1) #f)
;;#2A((a b c) (d e f))
;;> (subarray ra #f '(0 1))
;;#2A((a b) (d e))
;;> (subarray ra #f '(1 2))
;;#2A((b c) (e f))
;;@end example
(define (subarray array . selects)
(apply make-shared-array array
(lambda args
(let loop ((sels selects)
(args args)
(lst '()))
(cond ((null? sels)
(if (null? args)
(reverse lst)
(loop sels (cdr args) (cons (car args) lst))))
((number? (car sels))
(loop (cdr sels) args (cons (car sels) lst)))
(else
(loop (cdr sels) (cdr args) (cons (car args) lst))))))
(let loop ((sels selects)
(shp (array-shape array))
(nshp '()))
(cond ((null? shp)
(if (null? sels)
(reverse nshp)
(slib:error 'subarray 'rank (array-rank array) 'mismatch selects)))
((null? sels)
(loop sels (cdr shp) (cons (car shp) nshp)))
((not (car sels))
(loop (cdr sels) (cdr shp) (cons (car shp) nshp)))
((integer? (car sels))
(loop (cdr sels) (cdr shp) nshp))
(else
(loop (cdr sels) (cdr shp) (cons (car sels) nshp)))))))
;;@body
;;Behaves like @r{subarray}, but @r{align}s the returned array origin to
;;0 @dots{}.
(define (subarray0 array . selects)
(define ra (apply subarray array selects))
(apply array-align ra (map (lambda (x) 0) (array-shape ra))))
;;@body
;;
;;Returns an array shared with @1 but with a different origin. The @2
;;are the exact integer coordinates of the new origin. Indexes
;;corresponding to missing or #f coordinates are not realigned.
;;
;;For example:
;;@example
;;(define ra2 (create-array '#(5) '(5 9) '(-4 0)))
;;(array-shape ra2) @result{} ((5 9) (-4 0))
;;(array-shape (array-align ra2 0 0)) @result{} ((0 4) (0 4))
;;(array-shape (array-align ra2 0)) @result{} ((0 4) (-4 0))
;;(array-shape (array-align ra2)) @result{} ((5 9) (-4 0))
;;(array-shape (array-align ra2 0 #f)) @result{} ((0 4) (-4 0))
;;(array-shape (array-align ra2 #f 0)) @result{} ((5 9) (0 4))
;;@end example
(define (array-align array . coords)
(let* ((shape (array-shape array))
(offs (let recur ((shp shape)
(crd coords))
(cond ((null? shp) '())
((null? crd) (map (lambda (x) 0) shp))
((not (car crd)) (cons 0 (recur (cdr shp) (cdr crd))))
(else (cons (- (car crd) (caar shp))
(recur (cdr shp) (cdr crd))))))))
(apply make-shared-array
array (lambda inds (map - inds offs))
(map (lambda (spec off)
(list (+ (car spec) off) (+ (cadr spec) off)))
shape offs))))
;;@body
;;
;;Returns a subarray sharing contents with @1 except for slices removed
;;from either side of each dimension. Each of the @2 is an exact
;;integer indicating how much to trim. A positive @var{s} trims the
;;data from the lower end and reduces the upper bound of the result; a
;;negative @var{s} trims from the upper end and increases the lower
;;bound.
;;
;;For example:
;;@example
;;(array-trim '#(0 1 2 3 4) 1) @result{} #1A(1 2 3 4) ;; shape is ((0 3))
;;(array-trim '#(0 1 2 3 4) -1) @result{} #1A(0 1 2 3) ;; shape is ((1 4))
;;
;;(require 'array-for-each)
;;(define (centered-difference ra)
;; (array-map - (array-trim ra 1) (array-trim ra -1)))
;;(define (forward-difference ra)
;; (array-map - (array-trim ra 1) ra))
;;(define (backward-difference ra)
;; (array-map - ra (array-trim ra -1)))
;;
;;(centered-difference '#(0 1 3 5 9 22))
;; @result{} #1A(3 4 6 17) ;;shape is ((1 4))
;;(backward-difference '#(0 1 3 5 9 22))
;; @result{} #1A(1 2 2 4 13) ;; shape is ((1 5))
;;(forward-difference '#(0 1 3 5 9 22))
;; @result{} #(1 2 2 4 13) ;; shape is ((0 4))
;;@end example
(define (array-trim array . trims)
(let* ((shape (array-shape array))
(trims (let recur ((shp shape)
(ss trims))
(cond ((null? shp) '())
((null? ss) (map (lambda (x) 0) shp))
((integer? (car ss))
(cons (car ss) (recur (cdr shp) (cdr ss))))
(else
(slib:error 'array-trim 'bad 'trim (car ss)))))))
(apply make-shared-array
array
(lambda inds (map + inds trims))
(map (lambda (spec trim)
(cond ((negative? trim)
(cons (- (car spec) trim) (cdr spec)))
((positive? trim)
(list (car spec) (- (cadr spec) trim)))
(else spec)))
shape trims))))
|