Guest User

Untitled

a guest
Nov 14th, 2017
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lisp 6.45 KB | None | 0 0
  1.  
  2.  
  3. (defun choose-effective-medoid (cluster distance)
  4.   (declare (optimize (speed 1)))
  5.   (fbind ((metric (curry #'cl-ds.utils:distance distance)))
  6.     (flet ((cost-function (cluster old-cost)
  7.              (let* ((medioid (aref cluster 0))
  8.                     (value (reduce (lambda (prev next)
  9.                                      (let ((new-cost (+ prev (metric medioid next))))
  10.                                        (if (< new-cost old-cost)
  11.                                            new-cost
  12.                                            (return-from cost-function (values old-cost nil)))))
  13.                                    cluster
  14.                                    :start 1
  15.                                    :initial-value 0)))
  16.                (values value t))))
  17.       (iterate
  18.         (with compare-cost = (reduce (lambda (prev next)
  19.                                        (+ prev (metric (aref cluster 0) next)))
  20.                                      cluster
  21.                                      :start 1
  22.                                      :initial-value 0))
  23.         (with result-improved = nil)
  24.         (declare (type number compare-cost))
  25.         (for i from 1 below (length cluster))
  26.         (rotatef (aref cluster i) (aref cluster 0))
  27.         (multiple-value-bind (cost improved) (cost-function cluster compare-cost)
  28.           (if improved
  29.               (setf compare-cost cost
  30.                     result-improved t)
  31.               (rotatef (aref cluster 0) (aref cluster i))))
  32.         (finally (return result-improved))))))
  33.  
  34.  
  35. (-> choose-effective-medoids ((vector vector) cl-ds.utils:distance-matrix) boolean)
  36. (defun choose-effective-medoids (clusters distances)
  37.   (~>> (lparallel:pmap '(vector boolean)
  38.                        (lambda (x) (choose-effective-medoid x distances))
  39.                        clusters)
  40.        (some #'identity)))
  41.  
  42.  
  43. (defun choose-initial-medoids (total-size number-of-medoids &optional result)
  44.   (let* ((number-of-medoids (min total-size number-of-medoids))
  45.          (cluster-size (max 2 (round-to (/ total-size number-of-medoids) 2))))
  46.     (cl-ds.utils:with-vectors ((cluster-contents (or result
  47.                                                      (let ((array (make-array number-of-medoids
  48.                                                                               :element-type 'vector)))
  49.                                                        (iterate
  50.                                                          (for i below number-of-medoids)
  51.                                                          (setf (aref array i)
  52.                                                                (make-array cluster-size
  53.                                                                            :adjustable t
  54.                                                                            :element-type 'non-negative-fixnum
  55.                                                                            :fill-pointer 1)))
  56.                                                        array))))
  57.       (iterate
  58.         (with generator = (cl-ds.utils:lazy-shuffle 0 total-size))
  59.         (with medoids = (sort (iterate
  60.                                 (repeat number-of-medoids)
  61.                                 (collect (funcall generator) at start))
  62.                               #'<))
  63.         (for i from 0)
  64.         (for medoid in medoids)
  65.         (setf (aref (cluster-contents i) 0) medoid))
  66.       cluster-contents)))
  67.  
  68.  
  69. (defun assign-data-points-to-medoids (input clusters distances)
  70.   (fbind ((metric (curry #'cl-ds.utils:distance distances)))
  71.     (iterate
  72.       (with data =
  73.             (~>> input
  74.                  (lparallel:pmap
  75.                   '(vector (or null fixnum))
  76.                   (lambda (index)
  77.                     (let ((medoid (cl-ds.utils:lower-bound clusters
  78.                                                            index
  79.                                                            (lambda (left right)
  80.                                                              (< (aref left 0) right))))
  81.                           (result 0))
  82.                       (unless (and (< medoid (length clusters))
  83.                                    (eql (aref (aref clusters medoid) 0)
  84.                                         index))
  85.                         (iterate
  86.                           (declare (type number distance))
  87.                           (with min-distance = nil)
  88.                           (for cluster in-vector clusters)
  89.                           (for i from 0)
  90.                           (for medoid = (aref cluster 0))
  91.                           (for distance = (metric index medoid))
  92.                           (cond ((null min-distance)
  93.                                  (setf min-distance distance))
  94.                                 ((> min-distance distance)
  95.                                  (setf min-distance distance
  96.                                        result i)))
  97.                           (finally (return result)))))))))
  98.       (for i in-vector input)
  99.       (for asg in-vector data)
  100.       (unless (null asg)
  101.         (vector-push-extend i (aref clusters asg)))))
  102.   clusters)
  103.  
  104.  
  105. (-> partition-around-medoids (vector non-negative-fixnum cl-ds.utils:distance-matrix) vector)
  106. (defun partition-around-medoids (input-data number-of-medoids distance-matrix)
  107.   (declare (type vector input-data)
  108.            (optimize (debug 3) (safety 3)))
  109.   (when (or (zerop (length input-data))
  110.             (zerop number-of-medoids))
  111.     (return-from partition-around-medoids (make-array 0 :element-type 'vector)))
  112.   (iterate
  113.     (with length = (length input-data))
  114.     (with indexes = (coerce (iota length) '(vector non-negative-fixnum)))
  115.     (for cluster-contents
  116.          initially (choose-initial-medoids length number-of-medoids)
  117.          then (choose-initial-medoids length number-of-medoids cluster-contents))
  118.     (map nil (lambda (vec) (setf (fill-pointer vec) 1)) cluster-contents)
  119.     (setf cluster-contents (sort cluster-contents #'< :key (lambda (x) (aref x 0))))
  120.     (assign-data-points-to-medoids indexes cluster-contents distance-matrix)
  121.     (for improvements = (choose-effective-medoids cluster-contents distance-matrix))
  122.     (while improvements)
  123.     (finally
  124.      (iterate
  125.        (for i below (length cluster-contents))
  126.        (setf (aref cluster-contents i)
  127.              (map `(vector ,(array-element-type input-data))
  128.                   (curry #'aref input-data)
  129.                   (aref cluster-contents i))))
  130.      (return cluster-contents))))
Add Comment
Please, Sign In to add comment