annotate utils/harmony/gamma.lisp @ 35:1d757c33e00e

Changes for midi file import darcs-hash:20070502153016-f76cc-89b748c36180ccaca77d2a70a65a6e7f77df8d43.gz
author David Lewis <d.lewis@gold.ac.uk>
date Wed, 02 May 2007 16:30:16 +0100
parents d1010755f507
children
rev   line source
d@33 1 ;; CSR's gamma functions. I don't really know what's happening here,
d@33 2 ;; but it seems to work... Called from within harmonic_analysis.lisp
d@33 3
d@33 4 (in-package #:amuse-harmony)
d@33 5
d@33 6 (let ((p (make-array
d@33 7 9 :element-type 'double-float
d@33 8 :initial-contents ; cf. Lanczos' Approximation on Wikipedia.
d@33 9 '(0.99999999999980993d0 676.5203681218851d0 -1259.1392167224028d0
d@33 10 771.32342877765313d0 -176.61502916214059d0 12.507343278686905d0
d@33 11 -0.13857109526572012d0 9.9843695780195716d-6
d@33 12 1.5056327351493116d-7)))
d@33 13 (c (make-array 8 :element-type 'double-float
d@33 14 :initial-contents
d@33 15 (mapcar (lambda (x) (float x 1d0))
d@33 16 '(1/12 -1/360 1/1260 -1/1680 1/1188 -691/360360
d@33 17 1/156 -3617/122400)))))
d@33 18 (defun gamma/posreal (x)
d@33 19 (declare (type (double-float (0d0)) x))
d@33 20 (locally
d@33 21 (declare (optimize speed))
d@33 22 (labels ((corr (x)
d@33 23 (declare (type double-float x))
d@33 24 (let ((y (/ 1.0 (* x x))))
d@33 25 (do* ((i 7 (1- i))
d@33 26 (r (aref c i) (+ (* r y) (aref c i))))
d@33 27 ((<= i 0) (the (double-float (0d0)) (exp (/ r x))))
d@33 28 (declare (type double-float r)))))
d@33 29 (lngamma/lanczos (x)
d@33 30 (declare (type (double-float 0.5d0) x))
d@33 31 (let ((x (1- x)))
d@33 32 (do* ((i 0 (1+ i))
d@33 33 (ag (aref p 0) (+ ag (/ (aref p i) (+ x i)))))
d@33 34 ((>= i 8)
d@33 35 (let ((term1 (* (+ x 0.5d0) (log (/ (+ x 7.5d0) #.(exp 1d0)))))
d@33 36 (term2 (+ #.(log (sqrt (* 2 pi))) (log ag))))
d@33 37 (+ term1 (- term2 7.0d0))))
d@33 38 (declare (type (double-float (0d0)) ag)))))
d@33 39 (gamma/xgthalf (x)
d@33 40 (declare (type (double-float 0.5d0) x))
d@33 41 (cond
d@33 42 ((= x 0.5d0) 1.77245385090551602729817d0)
d@33 43 ((< x 5d0) (exp (lngamma/lanczos x)))
d@33 44 ;; the GNU scientific library suggests a third branch
d@33 45 ;; for x < 10, but in fact for our purposes the
d@33 46 ;; errors are under control.
d@33 47 (t
d@33 48 (let* ((p (expt x (* x 0.5)))
d@33 49 (e (exp (- x)))
d@33 50 (q (* (* p e) p))
d@33 51 (pre (* #.(sqrt 2) #.(sqrt pi) q (/ (sqrt x)))))
d@33 52 (* pre (corr x)))))))
d@33 53 (if (> x 0.5d0)
d@33 54 (gamma/xgthalf x)
d@33 55 (let ((g (gamma/xgthalf (- 1d0 x))))
d@33 56 (declare (type double-float g))
d@33 57 (/ pi g (sin (* pi x)))))))))
d@33 58
d@33 59 (defun beta (alpha)
d@33 60 (let ((sum 0)
d@33 61 (product 1))
d@33 62 (dotimes (i (length alpha) (/ product (gamma/posreal (float sum 1d0))))
d@33 63 (let ((alpha_i (aref alpha i)))
d@33 64 (setq product (* product (gamma/posreal (float alpha_i 1d0))))
d@33 65 (incf sum alpha_i)))))
d@33 66
d@33 67 ;; this is p(d|c_i), where the chord model is represented as a
d@33 68 ;; Dirichlet distribution with parameters alpha_i
d@33 69 #+nil
d@33 70 (defun likelihood (observations alpha)
d@33 71 ;; observations is a 12d vector summing to 1, alpha summing to 3
d@33 72 (assert (< (abs (1- (loop for d across observations sum d)))
d@33 73 (* single-float-epsilon 12)))
d@33 74 (let ((pairs (loop for alpha_i across alpha
d@33 75 for d_i across observations
d@33 76 if (zerop alpha_i)
d@33 77 do (unless (zerop d_i)
d@33 78 (return-from likelihood 0.0d0))
d@33 79 else
d@33 80 collect (cons alpha_i d_i))))
d@33 81 ;; now all the CARs of pairs have strictly positive alpha_i
d@33 82 ;; values, and the d_i are the corresponding observations.
d@33 83 (let ((alpha_prime (map 'simple-vector #'car pairs)))
d@33 84 (* (/ (beta alpha_prime))
d@33 85 (reduce #'* pairs :key (lambda (pair)
d@33 86 (expt (cdr pair) (1- (car pair)))))))))
d@33 87
d@33 88
d@33 89 (defun likelihood (observations alpha &optional (power 1))
d@33 90 (assert (< (abs (1- (loop for d across observations sum d)))
d@33 91 (* single-float-epsilon 12)))
d@33 92 (let* ((alpha_0 (loop for a across alpha sum a))
d@33 93 (alpha_0+1 (1+ alpha_0))
d@33 94 (alpha_00+1 (* alpha_0+1 power))
d@33 95 (alpha_00 (- alpha_00+1 1))
d@33 96 (alpha (map 'simple-vector
d@33 97 (lambda (x) (* x (/ alpha_00 alpha_0)))
d@33 98 alpha))
d@33 99 (quantum (expt 0.0005 power))) ; sake of argument
d@33 100 (let ((pairs
d@33 101 (loop for d_i across observations
d@33 102 for alpha_i across alpha
d@33 103 if (zerop alpha_i)
d@33 104 do (unless (zerop d_i)
d@33 105 (return-from likelihood 0.0d0))
d@33 106 else collect (cons d_i alpha_i))))
d@33 107 (assert (= (length pairs) 12))
d@33 108 (let ((alpha_prime (map 'simple-vector #'cdr pairs)))
d@33 109 (* (/ (beta alpha_prime)) (/ quantum)
d@33 110 (reduce #'* pairs :key
d@33 111 (lambda (pair)
d@33 112 (if (zerop (car pair))
d@33 113 (* (/ (cdr pair)) (expt quantum (cdr pair)))
d@33 114 (* quantum (expt (car pair) (1- (cdr
d@33 115 pair))))))))))))
d@33 116
d@33 117 (defun 4ple-likelihood (pitch-classes chord-probabilities intervals level sum)
d@33 118 (let ((observations))
d@33 119 (dolist (interval intervals)
d@33 120 (push (aref pitch-classes interval) observations)
d@33 121 (decf sum (aref pitch-classes interval)))
d@33 122 (push sum observations)
d@33 123 (likelihood/fourwise (make-array (length observations) :initial-contents (reverse observations))
d@33 124 chord-probabilities level)))
d@33 125
d@33 126 (let ((alpha_0s '((1 . 12) (1/2 . 9) (1/4 . 30))))
d@33 127 (defun likelihood/fourwise (observations alpha &optional (power 1))
d@33 128 (assert (< (abs (1- (loop for d across observations sum d)))
d@33 129 (* single-float-epsilon 4)))
d@33 130 (let* ((alpha_0 (loop for a across alpha sum a))
d@33 131 (alpha (map 'simple-vector
d@33 132 (lambda (x) (* x (/ (cdr (assoc power alpha_0s))
d@33 133 alpha_0)))
d@33 134 alpha))
d@33 135 (quantum (expt 0.0005 power))) ; sake of argument
d@33 136 (let ((pairs
d@33 137 (loop for d_i across observations
d@33 138 for alpha_i across alpha
d@33 139 if (zerop alpha_i)
d@33 140 do (unless (zerop d_i)
d@33 141 (return-from likelihood/fourwise 0.0d0))
d@33 142 else collect (cons d_i alpha_i))))
d@33 143 (assert (= (length pairs) 4))
d@33 144 (let ((alpha_prime (map 'simple-vector #'cdr pairs)))
d@33 145 (* (/ (beta alpha_prime)) (/ quantum)
d@33 146 (reduce #'* pairs :key
d@33 147 (lambda (pair)
d@33 148 (if (zerop (car pair))
d@33 149 (* (/ (cdr pair)) (expt quantum (cdr pair)))
d@33 150 (* quantum (expt (car pair) (1- (cdr pair)))))))))))))
d@33 151
d@33 152 (defparameter *alpha-scale* 1)
d@33 153 (defparameter *beta-scale* 1)
d@33 154 (defparameter *alpha* #(2.925 1.95 1.625))
d@33 155 (defparameter *beta* #(0.87 4.46))
d@33 156 (defparameter *minimal-betas* '((1 . 8.75) (1/2 . 3) (1/4 . 2.5)))
d@33 157 (defparameter *full-betas-1* '((1 . 14) (1/2 . 6) (1/4 . 8))) ;; gets 144|51
d@33 158 (defparameter *full-betas* '((1 . 14) (3/4 . 6) (1/2 . 6) (1/4 . 8))) ;; guess...
d@33 159 (defparameter *betas* *full-betas*)
d@33 160
d@33 161 (defun 3ple-likelihood (pitch-classes chord-probabilities non-chord intervals level sum
d@33 162 &optional (alpha *alpha*) (beta *beta*))
d@33 163 (declare (ignore chord-probabilities non-chord))
d@33 164 (let ((observations))
d@33 165 (dolist (interval intervals)
d@33 166 (push (aref pitch-classes interval) observations)
d@33 167 (decf sum (aref pitch-classes interval)))
d@33 168 (push sum observations)
d@33 169 (when (= sum 1) ;; So there are no chord notes at all... ?? move to likelihood function
d@33 170 (return-from 3ple-likelihood 0))
d@33 171 (likelihood/threeplusonewise (make-array (length observations) :initial-contents (reverse observations))
d@33 172 alpha beta
d@33 173 level)
d@33 174 #+nil (likelihood/threeplusonewise (make-array (length observations) :initial-contents (reverse observations))
d@33 175 (map 'vector #'(lambda (x) (* x *alpha-scale*))
d@33 176 #(2.925 1.95 1.625))
d@33 177 #+nil (map 'vector #'(lambda (x) (* x *beta-scale*))
d@33 178 #(0.87 4.46))
d@33 179 (make-array 2 :initial-contents (list 0.87 *beta-scale*))
d@33 180 level)))
d@33 181
d@33 182 ;; #(0.87 4.46) worked
d@33 183
d@33 184 ;;; observations is a non-relativistic four-vector of proportions:
d@33 185 ;;; #(tonic mediant dominant other).
d@33 186 ;;;
d@33 187 ;;; alpha is a three-vector of Dirichlet parameters for proportions of
d@33 188 ;;; tonic, mediant, dominant of the total chord notes.
d@33 189 ;;;
d@33 190 ;;; beta is a two-vector of Dirichlet parameters for proportions of
d@33 191 ;;; non-chord vs chord notes.
d@33 192 ;;;
d@33 193 ;;; suggested values:
d@33 194 ;;; alpha: #(2.925 1.95 1.625) ; (tonic, mediant, dominant)
d@33 195 ;;; beta: #(0.44 1.76) ; (non-chord, chord)
d@33 196 ;;;
d@33 197 ;;; model:
d@33 198 ;;; p(tmdo|c) = p(o|c)p(tmd|oc)
d@33 199 ;;; where
d@33 200 ;;; p(o|c) ~ Beta(0.44,1.76) (i.e. p({o,o'}|c) ~ Dir({0.44,1.76})
d@33 201 ;;; and
d@33 202 ;;; p(tmd|oc) ~ (1-o) Dir({2.925,1.95,1.625})
d@33 203 (defun likelihood/threeplusonewise
d@33 204 (observations alpha beta &optional (power 1))
d@33 205 (assert (< (abs (1- (loop for d across observations sum d)))
d@33 206 (* single-float-epsilon 4)))
d@33 207 (let* ((quantum (expt 0.00000005 power))) ; sake of argument
d@33 208 (let* ((o (aref observations 3))
d@33 209 (pairs
d@33 210 (loop repeat 3
d@33 211 for d_i across observations
d@33 212 for alpha_i across alpha
d@33 213 if (zerop alpha_i)
d@33 214 do (unless (zerop d_i)
d@33 215 (return-from likelihood/threeplusonewise 0.0d0))
d@33 216 else collect (cons (/ d_i (- 1 o)) alpha_i))))
d@33 217 (assert (= (length pairs) 3))
d@33 218 (assert (< (abs (1- (loop for (d) in pairs sum d))) (*
d@33 219 single-float-epsilon 3)))
d@33 220 (flet ((key (pair)
d@33 221 (if (zerop (car pair))
d@33 222 (* (/ (cdr pair)) (expt quantum (cdr pair)))
d@33 223 (* quantum (expt (car pair) (1- (cdr pair)))))))
d@33 224 (let ((alpha_prime (map 'simple-vector #'cdr pairs)))
d@33 225 (*
d@33 226 ;; p(o|c)
d@33 227 (/ (beta beta)) (/ quantum)
d@33 228 (reduce #'* (list (cons o (aref beta 0))
d@33 229 (cons (- 1 o) (aref beta 1)))
d@33 230 :key #'key)
d@33 231 ;; p(tmd|oc)
d@33 232 (/ (beta alpha_prime)) (/ quantum)
d@33 233 (reduce #'* pairs :key #'key)))))))