base.scm 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. ; -*- mode: scheme; coding: utf-8 -*-
  2. ; (c) Daniel Llorens - 2016-2023
  3. ; This library is free software; you can redistribute it and/or modify it under
  4. ; the terms of the GNU General Public License as published by the Free
  5. ; Software Foundation; either version 3 of the License, or (at your option) any
  6. ; later version.
  7. ;;; Commentary:
  8. ;; Basic definitions for arrays.
  9. ;;; Code:
  10. (define-module (newra base)
  11. #:export (ra?
  12. ra-root ra-zero ra-zero-set! ra-dims ra-type ra-vlen ra-vref ra-vset!
  13. ra-check
  14. ra-rank ra-type make-ra-new make-ra-root
  15. make-aseq aseq? aseq-org aseq-inc aseq-ref
  16. make-dim dim? dim-len dim-lo dim-hi dim-step c-dims
  17. ra-pos ra-offset
  18. ra-slice ra-cell ra-ref ra-set!
  19. ; for internal (newra) use, don't re-export from (newra)
  20. define-inlinable-case
  21. <aseq> <dim> make-dim* dim-check
  22. <ra-vtable> pick-functions pick-make
  23. %%ra-root %%ra-zero %%ra-type %%ra-rank
  24. %%ra-zero-set! %%ra-dims %%ra-vlen %%ra-vref %%ra-vset! %%ra-step
  25. ra-shape ra-dimensions ra-len ra-lo ra-size))
  26. (import (srfi srfi-26) (srfi srfi-2) (srfi srfi-71) (srfi srfi-4 gnu) (srfi srfi-9 gnu)
  27. (only (srfi srfi-1) fold every) (ice-9 match) (ice-9 control)
  28. (rnrs bytevectors) (only (rnrs base) vector-for-each)
  29. (ice-9 exceptions)
  30. (newra vector))
  31. ; ----------------
  32. ;; Conventions
  33. ; ----------------
  34. ;; ra: an array-type view created by make-ra*
  35. ;; dim: each axis of an ra, or its bounds, as many as the rank.
  36. ;; index: integer as axis argument
  37. ;; lo: lowest index in a dim
  38. ;; hi: highest index in a dim
  39. ;; end: one past hi
  40. ;; len: length of a dim = end-lo
  41. ;; lenm: len - 1.
  42. ;; v: a vector
  43. ;; l: a list
  44. ;; i, j: indices in a dim, from lo to hi
  45. ;; k: an index in a dim vector, from 0 to rank-1
  46. ;; slice: an ra, as a piece of another ra
  47. ;; cell: (also prefix-cell) slice obtained by fixing the first k indices into an ra.
  48. ;; item: slice obtained by fixing the first index into an ra; a (rank - 1)-cell.
  49. ; ----------------
  50. ; misc
  51. ; ----------------
  52. ; from Guile's (rnrs base)
  53. (define-syntax define-proxy
  54. (syntax-rules (@)
  55. ;; Define BINDING to point to (@ MODULE ORIGINAL). This hack is to
  56. ;; make sure MODULE is loaded lazily, at run-time, when BINDING is
  57. ;; encountered, rather than being loaded while compiling and
  58. ;; loading (rnrs base).
  59. ;; This avoids circular dependencies among modules and makes
  60. ;; (rnrs base) more lightweight.
  61. ((_ binding (@ module original))
  62. (define-syntax binding
  63. (identifier-syntax
  64. (module-ref (resolve-interface 'module) 'original))))))
  65. (define-proxy ra-from (@ (newra from) ra-from))
  66. ; cf https://www.scheme.com/tspl4/syntax.html - define-integrable
  67. ; cf guile/module/ice-9/boot.scm - define-inlinable
  68. ; actually inlining depends on Guile's peval.
  69. (define-syntax define-inlinable-case
  70. (lambda (x)
  71. (define prefix (string->symbol "% "))
  72. (define (make-procedure-name name)
  73. (datum->syntax name (symbol-append prefix (syntax->datum name) '-procedure)))
  74. (syntax-case x (case-lambda)
  75. ((_ name (case-lambda DOC (formals form1 form2 ...) ...))
  76. (and (identifier? #'name)
  77. (string? (syntax->datum #'DOC)))
  78. (with-syntax ((xname (make-procedure-name #'name)))
  79. #`(begin
  80. (define xname
  81. (syntax-parameterize ((name (identifier-syntax xname)))
  82. (case-lambda DOC (formals form1 form2 ...) ...)))
  83. (define-syntax-parameter name
  84. (lambda (x)
  85. (syntax-case x ()
  86. (_ (identifier? x) #'xname)
  87. ((_ arg (... ...))
  88. #'((syntax-parameterize ((name (identifier-syntax xname)))
  89. (case-lambda DOC (formals form1 form2 ...) ...))
  90. arg (... ...)))))))))
  91. ((_ name (case-lambda (formals form1 form2 ...) ...))
  92. #'(define-inlinable-case name
  93. (case-lambda "" (formals form1 form2 ...) ...))))))
  94. ; ----------------
  95. ; arithmetic sequence for ra roots
  96. ; ----------------
  97. (define-immutable-record-type <aseq>
  98. (make-aseq* org inc) aseq?
  99. (org aseq-org)
  100. (inc aseq-inc))
  101. (define-inlinable-case make-aseq
  102. (case-lambda
  103. (() (make-aseq* 0 1))
  104. ((org)
  105. (unless (real? org) (throw 'bad-aseq-org org))
  106. (make-aseq* org 1))
  107. ((org inc)
  108. (unless (real? org) (throw 'bad-aseq-org org))
  109. (unless (real? inc) (throw 'bad-aseq-inc inc))
  110. (make-aseq* org inc))))
  111. (define-inlinable (aseq-ref aseq i)
  112. (+ (aseq-org aseq) (* i (aseq-inc aseq))))
  113. ; ----------------
  114. ; dimension of array axes
  115. ; ----------------
  116. (define-immutable-record-type <dim>
  117. (make-dim* len lo step) dim?
  118. (len dim-len)
  119. (lo dim-lo)
  120. (step dim-step))
  121. ; when we KNOW arg is <dim>.
  122. (define-inlinable (%%dim-len dim) (struct-ref dim 0))
  123. (define-inlinable (%%dim-lo dim) (struct-ref dim 1))
  124. (define-inlinable (%%dim-step dim) (struct-ref dim 2))
  125. (define-inlinable-case make-dim
  126. (case-lambda
  127. "
  128. make-dim len
  129. make-dim len lo
  130. make-dim len lo step
  131. Create an ra axis descriptor with the given parameters.
  132. See also: dim-len dim-lo dim-step c-dims
  133. "
  134. ((len) (make-dim len 0 1))
  135. ((len lo) (make-dim len lo 1))
  136. ((len lo step)
  137. (when (and len (or (not (integer? len)) (negative? len)))
  138. (throw 'bad-dim-len len))
  139. ; lo #f requires len #f. FIXME doc when that can happen.
  140. (when (and (not lo) len)
  141. (throw 'bad-dim-lo-len lo len))
  142. (make-dim* len lo step))))
  143. (define-inlinable (dim-end dim)
  144. (match dim
  145. (($ <dim> len lo _)
  146. (+ lo len))))
  147. (define-inlinable-case dim-hi
  148. (case-lambda
  149. ((len lo)
  150. (and len (+ lo len -1)))
  151. ((dim)
  152. (match dim
  153. (($ <dim> len lo _)
  154. (dim-hi len lo))))))
  155. (define-inlinable-case dim-check
  156. (case-lambda
  157. ((len lo i)
  158. (if (and
  159. (or (not lo) (>= i lo))
  160. (or (not len) (< i (+ len lo)))) ; len implies lo
  161. i
  162. (throw 'dim-check-out-of-range len lo i)))
  163. ((dim i)
  164. (match dim
  165. (($ <dim> len lo _)
  166. (dim-check len lo i))))))
  167. ; ----------------
  168. ; the array/view type
  169. ; ----------------
  170. ; fields are: [apply setter data zero dims type vlen vref vset!]
  171. (define <ra-vtable>
  172. (make-struct/no-tail
  173. <applicable-struct-with-setter-vtable>
  174. (make-struct-layout "pwpwpwpwpwpwpwpwpw")))
  175. (define-inlinable (ra? o)
  176. (and (struct? o) (eq? <ra-vtable> (struct-vtable o))))
  177. (define-inlinable (ra-check o)
  178. (if (ra? o) o (throw 'not-ra? o)))
  179. ;; data: a container (function) addressable by a single integer
  180. ;; address: into data.
  181. ;; zero: address that corresponds to all the ra indices = 0.
  182. ;; %: regular macro.
  183. ;; %%: skip ra? check.
  184. (define-inlinable (%%ra-root a) (struct-ref a 2))
  185. (define-inlinable (%%ra-zero a) (struct-ref a 3))
  186. (define-inlinable (%%ra-zero-set! a z) (struct-set! a 3 z)) ; set on iteration. Everything else immutable.
  187. (define-inlinable (%%ra-dims a) (struct-ref a 4))
  188. (define-inlinable (%%ra-type a) (struct-ref a 5))
  189. (define-inlinable (%%ra-vlen a) (struct-ref a 6))
  190. (define-inlinable (%%ra-vref a) (struct-ref a 7))
  191. (define-inlinable (%%ra-vset! a) (struct-ref a 8))
  192. (define-syntax-rule (%rastruct-ref a n) (struct-ref (ra-check a) n))
  193. (define-syntax-rule (%rastruct-set! a n o) (struct-set! (ra-check a) n o))
  194. (define-inlinable (ra-root a)
  195. "
  196. Return the root vector of array @var{a}.
  197. "
  198. (%rastruct-ref a 2))
  199. (define-inlinable (ra-zero a)
  200. "
  201. Return the index @var{i} into the root vector of @var{ra} that corresponds to
  202. all array indices being 0. Note that @var{i} may be outside the range of the
  203. root vector, for example if @var{a} is empty or its lower bounds are positive.
  204. See also: @code{ra-offset}
  205. "
  206. (%rastruct-ref a 3))
  207. (define-inlinable (ra-zero-set! a z) (%rastruct-set! a 3 z))
  208. (define-inlinable (ra-dims a) (%rastruct-ref a 4))
  209. (define-inlinable (ra-type a) (%rastruct-ref a 5))
  210. (define-inlinable (ra-vlen a) (%rastruct-ref a 6))
  211. (define-inlinable (ra-vref a) (%rastruct-ref a 7))
  212. (define-inlinable (ra-vset! a) (%rastruct-ref a 8))
  213. (define-inlinable (%%ra-step a k) (dim-step (vector-ref (%%ra-dims a) k)))
  214. (define (pick-make type)
  215. (case type
  216. ((#t) make-vector)
  217. ((c64) make-c64vector)
  218. ((c32) make-c32vector)
  219. ((f64) make-f64vector)
  220. ((f32) make-f32vector)
  221. ((s64) make-s64vector)
  222. ((s32) make-s32vector)
  223. ((s16) make-s16vector)
  224. ((s8) make-s8vector)
  225. ((u64) make-u64vector)
  226. ((u32) make-u32vector)
  227. ((u16) make-u16vector)
  228. ((u8) make-u8vector)
  229. ((vu8) make-u8vector)
  230. ((a) make-string)
  231. ((b) make-bitvector)
  232. ((d) (throw 'no-dim-make))
  233. (else (throw 'bad-ra-root-type type))))
  234. (define (pick-functions v)
  235. (cond ((vector? v) (values #t vector-length vector-ref vector-set! ))
  236. ((c64vector? v) (values 'c64 c64vector-length c64vector-ref c64vector-set!))
  237. ((c32vector? v) (values 'c32 c32vector-length c32vector-ref c32vector-set!))
  238. ((f64vector? v) (values 'f64 f64vector-length f64vector-ref f64vector-set!))
  239. ((f32vector? v) (values 'f32 f32vector-length f32vector-ref f32vector-set!))
  240. ((s64vector? v) (values 's64 s64vector-length s64vector-ref s64vector-set!))
  241. ((s32vector? v) (values 's32 s32vector-length s32vector-ref s32vector-set!))
  242. ((s16vector? v) (values 's16 s16vector-length s16vector-ref s16vector-set!))
  243. ((s8vector? v) (values 's8 s8vector-length s8vector-ref s8vector-set! ))
  244. ((u64vector? v) (values 'u64 u64vector-length u64vector-ref u64vector-set!))
  245. ((u32vector? v) (values 'u32 u32vector-length u32vector-ref u32vector-set!))
  246. ((u16vector? v) (values 'u16 u16vector-length u16vector-ref u16vector-set!))
  247. ((u8vector? v) (values 'u8 u8vector-length u8vector-ref u8vector-set! ))
  248. ((bytevector? v) (values 'u8 u8vector-length u8vector-ref u8vector-set!))
  249. ((string? v) (values 'a string-length string-ref string-set! ))
  250. ((bitvector? v) (values 'b bitvector-length bitvector-ref bitvector-set!))
  251. ; TODO extend this to drag-along.
  252. ((aseq? v) (values 'd (const #f) aseq-ref (cut throw 'no-aseq-set! <...>)))
  253. (else (throw 'bad-ra-root v))))
  254. ; ----------------
  255. ; compute addresses
  256. ; ----------------
  257. (define-syntax %ra-pos
  258. (syntax-rules ()
  259. ((_ j pos dims)
  260. pos)
  261. ((_ j pos dims i0 i ...)
  262. (let ((dimj (vector-ref dims j)))
  263. (dim-check (%%dim-len dimj) (%%dim-lo dimj) i0)
  264. (%ra-pos (+ j 1) (+ pos (* i0 (%%dim-step dimj))) dims i ...)))))
  265. (define-inlinable-case ra-pos
  266. (case-lambda
  267. ((zero dims) (%ra-pos 0 zero dims))
  268. ((zero dims i0) (%ra-pos 0 zero dims i0))
  269. ((zero dims i0 i1) (%ra-pos 0 zero dims i0 i1))
  270. ((zero dims i0 i1 i2) (%ra-pos 0 zero dims i0 i1 i2))
  271. ((zero dims i0 i1 i2 i3) (%ra-pos 0 zero dims i0 i1 i2 i3))
  272. ((zero dims i0 i1 i2 i3 i4) (%ra-pos 0 zero dims i0 i1 i2 i3 i4))
  273. ((zero dims . i_)
  274. (let loop ((j 0) (pos zero) (i i_))
  275. (if (null? i)
  276. pos
  277. (if (>= j (vector-length dims))
  278. (throw 'too-many-indices i_)
  279. (let ((dimj (vector-ref dims j)))
  280. (loop (+ j 1)
  281. (+ pos (* (dim-check (%%dim-len dimj) (%%dim-lo dimj) (car i)) (%%dim-step dimj)))
  282. (cdr i)))))))))
  283. (define-inlinable-case ra-offset
  284. (case-lambda
  285. "
  286. Return the root vector index @var{i} that corresponds to all ra indices being
  287. equal to the lower bound of @var{ra} in axes [@var{org} ... @var{org}+@var{k}).
  288. See also: @code{ra-zero}
  289. "
  290. ((ra)
  291. (let ((ra (ra-check ra)))
  292. (ra-offset (%%ra-zero ra) (%%ra-dims ra))))
  293. ; internally - useful for some types of loops, or to transition from Guile C arrays.
  294. ((zero dims)
  295. (ra-offset zero dims (vector-length dims) 0))
  296. ((zero dims k)
  297. (ra-offset zero dims k 0))
  298. ((zero dims k org)
  299. ; min - enable prefix match, ignoring dead axes [(vector-length dims) ... (- k 1)]
  300. (let loop ((k (min (+ k org) (vector-length dims))) (pos zero))
  301. (if (<= k org)
  302. pos
  303. (let ((k (- k 1)))
  304. (match (vector-ref dims k)
  305. (($ <dim> _ lo step)
  306. (loop k (+ pos (* (or lo 0) step)))))))))))
  307. ; ----------------
  308. ; ref, set!, prefix slices
  309. ; ----------------
  310. (define-inlinable (%%ra-rank a) (vector-length (%%ra-dims a)))
  311. (define-inlinable (ra-rank a) (vector-length (ra-dims a)))
  312. (define-syntax %length
  313. (syntax-rules ()
  314. ((_) 0)
  315. ((_ i0 i ...) (+ 1 (%length i ...)))))
  316. ; FIXME would like to use let-syntax for these macros that are only used in one place.
  317. (define-syntax %ra-ref
  318. (syntax-rules ()
  319. ((_ ra i ...)
  320. (begin
  321. (let ((rank (ra-rank ra)))
  322. (unless (= rank (%length i ...))
  323. (throw 'bad-number-of-indices rank (%length i ...))))
  324. ((%%ra-vref ra) (%%ra-root ra) (%ra-pos 0 (%%ra-zero ra) (%%ra-dims ra) i ...))))))
  325. (define-inlinable-case ra-ref
  326. (case-lambda
  327. "
  328. Return the element of ra @var{a} determined by indices @var{i}. The number of
  329. indices must be equal to the rank of @var{a}.
  330. For example:
  331. @lisp
  332. (ra-ref (ra-i 2 3) 1 1)
  333. @result{} 5
  334. @end lisp
  335. See also: @code{ra-cell} @code{ra-slice} @code{ra-from}
  336. "
  337. ((ra) (%ra-ref ra))
  338. ((ra i0) (%ra-ref ra i0))
  339. ((ra i0 i1) (%ra-ref ra i0 i1))
  340. ((ra i0 i1 i2) (%ra-ref ra i0 i1 i2))
  341. ((ra i0 i1 i2 i3) (%ra-ref ra i0 i1 i2 i3))
  342. ((ra i0 i1 i2 i3 i4) (%ra-ref ra i0 i1 i2 i3 i4))
  343. ((ra . i)
  344. (unless (= (ra-rank ra) (length i))
  345. (throw 'bad-number-of-indices (ra-rank ra) (length i)))
  346. ((%%ra-vref ra) (%%ra-root ra) (apply ra-pos (%%ra-zero ra) (%%ra-dims ra) i)))))
  347. (define-syntax %ra-set!
  348. (syntax-rules ()
  349. ((_ ra o i ...)
  350. (begin
  351. (unless (= (ra-rank ra) (%length i ...))
  352. (throw 'bad-number-of-indices (ra-rank ra) (%length i ...)))
  353. ((%%ra-vset! ra) (%%ra-root ra) (%ra-pos 0 (%%ra-zero ra) (%%ra-dims ra) i ...) o)
  354. ra))))
  355. (define-inlinable-case ra-set!
  356. (case-lambda
  357. ((ra o) (%ra-set! ra o))
  358. ((ra o i0) (%ra-set! ra o i0))
  359. ((ra o i0 i1) (%ra-set! ra o i0 i1))
  360. ((ra o i0 i1 i2) (%ra-set! ra o i0 i1 i2))
  361. ((ra o i0 i1 i2 i3) (%ra-set! ra o i0 i1 i2 i3))
  362. ((ra o i0 i1 i2 i3 i4) (%ra-set! ra o i0 i1 i2 i3 i4))
  363. ((ra o . i)
  364. (unless (= (ra-rank ra) (length i))
  365. (throw 'bad-number-of-indices (ra-rank ra) (length i)))
  366. ((%%ra-vset! ra) (%%ra-root ra) (apply ra-pos (%%ra-zero ra) (%%ra-dims ra) i) o)
  367. ra)))
  368. (define (ra-slice ra . i)
  369. "
  370. Return the prefix cell of ra @var{a} determined by indices @var{i}. The number
  371. of indices must be no larger than the rank of @var{a}.
  372. This function always returns an array, even if the number of indices is equal to
  373. the rank of @var{a}.
  374. For example:
  375. @lisp
  376. (ra-slice (ra-i 2 3))
  377. @result{} #%2((0 1 2) (4 5 6))
  378. @end lisp
  379. @lisp
  380. (ra-slice (ra-i 2 3) 1)
  381. @result{} #%1(4 5 6)
  382. @end lisp
  383. @lisp
  384. (ra-slice (ra-i 2 3) 1 1)
  385. @result{} #%0(5)
  386. @end lisp
  387. @code{ra-slice} can be used to copy an array descriptor; the return value
  388. contains a fresh copy of the dim vector of @var{ra}.
  389. See also: @code{ra-ref} @code{ra-cell} @code{ra-from}
  390. "
  391. (let ((ra (ra-check ra)))
  392. (make-ra-root (%%ra-root ra)
  393. (vector-drop (%%ra-dims ra) (length i))
  394. (apply ra-pos (%%ra-zero ra) (%%ra-dims ra) i))))
  395. ; Unhappy about writing these things twice.
  396. (define-syntax %ra-cell
  397. (syntax-rules ()
  398. ((_ ra i ...)
  399. (let ((ra (ra-check ra)))
  400. (let ((pos (%ra-pos 0 (%%ra-zero ra) (%%ra-dims ra) i ...))
  401. (leni (%length i ...)))
  402. (if (= (%%ra-rank ra) leni)
  403. ((%%ra-vref ra) (%%ra-root ra) pos)
  404. (make-ra-root (%%ra-root ra) (vector-drop (%%ra-dims ra) leni) pos)))))))
  405. (define-inlinable-case ra-cell
  406. (case-lambda
  407. "
  408. ra-cell a i ...
  409. Return the prefix cell of ra @var{a} determined by indices @var{i}. The number
  410. of indices must be no larger than the rank of @var{a}. If the number of indices
  411. is equal to the rank of @var{a}, then return the corresponding element (same as
  412. @code{ra-ref}) and not a rank-0 cell.
  413. For example:
  414. @lisp
  415. (ra-cell (ra-i 2 3))
  416. @result{} #%2((0 1 2) (4 5 6))
  417. @end lisp
  418. @lisp
  419. (ra-cell (ra-i 2 3) 1)
  420. @result{} #%1(4 5 6)
  421. @end lisp
  422. @lisp
  423. (ra-cell (ra-i 2 3) 1 1)
  424. @result{} 5
  425. @end lisp
  426. See also: @code{ra-ref} @code{ra-slice} @code{ra-from}
  427. "
  428. ((ra) (%ra-cell ra))
  429. ((ra i0) (%ra-cell ra i0))
  430. ((ra i0 i1) (%ra-cell ra i0 i1))
  431. ((ra i0 i1 i2) (%ra-cell ra i0 i1 i2))
  432. ((ra i0 i1 i2 i3) (%ra-cell ra i0 i1 i2 i3))
  433. ((ra i0 i1 i2 i3 i4) (%ra-cell ra i0 i1 i2 i3 i4))
  434. ((ra . i)
  435. (let ((ra (ra-check ra)))
  436. (let ((pos (apply ra-pos (%%ra-zero ra) (%%ra-dims ra) i))
  437. (leni (length i)))
  438. (if (= (%%ra-rank ra) leni)
  439. ((%%ra-vref ra) (%%ra-root ra) pos)
  440. (make-ra-root (%%ra-root ra) (vector-drop (%%ra-dims ra) leni) pos)))))))
  441. ; these depend on accessor/setter.
  442. (define (no-rank-zero A)
  443. (if (zero? (%%ra-rank A)) (%ra-ref A) A))
  444. (define (make-ra* data zero dims type vlen vref vset!)
  445. (letrec ((ra
  446. (make-struct/simple
  447. <ra-vtable>
  448. ; tried catching dim-check exception but it's way too expensive
  449. (case-lambda
  450. (()
  451. (%ra-cell ra))
  452. ((i0)
  453. (if (integer? i0)
  454. (%ra-cell ra i0)
  455. (no-rank-zero (ra-from ra i0))))
  456. ((i0 i1)
  457. (if (and (integer? i0) (integer? i1))
  458. (%ra-cell ra i0 i1)
  459. (no-rank-zero (ra-from ra i0 i1))))
  460. ((i0 i1 i2)
  461. (if (and (integer? i0) (integer? i1) (integer? i2))
  462. (%ra-cell ra i0 i1 i2)
  463. (no-rank-zero (ra-from ra i0 i1 i2))))
  464. ((i0 i1 i2 i3)
  465. (if (and (integer? i0) (integer? i1) (integer? i2) (integer? i3))
  466. (%ra-cell ra i0 i1 i2 i3)
  467. (no-rank-zero (ra-from ra i0 i1 i2 i3))))
  468. ((i0 i1 i2 i3 i4)
  469. (if (and (integer? i0) (integer? i1) (integer? i2) (integer? i3) (integer? i4))
  470. (%ra-cell ra i0 i1 i2 i3 i4)
  471. (no-rank-zero (ra-from ra i0 i1 i2 i3 i4))))
  472. (i
  473. (if (every integer? i)
  474. (apply ra-cell ra i)
  475. (no-rank-zero (apply ra-from ra i)))))
  476. ; it should be easier :-/
  477. (match-lambda*
  478. ((o) (%ra-set! ra o))
  479. ((i0 o) (%ra-set! ra o i0))
  480. ((i0 i1 o) (%ra-set! ra o i0 i1))
  481. ((i0 i1 i2 o) (%ra-set! ra o i0 i1 i2))
  482. ((i0 i1 i2 i3 o) (%ra-set! ra o i0 i1 i2 i3))
  483. ((i0 i1 i2 i3 i4 o) (%ra-set! ra o i0 i1 i2 i3 i4))
  484. ((i ... o) (apply ra-set! ra o i)))
  485. data zero dims type vlen vref vset!)))
  486. ra))
  487. ; low level, for conversions
  488. (define make-ra-root
  489. (case-lambda
  490. "
  491. Make new array from root vector @var{root}, zero index @var{zero} and dim-vector
  492. @var{dims}.
  493. If @var{zero} is absent, it is computed so that the first element of the result
  494. is the first element of the root, that is, @code{(ra-offset ra)} is 0.
  495. If @var{dims} is absent, make a rank-1 array with the full length of @var{root}.
  496. See also: @code{ra-root} @code{ra-zero} @code{ra-dims}
  497. "
  498. ((root dims zero)
  499. (when dims
  500. (unless (vector? dims) (throw 'bad-dims dims))
  501. (vector-for-each (lambda (dim) (unless (dim? dim) (throw 'bad-dim dim))) dims))
  502. ; after check
  503. (let ((type vlen vref vset! (pick-functions root)))
  504. (make-ra* root zero
  505. (or dims (vector (make-dim (vlen root))))
  506. type vlen vref vset!)))
  507. ((root dims)
  508. (make-ra-root root dims (- (ra-offset 0 dims))))
  509. ((root)
  510. (make-ra-root root #f 0))))
  511. ; ----------------
  512. ; derived functions
  513. ; ----------------
  514. ; FIXME avoid list->vector etc.
  515. (define (c-dims . d)
  516. "
  517. Compute dim-vector for C-order (row-major) array of bounds @var{d} ...
  518. Each of the @var{d} ... may be @var{len}, or a bounds pair (@var{lo}
  519. @var{hi}). If @var{len} or @var{hi} is @code{#f}, this creates a dead axis.
  520. The first non-@code{#f} @var{hi} or @var{len} may be @code{#t}; this creates an
  521. unbounded axis.
  522. See also: @code{make-ra-root} @code{make-ra-new}
  523. "
  524. (let ((d (list->vector d)))
  525. (let loop ((i (- (vector-length d) 1)) (step 1))
  526. (if (negative? i)
  527. d
  528. (match (vector-ref d i)
  529. ((lo #f)
  530. (vector-set! d i (make-dim #f lo 0))
  531. (loop (- i 1) step))
  532. ((lo #t)
  533. (vector-set! d i (make-dim #f lo step))
  534. (loop (- i 1) #f))
  535. ((lo hi)
  536. (let ((len (- hi lo -1)))
  537. (vector-set! d i (make-dim len lo step))
  538. (loop (- i 1) (* len step))))
  539. (#t
  540. (vector-set! d i (make-dim #f 0 step))
  541. (loop (- i 1) #f))
  542. (#f
  543. (vector-set! d i (make-dim #f 0 0))
  544. (loop (- i 1) step))
  545. (len
  546. (vector-set! d i (make-dim len 0 step))
  547. (loop (- i 1) (* len step))))))))
  548. (define (make-ra-new type value dims)
  549. "
  550. Make new array of @var{type} from dim-vector @var{dims}, and fill it with
  551. @var{value}. @var{value} may be @code{*unspecified*}.
  552. See also: @code{make-dim} @code{ra-dims} @code{make-ra-root} @code{c-dims}
  553. "
  554. (let ((size (vector-fold
  555. (lambda (dim c)
  556. (match dim
  557. (($ <dim> len _ step)
  558. (* c (or len (if (zero? step)
  559. 1
  560. (throw 'cannot-make-new-ra-with-dims dims)))))))
  561. 1 dims))
  562. (make (pick-make type)))
  563. (make-ra-root (if (unspecified? value) (make size) (make size value))
  564. dims
  565. (- (ra-offset 0 dims)))))
  566. ; ----------------
  567. ; misc functions for Guile compatibility
  568. ; ----------------
  569. (define (ra-shape ra)
  570. "
  571. Return a list with the lower and upper bounds of each dimension of @var{ra}.
  572. @lisp
  573. (ra-shape (make-ra 'foo '(-1 3) 5)) ==> ((-1 3) (0 4))
  574. @end lisp
  575. See also: @code{ra-rank} @code{ra-dimensions} @code{ra-len}
  576. "
  577. (map (match-lambda
  578. (($ <dim> len lo _)
  579. (list lo (dim-hi len lo))))
  580. (vector->list (ra-dims ra))))
  581. (define (ra-dimensions ra)
  582. "
  583. Like ra-shape, but if the lower bound for a given dimension is zero, return
  584. the size of that dimension instead of a lower bound - upper bound pair.
  585. @lisp
  586. (ra-shape (make-ra 'foo '(-1 3) 5)) ==> ((-1 3) (0 4))
  587. (ra-dimensions (make-ra 'foo '(-1 3) 5)) ==> ((-1 3) 5)
  588. @end lisp
  589. See also: @code{ra-rank} @code{ra-shape} @code{ra-len}
  590. "
  591. (map (match-lambda
  592. (($ <dim> len lo _)
  593. (if (or (not lo) (zero? lo))
  594. len
  595. (list lo (dim-hi len lo)))))
  596. (vector->list (ra-dims ra))))
  597. (define* (ra-len ra #:optional (k 0))
  598. "
  599. Return the length of axis @var{k} of array @var{ra}. @var{k} defaults to 0. It
  600. is an error if @var{ra} has zero rank.
  601. See also: @code{ra-shape} @code{ra-dimensions} @code{ra-size} @code{ra-lo}
  602. "
  603. (dim-len (vector-ref (ra-dims ra) k)))
  604. (define* (ra-lo ra #:optional (k 0))
  605. "
  606. Return the lower bound of axis @var{k} of array @var{ra}. @var{k} defaults to
  607. 0. It is an error if @var{ra} has zero rank.
  608. See also: @code{ra-shape} @code{ra-dimensions} @code{ra-len}
  609. "
  610. (dim-lo (vector-ref (ra-dims ra) k)))
  611. (define* (ra-size ra #:optional (n (ra-rank ra)) (org 0))
  612. "
  613. Return the product of the lengths of axes [@var{org} .. @var{org}+@var{n}) of
  614. @var{ra}.
  615. @var{n} defaults to the rank of @var{ra} and @var{org} defaults to 0, so by
  616. default @code{(ra-size ra)} will return the number of elements of
  617. @var{ra}. Arrays of rank 0 have size 1.
  618. See also: @code{ra-shape} @code{ra-dimensions} @code{ra-len}
  619. "
  620. (vector-fold* n org (lambda (d s) (* s (dim-len d))) 1 (ra-dims ra)))