63.upstream.scm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. ;;;;"array.scm" Arrays for Scheme
  2. ; Copyright (C) 2001, 2003 Aubrey Jaffer
  3. ;
  4. ;Permission to copy this software, to modify it, to redistribute it,
  5. ;to distribute modified versions, and to use it for any purpose is
  6. ;granted, subject to the following restrictions and understandings.
  7. ;
  8. ;1. Any copy made of this software must include this copyright notice
  9. ;in full.
  10. ;
  11. ;2. I have made no warranty or representation that the operation of
  12. ;this software will be error-free, and I am under no obligation to
  13. ;provide any services, by way of maintenance, update, or otherwise.
  14. ;
  15. ;3. In conjunction with products arising from the use of this
  16. ;material, there shall be no use of my name in any advertising,
  17. ;promotional, or sales literature without prior written consent in
  18. ;each case.
  19. ;;@code{(require 'array)} or @code{(require 'srfi-63)}
  20. ;;@ftindex array
  21. (require 'record)
  22. (define array:rtd
  23. (make-record-type "array"
  24. '(dimensions
  25. scales ;list of dimension scales
  26. offset ;exact integer
  27. store ;data
  28. )))
  29. (define array:dimensions
  30. (let ((dimensions (record-accessor array:rtd 'dimensions)))
  31. (lambda (array)
  32. (cond ((vector? array) (list (vector-length array)))
  33. ((string? array) (list (string-length array)))
  34. (else (dimensions array))))))
  35. (define array:scales
  36. (let ((scales (record-accessor array:rtd 'scales)))
  37. (lambda (obj)
  38. (cond ((string? obj) '(1))
  39. ((vector? obj) '(1))
  40. (else (scales obj))))))
  41. (define array:store
  42. (let ((store (record-accessor array:rtd 'store)))
  43. (lambda (obj)
  44. (cond ((string? obj) obj)
  45. ((vector? obj) obj)
  46. (else (store obj))))))
  47. (define array:offset
  48. (let ((offset (record-accessor array:rtd 'offset)))
  49. (lambda (obj)
  50. (cond ((string? obj) 0)
  51. ((vector? obj) 0)
  52. (else (offset obj))))))
  53. (define array:construct
  54. (record-constructor array:rtd '(dimensions scales offset store)))
  55. ;;@args obj
  56. ;;Returns @code{#t} if the @1 is an array, and @code{#f} if not.
  57. (define array?
  58. (let ((array:array? (record-predicate array:rtd)))
  59. (lambda (obj) (or (string? obj) (vector? obj) (array:array? obj)))))
  60. ;;@noindent
  61. ;;@emph{Note:} Arrays are not disjoint from other Scheme types.
  62. ;;Vectors and possibly strings also satisfy @code{array?}.
  63. ;;A disjoint array predicate can be written:
  64. ;;
  65. ;;@example
  66. ;;(define (strict-array? obj)
  67. ;; (and (array? obj) (not (string? obj)) (not (vector? obj))))
  68. ;;@end example
  69. ;;@body
  70. ;;Returns @code{#t} if @1 and @2 have the same rank and dimensions and the
  71. ;;corresponding elements of @1 and @2 are @code{equal?}.
  72. ;;@body
  73. ;;@0 recursively compares the contents of pairs, vectors, strings, and
  74. ;;@emph{arrays}, applying @code{eqv?} on other objects such as numbers
  75. ;;and symbols. A rule of thumb is that objects are generally @0 if
  76. ;;they print the same. @0 may fail to terminate if its arguments are
  77. ;;circular data structures.
  78. ;;
  79. ;;@example
  80. ;;(equal? 'a 'a) @result{} #t
  81. ;;(equal? '(a) '(a)) @result{} #t
  82. ;;(equal? '(a (b) c)
  83. ;; '(a (b) c)) @result{} #t
  84. ;;(equal? "abc" "abc") @result{} #t
  85. ;;(equal? 2 2) @result{} #t
  86. ;;(equal? (make-vector 5 'a)
  87. ;; (make-vector 5 'a)) @result{} #t
  88. ;;(equal? (make-array (A:fixN32b 4) 5 3)
  89. ;; (make-array (A:fixN32b 4) 5 3)) @result{} #t
  90. ;;(equal? (make-array '#(foo) 3 3)
  91. ;; (make-array '#(foo) 3 3)) @result{} #t
  92. ;;(equal? (lambda (x) x)
  93. ;; (lambda (y) y)) @result{} @emph{unspecified}
  94. ;;@end example
  95. (define (equal? obj1 obj2)
  96. (cond ((eqv? obj1 obj2) #t)
  97. ((or (pair? obj1) (pair? obj2))
  98. (and (pair? obj1) (pair? obj2)
  99. (equal? (car obj1) (car obj2))
  100. (equal? (cdr obj1) (cdr obj2))))
  101. ((or (string? obj1) (string? obj2))
  102. (and (string? obj1) (string? obj2)
  103. (string=? obj1 obj2)))
  104. ((or (vector? obj1) (vector? obj2))
  105. (and (vector? obj1) (vector? obj2)
  106. (equal? (vector-length obj1) (vector-length obj2))
  107. (do ((idx (+ -1 (vector-length obj1)) (+ -1 idx)))
  108. ((or (negative? idx)
  109. (not (equal? (vector-ref obj1 idx)
  110. (vector-ref obj2 idx))))
  111. (negative? idx)))))
  112. ((or (array? obj1) (array? obj2))
  113. (and (array? obj1) (array? obj2)
  114. (equal? (array:dimensions obj1) (array:dimensions obj2))
  115. (equal? (array:store obj1) (array:store obj2))))
  116. (else #f)))
  117. ;;@body
  118. ;;Returns the number of dimensions of @1. If @1 is not an array, 0 is
  119. ;;returned.
  120. (define (array-rank obj)
  121. (if (array? obj) (length (array:dimensions obj)) 0))
  122. ;;@args array
  123. ;;Returns a list of dimensions.
  124. ;;
  125. ;;@example
  126. ;;(array-dimensions (make-array '#() 3 5))
  127. ;; @result{} (3 5)
  128. ;;@end example
  129. (define array-dimensions array:dimensions)
  130. ;;@args prototype k1 @dots{}
  131. ;;
  132. ;;Creates and returns an array of type @1 with dimensions @2, @dots{}
  133. ;;and filled with elements from @1. @1 must be an array, vector, or
  134. ;;string. The implementation-dependent type of the returned array
  135. ;;will be the same as the type of @1; except if that would be a vector
  136. ;;or string with rank not equal to one, in which case some variety of
  137. ;;array will be returned.
  138. ;;
  139. ;;If the @1 has no elements, then the initial contents of the returned
  140. ;;array are unspecified. Otherwise, the returned array will be filled
  141. ;;with the element at the origin of @1.
  142. (define (make-array prototype . dimensions)
  143. (define tcnt (apply * dimensions))
  144. (let ((store
  145. (if (string? prototype)
  146. (case (string-length prototype)
  147. ((0) (make-string tcnt))
  148. (else (make-string tcnt
  149. (string-ref prototype 0))))
  150. (let ((pdims (array:dimensions prototype)))
  151. (case (apply * pdims)
  152. ((0) (make-vector tcnt))
  153. (else (make-vector tcnt
  154. (apply array-ref prototype
  155. (map (lambda (x) 0) pdims)))))))))
  156. (define (loop dims scales)
  157. (if (null? dims)
  158. (array:construct dimensions (cdr scales) 0 store)
  159. (loop (cdr dims) (cons (* (car dims) (car scales)) scales))))
  160. (loop (reverse dimensions) '(1))))
  161. ;;@args prototype k1 @dots{}
  162. ;;@0 is an alias for @code{make-array}.
  163. (define create-array make-array)
  164. ;;@args array mapper k1 @dots{}
  165. ;;@0 can be used to create shared subarrays of other
  166. ;;arrays. The @var{mapper} is a function that translates coordinates in
  167. ;;the new array into coordinates in the old array. A @var{mapper} must be
  168. ;;linear, and its range must stay within the bounds of the old array, but
  169. ;;it can be otherwise arbitrary. A simple example:
  170. ;;
  171. ;;@example
  172. ;;(define fred (make-array '#(#f) 8 8))
  173. ;;(define freds-diagonal
  174. ;; (make-shared-array fred (lambda (i) (list i i)) 8))
  175. ;;(array-set! freds-diagonal 'foo 3)
  176. ;;(array-ref fred 3 3)
  177. ;; @result{} FOO
  178. ;;(define freds-center
  179. ;; (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j)))
  180. ;; 2 2))
  181. ;;(array-ref freds-center 0 0)
  182. ;; @result{} FOO
  183. ;;@end example
  184. (define (make-shared-array array mapper . dimensions)
  185. (define odl (array:scales array))
  186. (define rank (length dimensions))
  187. (define shape
  188. (map (lambda (dim) (if (list? dim) dim (list 0 (+ -1 dim)))) dimensions))
  189. (do ((idx (+ -1 rank) (+ -1 idx))
  190. (uvt (append (cdr (vector->list (make-vector rank 0))) '(1))
  191. (append (cdr uvt) '(0)))
  192. (uvts '() (cons uvt uvts)))
  193. ((negative? idx)
  194. (let ((ker0 (apply + (map * odl (apply mapper uvt)))))
  195. (array:construct
  196. (map (lambda (dim) (+ 1 (- (cadr dim) (car dim)))) shape)
  197. (map (lambda (uvt) (- (apply + (map * odl (apply mapper uvt))) ker0))
  198. uvts)
  199. (apply +
  200. (array:offset array)
  201. (map * odl (apply mapper (map car shape))))
  202. (array:store array))))))
  203. ;;@args rank proto list
  204. ;;@3 must be a rank-nested list consisting of all the elements, in
  205. ;;row-major order, of the array to be created.
  206. ;;
  207. ;;@0 returns an array of rank @1 and type @2 consisting of all the
  208. ;;elements, in row-major order, of @3. When @1 is 0, @3 is the lone
  209. ;;array element; not necessarily a list.
  210. ;;
  211. ;;@example
  212. ;;(list->array 2 '#() '((1 2) (3 4)))
  213. ;; @result{} #2A((1 2) (3 4))
  214. ;;(list->array 0 '#() 3)
  215. ;; @result{} #0A 3
  216. ;;@end example
  217. (define (list->array rank proto lst)
  218. (define dimensions
  219. (do ((shp '() (cons (length row) shp))
  220. (row lst (car lst))
  221. (rnk (+ -1 rank) (+ -1 rnk)))
  222. ((negative? rnk) (reverse shp))))
  223. (let ((nra (apply make-array proto dimensions)))
  224. (define (l2ra dims idxs row)
  225. (cond ((null? dims)
  226. (apply array-set! nra row (reverse idxs)))
  227. ((if (not (eqv? (car dims) (length row)))
  228. (slib:error 'list->array
  229. 'non-rectangular 'array dims dimensions))
  230. (do ((idx 0 (+ 1 idx))
  231. (row row (cdr row)))
  232. ((>= idx (car dims)))
  233. (l2ra (cdr dims) (cons idx idxs) (car row))))))
  234. (l2ra dimensions '() lst)
  235. nra))
  236. ;;@args array
  237. ;;Returns a rank-nested list consisting of all the elements, in
  238. ;;row-major order, of @1. In the case of a rank-0 array, @0 returns
  239. ;;the single element.
  240. ;;
  241. ;;@example
  242. ;;(array->list #2A((ho ho ho) (ho oh oh)))
  243. ;; @result{} ((ho ho ho) (ho oh oh))
  244. ;;(array->list #0A ho)
  245. ;; @result{} ho
  246. ;;@end example
  247. (define (array->list ra)
  248. (define (ra2l dims idxs)
  249. (if (null? dims)
  250. (apply array-ref ra (reverse idxs))
  251. (do ((lst '() (cons (ra2l (cdr dims) (cons idx idxs)) lst))
  252. (idx (+ -1 (car dims)) (+ -1 idx)))
  253. ((negative? idx) lst))))
  254. (ra2l (array-dimensions ra) '()))
  255. ;;@args vect proto dim1 @dots{}
  256. ;;@1 must be a vector of length equal to the product of exact
  257. ;;nonnegative integers @3, @dots{}.
  258. ;;
  259. ;;@0 returns an array of type @2 consisting of all the elements, in
  260. ;;row-major order, of @1. In the case of a rank-0 array, @1 has a
  261. ;;single element.
  262. ;;
  263. ;;@example
  264. ;;(vector->array #(1 2 3 4) #() 2 2)
  265. ;; @result{} #2A((1 2) (3 4))
  266. ;;(vector->array '#(3) '#())
  267. ;; @result{} #0A 3
  268. ;;@end example
  269. (define (vector->array vect prototype . dimensions)
  270. (define vdx (vector-length vect))
  271. (if (not (eqv? vdx (apply * dimensions)))
  272. (slib:error 'vector->array vdx '<> (cons '* dimensions)))
  273. (let ((ra (apply make-array prototype dimensions)))
  274. (define (v2ra dims idxs)
  275. (cond ((null? dims)
  276. (set! vdx (+ -1 vdx))
  277. (apply array-set! ra (vector-ref vect vdx) (reverse idxs)))
  278. (else
  279. (do ((idx (+ -1 (car dims)) (+ -1 idx)))
  280. ((negative? idx) vect)
  281. (v2ra (cdr dims) (cons idx idxs))))))
  282. (v2ra dimensions '())
  283. ra))
  284. ;;@args array
  285. ;;Returns a new vector consisting of all the elements of @1 in
  286. ;;row-major order.
  287. ;;
  288. ;;@example
  289. ;;(array->vector #2A ((1 2)( 3 4)))
  290. ;; @result{} #(1 2 3 4)
  291. ;;(array->vector #0A ho)
  292. ;; @result{} #(ho)
  293. ;;@end example
  294. (define (array->vector ra)
  295. (define dims (array-dimensions ra))
  296. (let* ((vdx (apply * dims))
  297. (vect (make-vector vdx)))
  298. (define (ra2v dims idxs)
  299. (if (null? dims)
  300. (let ((val (apply array-ref ra (reverse idxs))))
  301. (set! vdx (+ -1 vdx))
  302. (vector-set! vect vdx val)
  303. vect)
  304. (do ((idx (+ -1 (car dims)) (+ -1 idx)))
  305. ((negative? idx) vect)
  306. (ra2v (cdr dims) (cons idx idxs)))))
  307. (ra2v dims '())))
  308. (define (array:in-bounds? array indices)
  309. (do ((bnds (array:dimensions array) (cdr bnds))
  310. (idxs indices (cdr idxs)))
  311. ((or (null? bnds)
  312. (null? idxs)
  313. (not (integer? (car idxs)))
  314. (not (< -1 (car idxs) (car bnds))))
  315. (and (null? bnds) (null? idxs)))))
  316. ;;@args array index1 @dots{}
  317. ;;Returns @code{#t} if its arguments would be acceptable to
  318. ;;@code{array-ref}.
  319. (define (array-in-bounds? array . indices)
  320. (array:in-bounds? array indices))
  321. ;;@args array k1 @dots{}
  322. ;;Returns the (@2, @dots{}) element of @1.
  323. (define (array-ref array . indices)
  324. (define store (array:store array))
  325. (or (array:in-bounds? array indices)
  326. (slib:error 'array-ref 'bad-indices indices))
  327. ((if (string? store) string-ref vector-ref)
  328. store (apply + (array:offset array) (map * (array:scales array) indices))))
  329. ;;@args array obj k1 @dots{}
  330. ;;Stores @2 in the (@3, @dots{}) element of @1. The value returned
  331. ;;by @0 is unspecified.
  332. (define (array-set! array obj . indices)
  333. (define store (array:store array))
  334. (or (array:in-bounds? array indices)
  335. (slib:error 'array-set! 'bad-indices indices))
  336. ((if (string? store) string-set! vector-set!)
  337. store (apply + (array:offset array) (map * (array:scales array) indices))
  338. obj))
  339. ;;@noindent
  340. ;;These functions return a prototypical uniform-array enclosing the
  341. ;;optional argument (which must be of the correct type). If the
  342. ;;uniform-array type is supported by the implementation, then it is
  343. ;;returned; defaulting to the next larger precision type; resorting
  344. ;;finally to vector.
  345. (define (make-prototype-checker name pred? creator)
  346. (lambda args
  347. (case (length args)
  348. ((1) (if (pred? (car args))
  349. (creator (car args))
  350. (slib:error name 'incompatible 'type (car args))))
  351. ((0) (creator))
  352. (else (slib:error name 'wrong 'number 'of 'args args)))))
  353. (define (integer-bytes?? n)
  354. (lambda (obj)
  355. (and (integer? obj)
  356. (exact? obj)
  357. (or (negative? n) (not (negative? obj)))
  358. (do ((num obj (quotient num 256))
  359. (n (+ -1 (abs n)) (+ -1 n)))
  360. ((or (zero? num) (negative? n))
  361. (zero? num))))))
  362. ;;@args z
  363. ;;@args
  364. ;;Returns an inexact 128.bit flonum complex uniform-array prototype.
  365. (define A:floC128b (make-prototype-checker 'A:floC128b complex? vector))
  366. ;;@args z
  367. ;;@args
  368. ;;Returns an inexact 64.bit flonum complex uniform-array prototype.
  369. (define A:floC64b (make-prototype-checker 'A:floC64b complex? vector))
  370. ;;@args z
  371. ;;@args
  372. ;;Returns an inexact 32.bit flonum complex uniform-array prototype.
  373. (define A:floC32b (make-prototype-checker 'A:floC32b complex? vector))
  374. ;;@args z
  375. ;;@args
  376. ;;Returns an inexact 16.bit flonum complex uniform-array prototype.
  377. (define A:floC16b (make-prototype-checker 'A:floC16b complex? vector))
  378. ;;@args z
  379. ;;@args
  380. ;;Returns an inexact 128.bit flonum real uniform-array prototype.
  381. (define A:floR128b (make-prototype-checker 'A:floR128b real? vector))
  382. ;;@args z
  383. ;;@args
  384. ;;Returns an inexact 64.bit flonum real uniform-array prototype.
  385. (define A:floR64b (make-prototype-checker 'A:floR64b real? vector))
  386. ;;@args z
  387. ;;@args
  388. ;;Returns an inexact 32.bit flonum real uniform-array prototype.
  389. (define A:floR32b (make-prototype-checker 'A:floR32b real? vector))
  390. ;;@args z
  391. ;;@args
  392. ;;Returns an inexact 16.bit flonum real uniform-array prototype.
  393. (define A:floR16b (make-prototype-checker 'A:floR16b real? vector))
  394. ;;@args z
  395. ;;@args
  396. ;;Returns an exact 128.bit decimal flonum rational uniform-array prototype.
  397. (define A:floR128b (make-prototype-checker 'A:floR128b real? vector))
  398. ;;@args z
  399. ;;@args
  400. ;;Returns an exact 64.bit decimal flonum rational uniform-array prototype.
  401. (define A:floR64b (make-prototype-checker 'A:floR64b real? vector))
  402. ;;@args z
  403. ;;@args
  404. ;;Returns an exact 32.bit decimal flonum rational uniform-array prototype.
  405. (define A:floR32b (make-prototype-checker 'A:floR32b real? vector))
  406. ;;@args n
  407. ;;@args
  408. ;;Returns an exact binary fixnum uniform-array prototype with at least
  409. ;;64 bits of precision.
  410. (define A:fixZ64b (make-prototype-checker 'A:fixZ64b (integer-bytes?? -8) vector))
  411. ;;@args n
  412. ;;@args
  413. ;;Returns an exact binary fixnum uniform-array prototype with at least
  414. ;;32 bits of precision.
  415. (define A:fixZ32b (make-prototype-checker 'A:fixZ32b (integer-bytes?? -4) vector))
  416. ;;@args n
  417. ;;@args
  418. ;;Returns an exact binary fixnum uniform-array prototype with at least
  419. ;;16 bits of precision.
  420. (define A:fixZ16b (make-prototype-checker 'A:fixZ16b (integer-bytes?? -2) vector))
  421. ;;@args n
  422. ;;@args
  423. ;;Returns an exact binary fixnum uniform-array prototype with at least
  424. ;;8 bits of precision.
  425. (define A:fixZ8b (make-prototype-checker 'A:fixZ8b (integer-bytes?? -1) vector))
  426. ;;@args k
  427. ;;@args
  428. ;;Returns an exact non-negative binary fixnum uniform-array prototype with at
  429. ;;least 64 bits of precision.
  430. (define A:fixN64b (make-prototype-checker 'A:fixN64b (integer-bytes?? 8) vector))
  431. ;;@args k
  432. ;;@args
  433. ;;Returns an exact non-negative binary fixnum uniform-array prototype with at
  434. ;;least 32 bits of precision.
  435. (define A:fixN32b (make-prototype-checker 'A:fixN32b (integer-bytes?? 4) vector))
  436. ;;@args k
  437. ;;@args
  438. ;;Returns an exact non-negative binary fixnum uniform-array prototype with at
  439. ;;least 16 bits of precision.
  440. (define A:fixN16b (make-prototype-checker 'A:fixN16b (integer-bytes?? 2) vector))
  441. ;;@args k
  442. ;;@args
  443. ;;Returns an exact non-negative binary fixnum uniform-array prototype with at
  444. ;;least 8 bits of precision.
  445. (define A:fixN8b (make-prototype-checker 'A:fixN8b (integer-bytes?? 1) vector))
  446. ;;@args bool
  447. ;;@args
  448. ;;Returns a boolean uniform-array prototype.
  449. (define A:bool (make-prototype-checker 'A:bool boolean? vector))