727e2e4Interactive WALNUTS sampling of a 2D banana targetJeremy Magland 1function walnuts_sampler(N, dt, max_error)
2%WALNUTS_SAMPLER Interactive figure: WALNUTS sampling of a 2D banana target.
3% WALNUTS_SAMPLER(N, DT, MAX_ERROR) draws N samples from the banana target
4% (helpers/log_density.m) with the WALNUTS sampler (helpers/walnuts.m) and
5% opens a figure showing the target density and the samples.
6%
7% This is the wiring: it runs the sampler, evaluates the target on a grid for
8% the heatmap, loads the prebuilt figure app, and sends both to it. It also
9% re-samples on request (figure -> script), wired so adding controls later is
10% a UI-only change. Run walnuts_demo.m (which addpath's helpers/).
12if nargin < 1 || isempty(N); N = 1000; end
13if nargin < 2 || isempty(dt); dt = 0.4; end
14if nargin < 3 || isempty(max_error); max_error = 0.8; end
16burnin = 200;
17chain = walnuts(randn(2, 1), burnin + N, dt, max_error);
18samples = chain(:, burnin + 1:end);
20dens = density_grid();
22html = fileread(fullfile('app', 'dist', 'index.html'));
23fig = figure;
24gl = uigridlayout(fig, [1 1], 'Padding', [0 0 0 0], ...
25 'RowHeight', {'1x'}, 'ColumnWidth', {'1x'});
26uihtml(gl, 'HTMLSource', html, 'Data', pack_data(samples, dens, N, dt, max_error), ...
27 'HTMLEventReceivedFcn', @(src, ev) on_event(src, ev));
28end
30function on_event(src, ev)
31% Figure -> script. The target is fixed, so the figure only ever needs new
32% samples or a movie trajectory back.
33% 'resample' {n, dt, maxError} -> draw a fresh chain; reply with 'samples'.
34% 'movie' {dt, maxError} -> record a short chain's orbit trajectories;
35% reply with 'movie'.
36d = ev.HTMLEventData;
37N = 1000; dt = 0.4; max_error = 0.8;
38if isstruct(d)
39 if isfield(d, 'n'); N = max(1, round(d.n)); end
40 if isfield(d, 'dt'); dt = d.dt; end
41 if isfield(d, 'maxError'); max_error = d.maxError; end
42end
43switch ev.HTMLEventName
44 case 'resample'
45 burnin = 200;
46 chain = walnuts(randn(2, 1), burnin + N, dt, max_error);
47 samples = chain(:, burnin + 1:end);
48 sendEventToHTMLSource(src, 'samples', ...
49 struct('x', samples(1, :), 'y', samples(2, :), 'n', N, 'dt', dt, 'maxError', max_error));
50 case 'movie'
51 % Record the orbit-building trajectory of a few transitions for the
52 % step-by-step animation. Each traj{i} = {px, py, seg, startX/Y, selX/Y}.
53 n_steps = 12;
54 [~, traj] = walnuts(randn(2, 1), n_steps, dt, max_error, true);
55 sendEventToHTMLSource(src, 'movie', traj);
56end
57end
59function dens = density_grid()
60%DENSITY_GRID Evaluate the target log density on a grid for the heatmap.
61% Row-major flat values: index (iy-1)*nx + ix, iy from ymin (1) to ymax (ny).
62xmin = -6; xmax = 6;
63ymin = -7; ymax = 3;
64nx = 100; ny = 100;
65xs = linspace(xmin, xmax, nx);
66ys = linspace(ymin, ymax, ny);
67values = zeros(1, nx * ny);
68k = 1;
69for iy = 1:ny
70 for ix = 1:nx
71 values(k) = log_density([xs(ix); ys(iy)]);
72 k = k + 1;
73 end
74end
75dens = struct('values', values, 'nx', nx, 'ny', ny, ...
76 'xmin', xmin, 'xmax', xmax, 'ymin', ymin, 'ymax', ymax);
77end
79function data = pack_data(samples, dens, N, dt, max_error)
80data = struct();
81data.type = 'walnuts';
82data.samples = struct('x', samples(1, :), 'y', samples(2, :));
83data.density = dens;
84data.n = N;
85data.dt = dt;
86data.maxError = max_error;
87end