summary refs log tree commit diff
path: root/mew.scm
diff options
context:
space:
mode:
Diffstat (limited to 'mew.scm')
-rw-r--r--mew.scm58
1 files changed, 47 insertions, 11 deletions
diff --git a/mew.scm b/mew.scm
index 22a8752..8507634 100644
--- a/mew.scm
+++ b/mew.scm
@@ -371,6 +371,13 @@
         (and (hash-table? o)
              (zero? (hash-table-size o)))))
 
+  (define (empty o)
+    (cond ((list? o) '())
+          ((string? o) "")
+          ((vector? o) #())
+          ((hash-table? o) (tbl))
+          (else "no empty defined")))
+
   (define (len o)
     (cond ((list? o) (length o))
           ((string? o) (string-length o))
@@ -426,17 +433,46 @@
             (vector-set! res i (vector-ref res j)))
           (vector-set! res j (vector-ref v i))))))
 
-  (define (sample o)
-    (if (hash-table? o)
-      (esc ret
-        (let ((n (rand (hash-table-size o)))
-              (i 0))
-          (hash-table-for-each o
-                               (lambda (k v)
-                                 (if (= i n)
-                                   (ret (cons k v))
-                                   (set! i (inc i)))))))
-      (get o (rand (len o)))))
+  (define sample
+    (let ((gen-get (lambda (o)
+                     (if (hash-table? o)
+                       (lambda (n)
+                         (esc ret
+                           (let ((i 0))
+                             (hash-table-for-each o
+                                                  (lambda (k v)
+                                                    (if (= i n)
+                                                      (ret (cons k v))
+                                                      (set! i (inc i))))))))
+                       (lambda (n)
+                         (get o n))))))
+      (case-lambda
+        ((o)
+         ((gen-get o) (rand (len o))))
+        ((o k)
+         (if (or (<= k 0) (< (len o) k))
+           #()
+           ;; Algorithm L with additional shuffle at the end.
+           ;; https://dl.acm.org/doi/pdf/10.1145/198429.198435
+           (let ((geto (gen-get o))
+                 (r (make-vector k))
+                 (w (exp (/ (log (rand)) k)))
+                 (n (len o))
+                 (i 0))
+             (while (< i k)
+               (vector-set! r i (geto i))
+               (set! i (inc i)))
+             (while (< i n)
+               (set! i (+ i 1 (inexact->exact (floor (/ (log (rand))
+                                                        (log (- 1 w)))))))
+               (when (< i n)
+                 (vector-set! r (rand k) (geto i))
+                 (set! w (* w (exp (/ (log (rand)) k))))))
+             (shuffle! r)
+             (if (vector? o)
+               r
+               (into (empty o) r)))))
+         )))
 
   (define range
     (case-lambda