Explorar el Código

Fisher-Jenks breaks initial implementation

Innocenty Enikeew hace 10 años
padre
commit
cfbc8fe46b
Se han modificado 2 ficheros con 90 adiciones y 0 borrados
  1. 2 0
      .gitignore
  2. 88 0
      fisher-breaks.lisp

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+*~
+*.fasl

+ 88 - 0
fisher-breaks.lisp

@@ -0,0 +1,88 @@
+(defun make-pair (value weight) (cons value weight))
+(defun get-value (pair) (car pair))
+(defun get-weight (pair) (cdr pair))
+
+(defun get-value-count-pairs (values)
+  (let ((sorted (sort (copy-list values) #'<)))
+    (loop for x in (rest sorted)
+       with val = (first sorted)
+       with cnt = 1
+       if (< val x) collect (make-pair val cnt) into res and do (setf cnt 1 val x)
+       else do (incf cnt)
+       finally (return (append res (list (make-pair val cnt)))))))
+
+(defun calc-weightened (pairs)
+  (loop for (value . weight) in pairs
+     summing weight into acc-weight
+     summing (* value weight) into acc-weightened
+     collect (make-pair acc-weightened acc-weight)))
+
+(defun jenks-fisher (k values)
+  (declare (optimize (debug 2)))
+  (when (> k 1)
+    (let* ((pairs (get-value-count-pairs values))
+           (m (length pairs))
+           (buf-size (- m (1- k)))
+           (weightened (calc-weightened pairs))
+           (prev-ssm (make-array buf-size))
+           (cur-ssm (make-array buf-size))
+           (cb (make-array (list (1- k) buf-size)))
+           (compl 1))
+      (labels ((get-wv (b e)
+                 (assert (not (zerop b)))
+                 (assert (<= b e))
+                 (assert (< e m))
+                 (- (get-value (elt weightened e)) (get-value (elt weightened (1- b)))))
+               (get-w (b e)
+                 (assert (not (zerop b)))
+                 (assert (<= b e))
+                 (assert (< e m))
+                 (- (get-weight (elt weightened e)) (get-weight (elt weightened (1- b)))))
+               (get-ssm (b e)
+                 (/ (expt (get-wv b e) 2) (get-w b e)))
+               (calc-ssm (p i)
+                 (+ (elt prev-ssm p) (get-ssm (+ p compl) (+ i compl))))
+               (find-max-break-index (i bp ep)
+                 (assert (< bp ep))
+                 (assert (<= bp i))
+                 (assert (<= ep (1+ i)))
+                 (assert (< i buf-size))
+                 (assert (<= ep buf-size))
+                 (let ((found-point bp)
+                       (max-ssm (calc-ssm bp i)))
+                   (loop for point from (1+ bp) below ep
+                      for ssm = (calc-ssm point i)
+                      when (> ssm max-ssm)
+                      do (setf max-ssm ssm found-point point))
+                   (setf (elt cur-ssm i) max-ssm)
+                   found-point))
+               (calc-range (bi ei bp ep)
+                 (assert (<= bp bi ei))
+                 (assert (<= ep ei))
+                 (unless (= bi ei)
+                   (assert (< bp ep))
+                   (let* ((mi (floor (+ bi ei) 2))
+                          (mp (find-max-break-index mi bp (min ep (1+ mi)))))
+                     (assert (<= bp mp mi))
+                     (assert (< mp ep))
+                     (calc-range bi mi bp (min mi (1+ mp)))
+                     (setf (aref cb (1- compl) mi) mp)
+                     (calc-range (1+ mi) ei mp ep)))))
+        ;; Init first prev-ssm
+        (loop for i below buf-size
+           for (value . weight) in weightened
+           do (setf (elt prev-ssm i)
+                    (/ (expt value 2) weight)))
+        ;; Calc all
+        (dotimes (i (- k 2))
+          (setf compl (1+ i))
+          (calc-range 0 buf-size 0 buf-size)
+          (rotatef prev-ssm cur-ssm))
+        (cons (get-value (elt pairs 0))
+              (reverse
+               (loop for idx from (1- k) downto 1
+                  with last-bi = (find-max-break-index (1- buf-size) 0 buf-size)
+                  collect (get-value (elt pairs (+ last-bi idx)))
+                  do (assert (< last-bi buf-size))
+                  when (> idx 1)
+                  do (setf last-bi (aref cb (1- idx) last-bi)))))))))