% function mh(iters, burnin, psig, pausevery)
%
% Metropolis-Hastings sampler demonstration
%
% iters: how many iterations total
% burnin: how many iterations for burnin
% psig: std dev of proposal step (e.g. .1, .25)
% pausevery: stop and display progress this often (0 for never)
%
% For example,
%   mh(5000, 1000, .25, 0)
%   mh(1000, 300, .1, 20)

function mh(iters, burnin, psig, pausevery)

parallel = 1;				% number of parallel
                                        % trajectories to display
                                        % at once

[xs, ys] = meshgrid(-1:.05:1);

% plot function to integrate
figure(1);
zs = foo(xs,ys);
surfl(xs,ys,zs);
shading interp;
xlabel X
ylabel Y
zlabel f(X,Y)
set(gca,'CameraPosition', [13.017 -4.10426 29.1589])
% print -depsc foo.eps

% get true integral x^2*foo(x,y) by fine discretization
zs = zs./sum(zs(:));
fprintf('True E(x^2) %f\n', sum(sum(zs.*xs.*xs)));

% contour plot of function to integrate, on top of which we will
% plot progress of MH
figure(2);
contourf(xs,ys,foo(xs,ys));

% initial point for MH
x = zeros(parallel,1);
y = x;
v = foo(x,y);

% record the samples and acceptance decisions
samples = zeros(parallel, iters);
accept = zeros(parallel, iters);

% the MH sampler
for i = 1:iters

  % sample from proposal distribution (and possibly plot)
  nx = x + randn(size(x))*psig;
  ny = y + randn(size(y))*psig;
  nv = foo(nx, ny);
  if (pausevery > 0 && mod(i, pausevery)==0)
    h = line(nx, ny, 'Marker', 'o', 'MarkerSize', 15, 'LineWidth', 2, ...
	     'Color', [1 .5 .5], 'LineStyle', 'none');
  end

  % compute acceptance probability and decide which proposals to
  % accept; note Q is symmetric, so we don't need its ratio
  accprob = nv ./ v;
  mask = rand(size(x))>accprob;
  nx(mask) = x(mask);
  ny(mask) = y(mask);

  % add this step to the plot
  if (pausevery > 0)
    line([x nx]', [y ny]');
  else
    line(nx, ny, 'Marker', '.');
  end
  
  % do the update and remember the sample
  x = nx;
  y = ny;
  samples(:,i) = x.^2;
  accept(:,i) = ~mask;

  % pause for a plot if desired
  if (pausevery > 0 && mod(i, pausevery)==0)
    fprintf('acceptance rate %f\n', mean(mean(accept(:,1:i))));
    if (i > burnin)
      fprintf('current estimate %f\n', mean(mean(samples(:,burnin:i))));
    end
    pause
    delete(h)
  end
end

fprintf('final acceptance rate %f\n', mean(mean(accept)));
fprintf('final estimate %f\n', mean(mean(samples)));

% print -depsc mh-path.eps

return;


function zs = foo(xs, ys)

zs = exp(sin(2*pi*(xs+ys))-xs-2*(xs-.3).^2-2*ys.^2)+2*exp(-(xs-ys).^2);
zs(xs<-1) = 0;
zs(xs>1) = 0;
zs(ys<-1) = 0;
zs(ys>1) = 0;

return;

