forked from qobi/R6RS-AD
-
Notifications
You must be signed in to change notification settings - Fork 1
/
stochastic-scheme.ss
98 lines (82 loc) · 3.05 KB
/
stochastic-scheme.ss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#!r6rs
(library
(stochastic-scheme)
(export flip bottom distribution coalesce-duplicates draw-pair draw
probability support expected-value entropy upon-bottom)
(import (except (rnrs) + - * / sqrt exp log expt sin cos atan = < > <= >=
zero? positive? negative? real? magnitude)
(AD)
(QobiScheme))
(define (*flip* alpha) (error #f "Top-level flip"))
(define (flip alpha) (*flip* alpha))
(define (*bottom*) (error #f "Top-level bottom"))
(define (bottom) (*bottom*))
(define (distribution-thunk thunk)
(call-with-current-continuation
(lambda (c)
(let ((distribution '()) (saved-flip *flip*) (saved-bottom *bottom*) (p 1))
(set! *flip*
(lambda (alpha)
(unless (<= 0 alpha 1) (error #f "Alpha not probability"))
(call-with-current-continuation
(lambda (c)
(let ((saved-bottom *bottom*) (saved-p p))
(set! p (* alpha p))
(set! *bottom*
(lambda ()
(set! p (* (- 1 alpha) saved-p))
(set! *bottom* saved-bottom)
(c #f)))
#t)))))
(set! *bottom*
(lambda ()
(set! *flip* saved-flip)
(set! *bottom* saved-bottom)
(c (reverse distribution))))
(let ((value (thunk)))
(set! distribution (cons (cons value p) distribution)))
(bottom)))))
(define-syntax distribution
(syntax-rules () ((distribution e) (distribution-thunk (lambda () e)))))
(define (coalesce-duplicates distribution)
(let loop ((distribution distribution) (new-distribution '()))
(cond ((null? distribution) (reverse new-distribution))
((zero? (cdr (first distribution)))
(loop (rest distribution) new-distribution))
((position-if
(lambda (pair) (equal? (car pair) (car (first distribution))))
new-distribution)
=> (lambda (i)
(loop (rest distribution)
(map-indexed
(lambda (pair j)
(if (= i j)
(cons (car pair)
(+ (cdr (first distribution)) (cdr pair)))
pair))
new-distribution))))
(else (loop (rest distribution)
(cons (first distribution) new-distribution))))))
(define (draw-pair distribution)
(define (min x1 x2) (if (< x1 x2) x1 x2))
(define (max x1 x2) (if (> x1 x2) x1 x2))
(let loop ((distribution distribution) (p 1))
(cond
((or (zero? p) (null? distribution)) (bottom))
((flip (min (/ (cdr (first distribution)) p) 1)) (first distribution))
(else
(loop (rest distribution) (max (- p (cdr (first distribution))) 0))))))
(define (draw distribution) (car (draw-pair distribution)))
(define (probability distribution)
(fold + 0 (map cdr (remove-if-not car distribution))))
(define (support distribution) (map car distribution))
(define (expected-value distribution)
(fold + 0 (map (lambda (pair) (* (car pair) (cdr pair))) distribution)))
(define (entropy distribution)
(fold
+ 0 (map (lambda (pair) (* (cdr pair) (log (cdr pair)))) distribution)))
(define (upon-bottom-thunk thunk)
(let ((saved-bottom *bottom*))
(set! *bottom* (lambda () (thunk) (saved-bottom)))))
(define-syntax upon-bottom
(syntax-rules () ((upon-bottom e) (upon-bottom-thunk (lambda () e))))))