[alexandria.git] updated branch master: 485544d generic MEAN and MEDIAN, new function DISPLACE-ARRAY

Nikodemus Siivola nsiivola at common-lisp.net
Fri Jan 20 15:34:24 UTC 2012


The branch master has been updated:
       via  485544d4feb13d3f463f54a5605b3a480bc49046 (commit)
       via  36800ad120545e48e80ce5f2defacf6366ea8404 (commit)
       via  d92432dde897c8f249c377c727bc68d54efb1ddf (commit)
      from  77b219a8361b9549aeb8941afc945fa2e3c84eb9 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 485544d4feb13d3f463f54a5605b3a480bc49046
Author: tpapp <tkpapp at gmail.com>
Date:   Wed Jan 4 12:28:39 2012 +0100

    generic MEAN and MEDIAN, new function DISPLACE-ARRAY
    
     Objects other than sequences have means and medians (eg probability
     distributions, arrays, sequences/arrays wrapped in another object, etc), so
     it makes sense to make these functions generic.
    
     DISPLACE-ARRAY is a small utility function that is used in the implementation
     of MEDIAN for arrays, but is also of general utility because it makes the
     creation of displaced arrays simpler, dispensing with the need to specify the
     element type, and offering sensible defaults when one wants vectors.
    
     Also added tests for all the new functions/methods.

commit 36800ad120545e48e80ce5f2defacf6366ea8404
Author: Jyrki Jaakkola <jjkola at email.com>
Date:   Fri Jan 20 16:59:54 2012 +0200

    make Alexandria work with readtable-case :INVERT

commit d92432dde897c8f249c377c727bc68d54efb1ddf
Author: Ryan Davis <ryan at acceleration.net>
Date:   Wed Dec 21 13:20:47 2011 -0500

    convert ENSURE-GETHASH into a macro
    
     Evaluate the default-form only if we actually use it.

-----------------------------------------------------------------------

Summary of changes:
 arrays.lisp      |   11 +++++++++++
 hash-tables.lisp |   10 +++++-----
 numbers.lisp     |   53 +++++++++++++++++++++++++++++++++++++++++++++--------
 package.lisp     |    1 +
 tests.lisp       |   49 +++++++++++++++++++++++++++++++++++++++----------
 types.lisp       |    8 ++++----
 6 files changed, 105 insertions(+), 27 deletions(-)

diff --git a/arrays.lisp b/arrays.lisp
index 76c1879..1f30150 100644
--- a/arrays.lisp
+++ b/arrays.lisp
@@ -16,3 +16,14 @@ arguments."
      (setf (row-major-aref new-array i)
            (row-major-aref array i)))
    new-array))
+
+(declaim (inline displace-array))
+(defun displace-array (array &key (offset 0)
+                                  (dimensions (- (array-total-size array)
+                                               offset)))
+  "Return an array displaced to ARRAY with the given OFFSET and DIMENSIONS.
+Default arguments displace to a vector."
+  (make-array dimensions
+              :displaced-to array
+              :displaced-index-offset offset
+              :element-type (array-element-type array)))
diff --git a/hash-tables.lisp b/hash-tables.lisp
index a574737..65253e7 100644
--- a/hash-tables.lisp
+++ b/hash-tables.lisp
@@ -89,11 +89,11 @@ PLIST. Hash table is initialized using the HASH-TABLE-INITARGS."
       (setf (gethash (car tail) table) (cadr tail)))
     table))
 
