home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / scheme / pcscheme / geneva / pcscheme.exe / SAMPLES / ARRAY.S next >
Encoding:
Internet Message Format  |  1993-05-13  |  11.4 KB

  1. From news.unige.ch!scsing.switch.ch!ira.uka.de!yale.edu!qt.cs.utexas.edu!cs.utexas.edu!sun-barr!olivea!mintaka.lcs.mit.edu!mintaka.lcs.mit.edu!alan Mon Feb 22 10:27:37 1993
  2. Path: news.unige.ch!scsing.switch.ch!ira.uka.de!yale.edu!qt.cs.utexas.edu!cs.utexas.edu!sun-barr!olivea!mintaka.lcs.mit.edu!mintaka.lcs.mit.edu!alan
  3. From: alan@lcs.mit.edu (Alan Bawden)
  4. Newsgroups: comp.lang.scheme
  5. Subject: Re: multi-dimensional arrays in R5RS?
  6. Message-ID: <ALAN.93Feb21005639@cayenne.lcs.mit.edu>
  7. Date: 21 Feb 93 05:56:39 GMT
  8. References: <1993Feb18.174309.4517@cs.uoregon.edu>
  9.     <1993Feb18.154049.6310@news.cs.indiana.edu>
  10.     <1993Feb18.210843.16088@cs.uoregon.edu>
  11.     <1993Feb19.142555.15696@news.cs.indiana.edu>
  12.     <CARLTON.93Feb19220914@husc11.harvard.edu>
  13. Sender: news@mintaka.lcs.mit.edu
  14. Organization: ITS Preservation Society
  15. Lines: 326
  16. In-Reply-To: carlton@husc11.harvard.edu's message of 20 Feb 93 06:09:14 GMT
  17.  
  18. In article <CARLTON.93Feb19220914@husc11.harvard.edu> 
  19. carlton@husc11.harvard.edu (david carlton) writes:
  20.  
  21.    In article <1993Feb19.142555.15696@news.cs.indiana.edu>,
  22.    "John Lacey" <johnl@cs.indiana.edu> writes:
  23.    > An implication of this approach to the issue at hand is that the
  24.    > printed representation would be a vector of vectors, but the
  25.    > compiler would see multidimensional array primitives, with all
  26.    > the optimization benefits of that.
  27.    This approach (which I think is a good one) says nothing about the
  28.    printed representation.  The library could provide functions to
  29.    manipulate multidimensional arrays without guaranteeing anything at
  30.    all about their printed representation or their representation.
  31.  
  32. Right.
  33.  
  34. The most peculiar thing to me about this discussion of arrays for Scheme is
  35. the seemingly widespread notion that arrays should be somehow identified
  36. with vectors that contain vectors.  (One common corollary of this belief
  37. seems to be that if you don't have native arrays, you -have- to use vectors
  38. of vectors -- which is inefficient.)
  39.  
  40. Well, let me point out that the difference between a vector and an array is
  41. really just some arithmetic performed on the indices.  If I'm writing a
  42. program that does a lot of manipulating of 4x4 matrices, I can do as well
  43. as any native array implementation by using 16 element vectors, and writing
  44.  
  45.   (vector-ref M (+ (* 4 i) j))
  46.  
  47. instead of
  48.  
  49.   (array-ref M i j)
  50.  
  51. If I write my loops so that, in fact, I process the elements of the matrix
  52. in the order that they are layed out in the vector, then a good compiler
  53. should be able to do just as well is it could if I used native arrays.
  54.  
  55. In order to drive this point home, here is an implementation of arrays for
  56. scheme that works by abstracting out the index arithmetic.  This makes it
  57. trivial to provide shared subarrays.  In fact, this approach gets you a lot
  58. more than you could ever get by simply using vectors of vectors.
  59.  
  60. (This code has -not- been thoroughly debugged -- near the end there are a
  61. bunch of little functions that I wrote by hand that have not been
  62. exhaustively tested and could easily contain typos.)
  63.  
  64. ------- Begin arrays.scm
  65.  
  66. ; Arrays for Scheme
  67. ;
  68. ; Copyright (C) 1993 Alan Bawden
  69. ;
  70. ; You may use this code any way you like, as long as you don't charge money
  71. ; for it, remove this notice, or hold me liable for its results.
  72.  
  73. ; The user interface consists of the following 5 functions
  74. ;   (ARRAY? <object>)  =>  <boolean>
  75. ;   (MAKE-ARRAY <initial-value> <bound> <bound> ...)  =>  <array>
  76. ;   (ARRAY-REF <array> <index> <index> ...)  =>  <value>
  77. ;   (ARRAY-SET! <array> <new-value> <index> <index> ...)
  78. ;   (MAKE-SHARED-ARRAY <array> <mapper> <bound> <bound> ...)  =>  <array>
  79. ;
  80. ; When constructing an array, <bound> is either an inclusive range of
  81. ; indices expressed as a two element list, or an upper bound expressed as a
  82. ; single integer.  So
  83. ;
  84. ;   (make-array 'foo 3 3)
  85. ;
  86. ; and
  87. ;
  88. ;   (make-array 'foo '(0 2) '(0 2))
  89. ;
  90. ; are equivalent.
  91. ;
  92. ; MAKE-SHARED-ARRAY can be used to create shared subarrays of other arrays.
  93. ; The <mapper> is a function that translates coordinates in the new array
  94. ; into coordinates in the old array.  A <mapper> must be linear, and its
  95. ; range must stay within the bounds of the old array, but it can be
  96. ; otherwise arbitrary.  A simple example:
  97. ;
  98. ;   (define fred (make-array #F 8 8))
  99. ;   (define freds-diagonal
  100. ;     (make-shared-array fred (lambda (i) (list i i)) 8))
  101. ;   (array-set! freds-diagonal 'foo 3)
  102. ;   (array-ref fred 3 3)  =>  FOO
  103. ;   (define freds-center
  104. ;     (make-shared-array fred (lambda (i j) (list (+ 3 i) (+ 3 j))) 2 2))
  105. ;   (array-ref freds-center 0 0)  =>  FOO
  106. ;
  107. ; End of manual.
  108.  
  109. ; If you comment out the bounds checking code, this is about as efficient
  110. ; as you could ask for without help from the compiler.
  111. ;
  112. ; An exercise left to the reader: implement the rest of APL.
  113. ;
  114. ; Functions not part of the user interface have names that start with
  115. ; "array/" (the poor man's package system).
  116. ;
  117. ; This assumes your Scheme has the usual record type package.
  118.  
  119. (define array/rtd
  120.   (make-record-type "Array"
  121.     '(vector
  122.       indexer        ; Must be a -linear- function!
  123.       shape)))
  124.  
  125. (define array/vector (record-accessor array/rtd 'vector))
  126. (define array/indexer (record-accessor array/rtd 'indexer))
  127. (define array/shape (record-accessor array/rtd 'shape))
  128.  
  129. (define array? (record-predicate array/rtd))
  130.  
  131. (define array/construct
  132.   (record-constructor array/rtd '(vector indexer shape)))
  133.  
  134. (define (array/compute-shape specs)
  135.   (map (lambda (spec)
  136.      (cond ((and (integer? spec)
  137.              (< 0 spec))
  138.         (list 0 (- spec 1)))
  139.            ((and (pair? spec)
  140.              (pair? (cdr spec))
  141.              (null? (cddr spec))
  142.              (integer? (car spec))
  143.              (integer? (cadr spec))
  144.              (<= (car spec) (cadr spec)))
  145.         spec)
  146.            (else (error "Bad array dimension: ~S" spec))))
  147.        specs))
  148.  
  149. (define (make-array initial-value . specs)
  150.   (let ((shape (array/compute-shape specs)))
  151.     (let loop ((size 1)
  152.            (indexer (lambda () 0))
  153.            (l (reverse shape)))
  154.       (if (null? l)
  155.       (array/construct (make-vector size initial-value)
  156.                (array/optimize-linear-function indexer
  157.                                (length shape))
  158.                shape)
  159.       (loop (* size (+ 1 (- (cadar l) (caar l))))
  160.         (lambda (first-index . rest-of-indices)
  161.           (+ (* size (- first-index (caar l)))
  162.              (apply indexer rest-of-indices)))
  163.         (cdr l))))))
  164.  
  165. (define (make-shared-array array mapping . specs)
  166.   (let ((new-shape (array/compute-shape specs))
  167.     (old-indexer (array/indexer array)))
  168.     (let check ((indices '())
  169.         (bounds (reverse new-shape)))
  170.       (cond ((null? bounds)
  171.          (array/check-bounds array (apply mapping indices)))
  172.         (else
  173.          (check (cons (caar bounds) indices) (cdr bounds))
  174.          (check (cons (cadar bounds) indices) (cdr bounds)))))
  175.     (array/construct (array/vector array)
  176.              (array/optimize-linear-function
  177.                (lambda indices
  178.              (apply old-indexer (apply mapping indices)))
  179.                (length new-shape))
  180.              new-shape)))
  181.  
  182. (define (array/in-bounds? array indices)
  183.   (let loop ((indices indices)
  184.          (shape (array/shape array)))
  185.     (if (null? indices)
  186.     (null? shape)
  187.     (let ((index (car indices)))
  188.       (and (not (null? shape))
  189.            (integer? index)
  190.            (<= (caar shape) index (cadar shape))
  191.            (loop (cdr indices) (cdr shape)))))))
  192.  
  193. (define (array/check-bounds array indices)
  194.   (or (array/in-bounds? array indices)
  195.       (error "Bad indices for ~S: ~S" array indices)))
  196.  
  197. (define (array-ref array . indices)
  198.   (array/check-bounds array indices)
  199.   (vector-ref (array/vector array)
  200.           (apply (array/indexer array) indices)))
  201.  
  202. (define (array-set! array new-value . indices)
  203.   (array/check-bounds array indices)
  204.   (vector-set! (array/vector array)
  205.            (apply (array/indexer array) indices)
  206.            new-value))
  207.  
  208. ; STOP!  Do not read beyond this point on your first reading of
  209. ; this code -- you should simply assume that the rest of this file
  210. ; contains only the following single definition:
  211. ;
  212. ;   (define (array/optimize-linear-function f d) f)
  213. ;
  214. ; Of course everything would be pretty inefficient if this were really the
  215. ; case, but it isn't.  The following code takes advantage of the fact that
  216. ; you can learn everything there is to know from a linear function by
  217. ; simply probing around in its domain and observing its values -- then a
  218. ; more efficient equivalent can be constructed.
  219.  
  220. (define (array/optimize-linear-function f d)
  221.   (cond ((= d 0)
  222.      (array/0d-c (f)))
  223.     ((= d 1)
  224.      (let ((c (f 0)))
  225.        (array/1d-c0 c (- (f 1) c))))
  226.     ((= d 2)
  227.      (let ((c (f 0 0)))
  228.        (array/2d-c01 c (- (f 1 0) c) (- (f 0 1) c))))
  229.     ((= d 3)
  230.      (let ((c (f 0 0 0)))
  231.        (array/3d-c012 c (- (f 1 0 0) c) (- (f 0 1 0) c) (- (f 0 0 1) c))))
  232.     (else
  233.      (let* ((v (make-list d 0))
  234.         (c (apply f v)))
  235.        (let loop ((p v)
  236.               (old-val c)
  237.               (coefs '()))
  238.          (cond ((null? p)
  239.             (array/Nd-c* c (reverse coefs)))
  240.            (else
  241.             (set-car! p 1)
  242.             (let ((new-val (apply f v)))
  243.               (loop (cdr p)
  244.                 new-val
  245.                 (cons (- new-val old-val) coefs))))))))))
  246.  
  247. ; 0D cases:
  248.  
  249. (define (array/0d-c c)
  250.   (lambda () c))
  251.  
  252. ; 1D cases:
  253.  
  254. (define (array/1d-c c)
  255.   (lambda (i0) (+ c i0)))
  256.  
  257. (define (array/1d-0 n0)
  258.   (cond ((= 1 n0) +)
  259.     (else (lambda (i0) (* n0 i0)))))
  260.  
  261. (define (array/1d-c0 c n0)
  262.   (cond ((= 0 c) (array/1d-0 n0))
  263.     ((= 1 n0) (array/1d-c c))
  264.     (else (lambda (i0) (+ c (* n0 i0))))))
  265.  
  266. ; 2D cases:
  267.  
  268. (define (array/2d-0 n0)
  269.   (lambda (i0 i1) (+ (* n0 i0) i1)))
  270.  
  271. (define (array/2d-1 n1)
  272.   (lambda (i0 i1) (+ i0 (* n1 i1))))
  273.  
  274. (define (array/2d-c0 c n0)
  275.   (lambda (i0 i1) (+ c (* n0 i0) i1)))
  276.  
  277. (define (array/2d-c1 c n1)
  278.   (lambda (i0 i1) (+ c i0 (* n1 i1))))
  279.  
  280. (define (array/2d-01 n0 n1)
  281.   (cond ((= 1 n0) (array/2d-1 n1))
  282.     ((= 1 n1) (array/2d-0 n0))
  283.     (else (lambda (i0 i1) (+ (* n0 i0) (* n1 i1))))))
  284.  
  285. (define (array/2d-c01 c n0 n1)
  286.   (cond ((= 0 c) (array/2d-01 n0 n1))
  287.     ((= 1 n0) (array/2d-c1 c n1))
  288.     ((= 1 n1) (array/2d-c0 c n0))
  289.     (else (lambda (i0 i1) (+ c (* n0 i0) (* n1 i1))))))
  290.  
  291. ; 3D cases:
  292.  
  293. (define (array/3d-01 n0 n1)
  294.   (lambda (i0 i1 i2) (+ (* n0 i0) (* n1 i1) i2)))
  295.  
  296. (define (array/3d-02 n0 n2)
  297.   (lambda (i0 i1 i2) (+ (* n0 i0) i1 (* n2 i2))))
  298.  
  299. (define (array/3d-12 n1 n2)
  300.   (lambda (i0 i1 i2) (+ i0 (* n1 i1) (* n2 i2))))
  301.  
  302. (define (array/3d-012 n0 n1 n2)
  303.   (lambda (i0 i1 i2) (+ (* n0 i0) (* n1 i1) (* n2 i2))))
  304.  
  305. (define (array/3d-c12 c n1 n2)
  306.   (lambda (i0 i1 i2) (+ c i0 (* n1 i1) (* n2 i2))))
  307.  
  308. (define (array/3d-c02 c n0 n2)
  309.   (lambda (i0 i1 i2) (+ c (* n0 i0) i1 (* n2 i2))))
  310.  
  311. (define (array/3d-c01 c n0 n1)
  312.   (lambda (i0 i1 i2) (+ c (* n0 i0) (* n1 i1) i2)))
  313.  
  314. (define (array/3d-012 n0 n1 n2)
  315.   (cond ((= 1 n0) (array/3d-12 n1 n2))
  316.     ((= 1 n1) (array/3d-02 n0 n2))
  317.     ((= 1 n2) (array/3d-01 n0 n1))
  318.     (else (lambda (i0 i1 i2) (+ (* n0 i0) (* n1 i1) (* n2 i2))))))
  319.  
  320. (define (array/3d-c012 c n0 n1 n2)
  321.   (cond ((= 0 c) (array/3d-012 n0 n1 n2))
  322.     ((= 1 n0) (array/3d-c12 c n1 n2))
  323.     ((= 1 n1) (array/3d-c02 c n0 n2))
  324.     ((= 1 n2) (array/3d-c01 c n0 n1))
  325.     (else (lambda (i0 i1 i2) (+ c (* n0 i0) (* n1 i1) (* n2 i2))))))
  326.  
  327. ; ND cases:
  328.  
  329. (define (array/Nd-* coefs)
  330.   (lambda indices (apply + (map * coefs indices))))
  331.  
  332. (define (array/Nd-c* c coefs)
  333.   (cond ((= 0 c) (array/Nd-* coefs))
  334.     (else (lambda indices (apply + c (map * coefs indices))))))
  335.  
  336. ------- End arrays.scm
  337. --
  338.  
  339. --
  340. Alan Bawden                               Alan@LCS.MIT.EDU
  341. Work: MIT Room NE43-510, 545 Tech. Sq., Cambridge, MA 02139     (617) 253-7328
  342. Home: 29 Reed St., Cambridge, MA 02140                 (617) 492-7274
  343.  
  344.