home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #20 / NN_1992_20.iso / spool / comp / lang / lisp / 2444 < prev    next >
Encoding:
Text File  |  1992-09-15  |  12.6 KB  |  383 lines

  1. Newsgroups: comp.lang.lisp
  2. Path: sparky!uunet!statsci!almond
  3. From: almond@statsci.com (Russell G. Almond)
  4. Subject: Re: copy-array?
  5. In-Reply-To: barmar@think.com's message of 14 Sep 92 23:01:51 GMT
  6. Message-ID: <ALMOND.92Sep15190205@bass.statsci.com>
  7. Sender: usenet@statsci.com (Usenet News Account)
  8. Organization: Statistical Sciences, Inc., Seattle, WA USA
  9. References: <9209142212.AA24213@brownie.cs.wisc.edu> <1935kvINNi3f@early-bird.think.com>
  10. Date: Wed, 16 Sep 1992 03:02:05 GMT
  11. Lines: 370
  12.  
  13. In article <1935kvINNi3f@early-bird.think.com> barmar@think.com (Barry Margolin) writes:
  14.  
  15.    In article <9209142212.AA24213@brownie.cs.wisc.edu> so@CS.WISC.EDU (Bryan S. So) writes:
  16.    >This is almost the first time I seriously use arrays
  17.    >in Common Lisp.  Now, how come there is no intrinsic
  18.    >function to make a copy of an array?
  19.  
  20.    There was a proposal in X3J13 to extend some of the sequence functions to
  21.    work on multidimensional arrays, but it was voted down.  That would have
  22.    enabled COPY-SEQ to do what you want.
  23.  
  24.    It's kind of a shame that a multidimensional array can't be used as the
  25.    :INITIAL-CONTENTS argument for MAKE-ARRAY, even when it matches the
  26.    dimensionality of the array being built.  Then you could do:
  27.  
  28.    (make-array ... :initial-contents old-array)
  29.  
  30.    >The only algorithm I have is to make a new array then
  31.    >assign the elements one by one.  Is there an easier/
  32.    >more efficient method to do this?
  33.  
  34.    You can do it using displaced arrays and MAP-INTO:
  35.  
  36.    [ ... ]
  37.  
  38. The problem is a little bit more general than you think.  There are
  39. actually many cases in which you would like to think of an array as a
  40. vector and perform operations on all elements.  S (and S-PLUS) which
  41. are primarily statistics languages do this, and I've found myself
  42. wanting it so much in LISP that I created a specialized structure to
  43. do it, I call a d-array.  It basically supports an array and a vector
  44. displaced to the same location in storage. If you modify the one, it
  45. modified the other.  I haven't had efficiency problems because its
  46. displaced.
  47.  
  48. Code follows .sig.
  49.  
  50.  
  51.             Russell Almond               
  52. Statistical Sciences, Inc.        U. Washington
  53. 1700 Westlake Ave., N Suite 500        Statistics, GN-22
  54. Seattle, WA  98109            Seattle, WA  98195
  55. (206) 283-8802                
  56. almond@statsci.com            almond@stat.washington.edu
  57.  
  58.  
  59.  
  60.  
  61. ;;; -*- mode: fi:common-lisp; package: rga-utils -*-
  62.  
  63. ;;; Copyright 1992 Russell G. Almond
  64.  
  65. ;;; This code is in the Public Domain.  Anyone who can get some use
  66. ;;; from it is welcome.
  67. ;;; This code come with no warentee.
  68.  
  69. (in-package :rga)
  70.  
  71. ;;;; d-arrays.lisp
  72.  
  73. ;;; This code contains a series of utilities for manipulating arrays.
  74. ;;; In particular it sets up a structure called a d-array which is an
  75. ;;; array with a vector displaced to its contents.  These are much
  76. ;;; easier for certain operations.
  77.  
  78.  
  79.  
  80. ;;; First some functions mandated by X3J13 which have not made it into
  81. ;;; all versions of Common Lisp
  82.  
  83.  
  84.  
  85. #+:cmu(defun map-into (result funct &rest sequences)
  86.   "When this definition generates an error comment it out!"
  87.   (declare (type Sequence result)
  88.        (type Function funct))
  89.   (let ((out-length (if (and (vectorp result)
  90.                  (array-has-fill-pointer-p result))
  91.             (array-total-size result)
  92.               (length result))))
  93.     (if (eql 0 out-length) (return 'map-into result))
  94.     (let* ((in-length (apply #'min out-length
  95.                 (mapcar #'length sequences)))
  96.        (dummy-variables (mapcar #'(lambda (x) (gensym)) sequences))
  97.        (loop-as-clauses
  98.         (mapcan #'(lambda (x x-seq)
  99.             (list 'as x (if (listp x-seq) 'in
  100.                       'across)
  101.                   x-seq))
  102.             dummy-variables sequences)))
  103.       (eval `(loop
  104.         for which-el from 0 to ,in-length
  105.         ,@loop-as-clauses
  106.          do (setf (elt ,result which-el)
  107.               (funcall ,funct ,@dummy-variables))
  108.             ))
  109.       (if (array-has-fill-pointer-p result)
  110.       (setf (fill-pointer result) in-length))
  111.       result)))
  112. ;;; It is unclear what should happen when map-into is called with
  113. ;;; result and adjustable array whose total-length is less than the
  114. ;;; min length of the other sequences.  We will assume that if this is
  115. ;;; the case, iteration terminates when we reach the last function in
  116. ;;; the sequence.
  117.  
  118.  
  119.  
  120.  
  121. #+:excl(excl:without-package-locks
  122. (defun row-major-aref (array index)
  123.   (declare (type Array array) (type Fixnum index))
  124.   "Comment this code out if your implementation supports it!"
  125.   (aref (make-array (array-total-size array)
  126.             :displaced-to array
  127.             :element-type (array-element-type array))
  128.     index))
  129.     
  130. (defun (setf row-major-aref) (array index value)
  131.   (declare (type Array array) (type Fixnum index) (type T value))
  132.   "Comment this code out if your implementation supports it!"
  133.   (setf (aref (make-array (array-total-size array)
  134.             :displaced-to array
  135.             :element-type (array-element-type array))
  136.     index)
  137.     value))
  138. )
  139.  
  140. ;;;----------------------------------------------------------------------
  141. ;;; Common-lisp syntax extension.
  142.  
  143. ;;; These functions deal with setting elements of an array using a
  144. ;;; list of the indexies rather than an including the index of the
  145. ;;; lists directly.
  146. (declaim (inline elt-array set-elt-array))
  147. (defun elt-array (array indexlist)
  148.   (declare (type Array array) (type List indexlist)
  149.        (:returns (type T)))
  150.   "Access element marked by <indexlist> in <array>.  Allows
  151. <indexlist> to be treated as a single entity."
  152.   (apply #'aref array indexlist))
  153.  
  154. (defun set-elt-array (array indexlist value)
  155.   (declare (type Array array) (type List indexlist)
  156.        (type T value)
  157.        (:returns (type T value)))
  158.   "Access element marked by <indexlist> in <array>.  Allows
  159. <indexlist> to be treated as a single entity."
  160.   (setf (apply #'aref array indexlist) value))
  161.  
  162.  
  163. (defsetf elt-array set-elt-array
  164.     "Access element marked by <indexlist> in <array>.  Allows
  165. <indexlist> to be treated as a single entity."
  166.     )
  167. ;(declaim (inline (setf elt-array)))
  168.  
  169.  
  170. ;
  171. ;;;----------------------------------------------------------------------
  172. ;;; Floating Point defaults.
  173. ;;;----------------------------------------------------------------------
  174.  
  175. (defvar user::*rga-precision* `Double-Float
  176.   "Default precsions for operations.  Should usually be Long-Float or
  177. Double-Float.  Could be set in you init file.")
  178.  
  179.  
  180. (deftype Default-Precision ()
  181.   "Default Floating Point Type."
  182.   user::*rga-precision*)
  183.  
  184. (deftype Default-Array (&rest dims)
  185.   "Default Floating Point Type Array."
  186.   (list* 'array user::*rga-precision* dims))
  187.  
  188. (deftype Default-Vector (&rest dims)
  189.   "Default Floating Point Type Vector."
  190.   (list* 'array user::*rga-precision* dims))
  191.  
  192.  
  193. (defconstant *0* (coerce 0.0 *rga-precision*))
  194. (defconstant *1* (coerce 1.0 *rga-precision*))
  195. (defconstant *-1* (coerce -1.0 *rga-precision*))
  196.  
  197. ;;; Type casting functions to switch between arrays and vectors.
  198.  
  199. (defun as-vector (arr &optional (type (array-element-type arr)))
  200.   (declare (type Array arr)
  201.        (:returns (type vector vec)))
  202.   "Unwraps array <arr> into a vector <vec> of the same element type." 
  203.   (make-array (array-total-size arr) :displaced-to arr
  204.           :element-type type)) 
  205.  
  206. (defun as-array (dims vec &optional (type (array-element-type vec)))
  207.   (declare (type Vector vec) (type List dims)
  208.        (:returns (type Array arr)))
  209.   "Wraps vector <vec> into an array <arr> of the same element type
  210. with dimensions <dims>." 
  211.   (make-array dims :displaced-to vec :element-type type)) 
  212.  
  213.  
  214. (defun copy-array (arr)
  215.   "Copies array <arr> yielding a fresh array with same contents as <arr>."
  216.   (declare (type Array arr)
  217.        (:returns (type Array)))
  218.   (as-array (array-dimensions arr)
  219.         (copy-seq (as-vector arr))
  220.         (array-element-type arr)))
  221.  
  222.  
  223.  
  224. ;;; linear-comb -- forms the linear combination of serval arrays given
  225. ;;; a series of co-efficients.  As this thing use mapcar to do its
  226. ;;; basic operation, if the lists are of unequal length the shorter
  227. ;;; one is used.  
  228. (defun linear-comb (array-list weight-list
  229.             &key (result
  230.               (make-array (array-dimensions (car array-list))
  231.                       :element-type
  232.                       (array-element-type (car array-list))
  233.                       )))
  234.   (declare (type List array-list) (type List weight-list)
  235.        (type Default-Array result)
  236.        (:returns (type Array weighted-sum)))
  237.   "Produces a linear cominbation of arrays in <array-list> using
  238. numbers in <weight-list> to do its work."
  239.   (let ((vec-list (mapcar #'as-vector array-list))
  240.     (res-vec (as-vector result)))
  241.     (map-into res-vec #'(lambda (&rest args)
  242.               (weight-sum weight-list args))
  243.           vec-list)
  244.     result))
  245.  
  246. ;; weight-sum -- takes a list of weights and then the rest of the
  247. ;; arguments are assumed to be things to be summed with the weights
  248. (defun weight-sum (weight-list obj-list)
  249.   (declare (type List weight-list obj-list)
  250.        (:returns (type Number linear-comb)))
  251.   "Produces a weighted sum of <obj-list> using weights in
  252. <weight-list>." 
  253.   (reduce #'+ (mapcar #'* weight-list obj-list)))
  254.  
  255.  
  256.  
  257.  
  258.  
  259.  
  260. ;
  261. ;;;----------------------------------------------------------------------
  262. ;;; d-arrays
  263. ;;;----------------------------------------------------------------------
  264.  
  265. ;;; D-arrays have both vector and array specifications.
  266.  
  267.  
  268. (defstruct (d-array (:conc-name d-)
  269.                 (:constructor %make-d-array (arr vec))
  270.                 (:copier nil)
  271.                 (:predicate d-array?)
  272.                 (:print-function
  273.                  (lambda (d-array s k)
  274.                (if *print-readably*
  275.                (format s "(as-d-array ~S)"
  276.                    (d-arr d-array))
  277.              (format s "#<D-array ~S>"
  278.                  (d-arr d-array))))))
  279.   "Provides a convenient-method for refering to an array as either an
  280. array or a vector.  Accessors are #'d-arr and #'d-vec."
  281.   (arr #() :type array :read-only t)
  282.   (vec #() :type vector :read-only t))
  283.         
  284.  
  285. #-cmu(defmethod make-load-form ((self D-Array))
  286.        (make-load-form-saving-slots self))
  287.  
  288. ;;; Construction Functions
  289.  
  290. (defun make-d-array (dims &key (element-type *rga-precision*)
  291.                    (initial-element *0*)
  292.                    (initial-contents nil)
  293.                    (adjustable nil)
  294.                    (displaced-to nil)
  295.                    (displaced-index-offset 0))
  296.   "Creates a D-array using a synatic similar to make-array.  First
  297. array is made using make-array.  Next a vector is made displaced to
  298. that array.  The two are stored in a d-array structure which is
  299. returned. "
  300.   (declare (type List dims)
  301.        (type T element-type)
  302.        (type T initial-element)
  303.        (type Sequence initial-contents)
  304.        (type T adjustable)
  305.        (type (or Null Array) displaced-to)
  306.        (type Integer displaced-index-offset)
  307.        (:returns (type D-array)))
  308.   (let* ((arr (apply #'make-array dims :element-type element-type
  309.              :adjustable adjustable :fill-pointer nil
  310.              (cond (displaced-to
  311.                 (list :displaced-to displaced-to
  312.                   :displaced-index-offset
  313.                   displaced-index-offset))
  314.                (initial-contents 
  315.                 (list :initial-contents initial-contents))
  316.                (t (list :initial-element initial-element)))))
  317.      (vec (make-array (array-total-size arr) :element-type element-type
  318.               :displaced-to arr)))
  319.     (%make-d-array arr vec)))
  320.  
  321.     
  322. (defun force-d-array (array)
  323.   "Turns an array into a d-array."
  324.   (declare (type Array array)
  325.        (:returns (type D-Array)))
  326.   (%make-d-array array (make-array (array-total-size array)
  327.                  :element-type (array-element-type array)
  328.                  :displaced-to array)))
  329.  
  330. (defun coerce-d-array (dims vector)
  331.   "Turns a vector into a d-array with dimensions <dims>."
  332.   (declare (type List dims)
  333.        (type Array array)
  334.        (:returns (type D-Array)))
  335.   (%make-d-array (make-array dims
  336.                  :element-type (array-element-type vector)
  337.                  :displaced-to vector)
  338.          vector))
  339.  
  340.  
  341. (defun copy-d-array (old-array &key result)
  342.   "Copies <old-array> into a new location.  If <result> is given it
  343. must be a d-array of the same total-size as <old-array> and of the
  344. same element type."
  345.   (if result
  346.       (if (and (eql (array-element-type (d-arr old-array))
  347.             (array-element-type (d-arr result)))
  348.            (eql (array-total-size (d-arr old-array))
  349.             (array-total-size (d-arr result))))
  350.       (map-into (d-vec result) #'identity (d-vec old-array))
  351.     (error "~S and ~S do not match on size or element-type.~%"
  352.            old-array result))
  353.     (setq result
  354.       (coerce-d-array (array-dimensions (d-arr old-array))
  355.               (copy-seq (d-vec old-array)))))
  356.   result)
  357.  
  358.                    
  359.                    
  360. (defun d-linear-comb (d-array-list weight-list
  361.               &key (result
  362.                 (make-d-array (array-dimensions
  363.                        (d-arr (car d-array-list)))
  364.                       :element-type
  365.                       (array-element-type
  366.                        (d-arr (car d-array-list)))
  367.                       )))
  368.   (declare (type List d-array-list) (type List weight-list)
  369.        (type D-Array result)
  370.        (:returns (type Array weighted-sum)))
  371.   "Produces a linear cominbation of arrays in <array-list> using
  372. numbers in <weight-list> to do its work."
  373.   (let ((vec-list (mapcar #'d-vec d-array-list))
  374.     (res-vec (d-vec result)))
  375.     (apply #'map-into res-vec #'(lambda (&rest args)
  376.                   (weight-sum weight-list args))
  377.        vec-list)
  378.     result))
  379.  
  380.  
  381.  
  382.  
  383.