-(defun ensure-gethash (key hash-table &optional default)
+(defmacro ensure-gethash (key hash-table &optional default)
   "Like GETHASH, but if KEY is not found in the HASH-TABLE saves the DEFAULT
 under key before returning it. Secondary return value is true if key was
 already in the table."
-  (multiple-value-bind (value ok) (gethash key hash-table)
-    (if ok
-        (values value ok)
-        (values (setf (gethash key hash-table) default) nil))))
+  `(multiple-value-bind (value ok) (gethash ,key ,hash-table)
+     (if ok
+         (values value ok)
+         (values (setf (gethash ,key ,hash-table) ,default) nil))))
diff --git a/numbers.lisp b/numbers.lisp
index 03430cc..7340f26 100644
--- a/numbers.lisp
+++ b/numbers.lisp
@@ -84,21 +84,58 @@ Examples:
 interpolation coefficient V."
    (+ a (* v (- b a))))
 
-(declaim (inline mean))
-(defun mean (sample)
-  "Returns the mean of SAMPLE. SAMPLE must be a sequence of numbers."
-  (/ (reduce #'+ sample) (length sample)))
-
-(declaim (inline median))
-(defun median (sample)
-  "Returns median of SAMPLE. SAMPLE must be a sequence of real numbers."
-  (let* ((vector (sort (copy-sequence 'vector sample) #'<))
+(defgeneric mean (object)
+  (:documentation "Returns the mean of OBJECT.
+Predefined methods work on sequences and arrays of numbers. Users can
+define new methods.")
+  (:method ((object list))
+    (let ((sum 0)
+          (count 0))
+      (declare (fixnum count))
+      (dolist (elt object)
+        (incf sum elt)
+        (incf count))
+      (/ sum count)))
+  (:method ((object vector))
+    ;; Need a separate method for vectors, since
+    ;; they could have fill-pointers which we need to respect.
+    (let ((n (length object)))
+      (/ (loop for index below n
+               summing (aref object index))
+         n)))
+  (:method ((object array))
+    (let ((n (array-total-size object)))
+      (/ (loop for index below n
+               summing (row-major-aref object index))
+         n)))
+  (:method ((object sequence))
+    ;; For implementations supporting custom sequence types.
+    (/ (reduce #'+ object) (length object))))
+
+(defun median-in-place (vector)
+  (declare (vector vector))
+  (let* ((vector (sort vector #'<))
          (length (length vector))
          (middle (truncate length 2)))
     (if (oddp length)
         (aref vector middle)
         (/ (+ (aref vector middle) (aref vector (1- middle))) 2))))
 
+(defgeneric median (object)
+  (:documentation
+   "Returns median of OBJECT.
+Predefined methods work on sequences and arrays of numbers. Users can
+define new methods.")
+  (:method ((object list))
+    (median-in-place (copy-sequence 'vector object)))
+  (:method ((object array))
+    (median-in-place (copy-sequence 'vector (if (vectorp object)
+                                                object
+                                                (displace-array object)))))
+  (:method ((object sequence))
+    ;; For implementations supporting custom sequence types.
+    (median-in-place (copy-sequence 'vector object))))
+
 (declaim (inline variance))
 (defun variance (sample &key (biased t))
   "Variance of SAMPLE. Returns the biased variance if BIASED is true (the default),
diff --git a/package.lisp b/package.lisp
index 673ed30..8bdf060 100644
--- a/package.lisp
+++ b/package.lisp
@@ -101,6 +101,7 @@
    #:array-index
    #:array-length
    #:copy-array
+   #:displace-array
    ;; Sequences
    #:copy-sequence
    #:deletef
diff --git a/tests.lisp b/tests.lisp
index babe0f4..7d7d1ca 100644
--- a/tests.lisp
+++ b/tests.lisp
@@ -47,6 +47,24 @@
        (typep copy 'simple-array)))
  t)
 
+(deftest displace-array.1
+    (displace-array #2A((1 2)
+                        (3 4)))
+  #(1 2 3 4))
+
+(deftest displace-array.2
+    (displace-array #2A((1 2)
+                        (3 4))
+                    :offset 1)
+  #(2 3 4))
+
+(deftest displace-array.3
+    (displace-array #2A((1 2)
+                        (3 4))
+                    :offset 1
+                    :dimensions '(3 1))
+  #2A((2) (3) (4)))
+
 (deftest array-index.1
     (typep 0 'array-index)
   t)
@@ -958,6 +976,12 @@
     (mean '(1 2 10))
   13/3)
 
+(deftest mean.4
+    (mean #2A((1 2 3)
+              (4 5 6)
+              (7 8 9)))
+  5)
+
 (deftest median.1
     (median '(100 0 99 1 98 2 97))
   97)
@@ -966,6 +990,11 @@
     (median '(100 0 99 1 98 2 97 96))
   193/2)
 
+(deftest median.3
+    (median #2A((100 0 99 1)
+                (98 2 97 96)))
+  193/2)
+
 (deftest variance.1
     (variance (list 1 2 3))
   2/3)
@@ -1584,18 +1613,18 @@
   :inherited)
 
 (deftest format-symbol.1
-    (let ((s (format-symbol nil "X-~D" 13)))
+    (let ((s (format-symbol nil '#:x-~d 13)))
       (list (symbol-package s)
-            (symbol-name s)))
-  (nil "X-13"))
+            (string= (string '#:x-13) (symbol-name s))))
+  (nil t))
 
 (deftest format-symbol.2
-    (format-symbol :keyword "SYM-~A" :bolic)
+    (format-symbol :keyword '#:sym-~a (string :bolic))
   :sym-bolic)
 
 (deftest format-symbol.3
     (let ((*package* (find-package :cl)))
-      (format-symbol t "FIND-~A" 'package))
+      (format-symbol t '#:find-~a (string 'package)))
   find-package)
 
 (deftest make-keyword.1
@@ -1657,12 +1686,12 @@
 
 (macrolet
     ((test (type numbers)
-       `(deftest ,(format-symbol t "CDR5.~A" type)
+       `(deftest ,(format-symbol t '#:cdr5.~a (string type))
 	    (let ((numbers ,numbers))
-	      (values (mapcar (of-type ',(format-symbol t "NEGATIVE-~A" type)) numbers)
-		      (mapcar (of-type ',(format-symbol t "NON-POSITIVE-~A" type)) numbers)
-		      (mapcar (of-type ',(format-symbol t "NON-NEGATIVE-~A" type)) numbers)
-		      (mapcar (of-type ',(format-symbol t "POSITIVE-~A" type)) numbers)))
+	      (values (mapcar (of-type ',(format-symbol t '#:negative-~a (string type))) numbers)
+		      (mapcar (of-type ',(format-symbol t '#:non-positive-~a (string type))) numbers)
+		      (mapcar (of-type ',(format-symbol t '#:non-negative-~a (string type))) numbers)
+		      (mapcar (of-type ',(format-symbol t '#:positive-~a (string type))) numbers)))
 	  (t t t nil nil nil nil)
 	  (t t t t nil nil nil)
 	  (nil nil nil t t t t)
diff --git a/types.lisp b/types.lisp
index b806c0d..6aa722f 100644
--- a/types.lisp
+++ b/types.lisp
@@ -34,10 +34,10 @@ ARRAY-DIMENSION-LIMIT."
 			    type
 			    (if (equal range-beg ''*) inf (ensure-car range-beg))
 			    (if (equal range-end ''*) inf (ensure-car range-end))))))
-           (let* ((negative-name     (make-subtype-name '#:negative-~A))
-                  (non-positive-name (make-subtype-name '#:non-positive-~A))
-                  (non-negative-name (make-subtype-name '#:non-negative-~A))
-                  (positive-name     (make-subtype-name '#:positive-~A))
+           (let* ((negative-name     (make-subtype-name '#:negative-~a))
+                  (non-positive-name (make-subtype-name '#:non-positive-~a))
+                  (non-negative-name (make-subtype-name '#:non-negative-~a))
+                  (positive-name     (make-subtype-name '#:positive-~a))
                   (negative-p-name     (make-predicate-name negative-name))
                   (non-positive-p-name (make-predicate-name non-positive-name))
                   (non-negative-p-name (make-predicate-name non-negative-name))
-- 
Alexandria hooks/post-receive




More information about the alexandria-cvs mailing list