|
| 1 | +function samples = ars(logpdf, pdfargs, N, xi, support) |
| 2 | + |
| 3 | +% Perform adaptive rejection sampling as described in gilks & wild |
| 4 | +% '92, and wild & gilks 93. The PDF must be log-concave. Draw N |
| 5 | +% samples from the pdf passed in as a function handle to its log. The |
| 6 | +% log could be offset by an additive constant, corresponding to an |
| 7 | +% unnormalized distribution. |
| 8 | +% |
| 9 | +% The pdf function should have prototype [h, hprime] = logpdf(x, |
| 10 | +% pdfargs{:}), where x could be a vector of points, h is the value of |
| 11 | +% the log pdf and hprime is its derivative. |
| 12 | +% |
| 13 | +% The xi argument to this function is a number of points to initially |
| 14 | +% evaluate the pdf at, which must be on either side of the |
| 15 | +% distribution's mode. And the support is a 2-vector specifying the |
| 16 | +% support of the pdf, defaults to [-inf inf]. |
| 17 | +% |
| 18 | +% This function does not use the lower squeezing bound because it |
| 19 | +% is optimized for generating a small number of samples each call. |
| 20 | + |
| 21 | +% Copyright (C) 2005 Michael Mandel, mim at ee columbia edu; |
| 22 | +% distributable under GPL, see README.txt |
| 23 | + |
| 24 | +samples = []; |
| 25 | + |
| 26 | +% Don't need to approximate the curve too well, all the sorting and |
| 27 | +% whatnot gets expensive |
| 28 | +Nxmax = 50; |
| 29 | + |
| 30 | +if(nargin < 5) support = [-inf inf]; end |
| 31 | + |
| 32 | +x = sort(xi); |
| 33 | +[h, hprime] = feval(logpdf, x, pdfargs{:}); |
| 34 | +if(~isfinite(h(1))) |
| 35 | + x |
| 36 | + h |
| 37 | + hprime |
| 38 | + logpdf |
| 39 | + pdfargs{:} |
| 40 | + size(pdfargs) |
| 41 | + det(pdfargs{2}) |
| 42 | + error('h not finite'); |
| 43 | +end |
| 44 | + |
| 45 | +if(support(1) == 0) |
| 46 | + % Cheat! Get closer and closer to 0 as needed |
| 47 | + while(hprime(1) < 0) |
| 48 | + xt = x(1)/2; |
| 49 | + [ht,hpt] = feval(logpdf, xt, pdfargs{:}); |
| 50 | + [x,z,h,hprime,hu,sc,cu] = insert(x,xt,h,ht,hprime,hpt,support); |
| 51 | + end |
| 52 | + |
| 53 | + while(hprime(end) > 0) |
| 54 | + xt = x(end)*2; |
| 55 | + [ht,hpt] = feval(logpdf, xt, pdfargs{:}); |
| 56 | + [x,z,h,hprime,hu,sc,cu] = insert(x,xt,h,ht,hprime,hpt,support); |
| 57 | + end |
| 58 | +end |
| 59 | + |
| 60 | +if(hprime(1) < 0 || hprime(end) > 0) |
| 61 | + % If the lower bound isn't 0, can't help it (for now) |
| 62 | + error(['Starting points ' num2str(x) ' do not enclose the' ... |
| 63 | + ' mode']); |
| 64 | +end |
| 65 | + |
| 66 | + |
| 67 | +% Avoid under/overflow errors. the envelope and pdf are only |
| 68 | +% proporitional to the true pdf, so we can choose any constant |
| 69 | +% of proportionality. |
| 70 | +offset = max(h); |
| 71 | +h = h-offset; |
| 72 | + |
| 73 | +[x,z,h,hprime,hu,sc,cu] = insert(x,[], h,[], hprime,[], support); |
| 74 | + |
| 75 | +Nsamp = 0; |
| 76 | +while Nsamp < N |
| 77 | + % Draw 2 random numbers in [0,1] |
| 78 | + u = rand(1,2); |
| 79 | + |
| 80 | + % Find the largest z such that sc(z) < u |
| 81 | + idx = find(sc/cu < u(1)); |
| 82 | + idx = idx(end); |
| 83 | + |
| 84 | + % Figure out the x in that segment that u corresponds to |
| 85 | + xt = x(idx) + (-h(idx) + log(hprime(idx)*(cu*u(1) - sc(idx)) + ... |
| 86 | + exp(hu(idx)))) / hprime(idx); |
| 87 | + [ht,hpt] = feval(logpdf, xt, pdfargs{:}); |
| 88 | + ht = ht-offset; |
| 89 | + |
| 90 | + % Figure out what h_u(xt) is a dumb way, uses assumption that the |
| 91 | + % log pdf is concave |
| 92 | + hut = min(hprime.*(xt - x) + h); |
| 93 | + |
| 94 | + % Decide whether to keep the sample |
| 95 | + if(u(2) < exp(ht - hut)) |
| 96 | + Nsamp = Nsamp+1; |
| 97 | + samples(Nsamp) = xt; |
| 98 | + else |
| 99 | +% $$$ fprintf('.'); |
| 100 | + end |
| 101 | + |
| 102 | + % Update vectors if necessary |
| 103 | + if(length(x) < Nxmax) |
| 104 | + [x,z,h,hprime,hu,sc,cu] = insert(x,xt,h,ht,hprime,hpt,support); |
| 105 | + end |
| 106 | +end |
| 107 | + |
| 108 | + |
| 109 | + |
| 110 | +function [x, z, h, hprime, hu, sc, cu] = ... |
| 111 | + insert(x, xnew, h, hnew, hprime, hprimenew, support) |
| 112 | +% Insert xnew into x and update all other vectors to reflect the |
| 113 | +% new point's addition. |
| 114 | + |
| 115 | +[x,order] = sort([x xnew]); |
| 116 | +h = [h hnew]; h = h(order); |
| 117 | +hprime = [hprime hprimenew]; hprime = hprime(order); |
| 118 | + |
| 119 | +z = [support(1) x(1:end-1)+(-diff(h)+hprime(2:end).*diff(x)) ./ ... |
| 120 | + diff(hprime) support(end)]; |
| 121 | +hu = [hprime(1) hprime] .* (z - [x(1) x]) + [h(1) h]; |
| 122 | + |
| 123 | +% $$$ plot(z, hu); |
| 124 | + |
| 125 | +sc = [0 cumsum(diff(exp(hu)) ./ hprime)]; |
| 126 | +cu = sc(end); |
| 127 | + |
0 commit comments