annotate toolboxes/FullBNT-1.0.7/netlab3.3/hmc.m @ 0:e9a9cd732c1e tip

first hg version after svn
author wolffd
date Tue, 10 Feb 2015 15:05:51 +0000
parents
children
rev   line source
wolffd@0 1 function [samples, energies, diagn] = hmc(f, x, options, gradf, varargin)
wolffd@0 2 %HMC Hybrid Monte Carlo sampling.
wolffd@0 3 %
wolffd@0 4 % Description
wolffd@0 5 % SAMPLES = HMC(F, X, OPTIONS, GRADF) uses a hybrid Monte Carlo
wolffd@0 6 % algorithm to sample from the distribution P ~ EXP(-F), where F is the
wolffd@0 7 % first argument to HMC. The Markov chain starts at the point X, and
wolffd@0 8 % the function GRADF is the gradient of the `energy' function F.
wolffd@0 9 %
wolffd@0 10 % HMC(F, X, OPTIONS, GRADF, P1, P2, ...) allows additional arguments to
wolffd@0 11 % be passed to F() and GRADF().
wolffd@0 12 %
wolffd@0 13 % [SAMPLES, ENERGIES, DIAGN] = HMC(F, X, OPTIONS, GRADF) also returns a
wolffd@0 14 % log of the energy values (i.e. negative log probabilities) for the
wolffd@0 15 % samples in ENERGIES and DIAGN, a structure containing diagnostic
wolffd@0 16 % information (position, momentum and acceptance threshold) for each
wolffd@0 17 % step of the chain in DIAGN.POS, DIAGN.MOM and DIAGN.ACC respectively.
wolffd@0 18 % All candidate states (including rejected ones) are stored in
wolffd@0 19 % DIAGN.POS.
wolffd@0 20 %
wolffd@0 21 % [SAMPLES, ENERGIES, DIAGN] = HMC(F, X, OPTIONS, GRADF) also returns
wolffd@0 22 % the ENERGIES (i.e. negative log probabilities) corresponding to the
wolffd@0 23 % samples. The DIAGN structure contains three fields:
wolffd@0 24 %
wolffd@0 25 % POS the position vectors of the dynamic process.
wolffd@0 26 %
wolffd@0 27 % MOM the momentum vectors of the dynamic process.
wolffd@0 28 %
wolffd@0 29 % ACC the acceptance thresholds.
wolffd@0 30 %
wolffd@0 31 % S = HMC('STATE') returns a state structure that contains the state of
wolffd@0 32 % the two random number generators RAND and RANDN and the momentum of
wolffd@0 33 % the dynamic process. These are contained in fields randstate,
wolffd@0 34 % randnstate and mom respectively. The momentum state is only used for
wolffd@0 35 % a persistent momentum update.
wolffd@0 36 %
wolffd@0 37 % HMC('STATE', S) resets the state to S. If S is an integer, then it
wolffd@0 38 % is passed to RAND and RANDN and the momentum variable is randomised.
wolffd@0 39 % If S is a structure returned by HMC('STATE') then it resets the
wolffd@0 40 % generator to exactly the same state.
wolffd@0 41 %
wolffd@0 42 % The optional parameters in the OPTIONS vector have the following
wolffd@0 43 % interpretations.
wolffd@0 44 %
wolffd@0 45 % OPTIONS(1) is set to 1 to display the energy values and rejection
wolffd@0 46 % threshold at each step of the Markov chain. If the value is 2, then
wolffd@0 47 % the position vectors at each step are also displayed.
wolffd@0 48 %
wolffd@0 49 % OPTIONS(5) is set to 1 if momentum persistence is used; default 0,
wolffd@0 50 % for complete replacement of momentum variables.
wolffd@0 51 %
wolffd@0 52 % OPTIONS(7) defines the trajectory length (i.e. the number of leap-
wolffd@0 53 % frog steps at each iteration). Minimum value 1.
wolffd@0 54 %
wolffd@0 55 % OPTIONS(9) is set to 1 to check the user defined gradient function.
wolffd@0 56 %
wolffd@0 57 % OPTIONS(14) is the number of samples retained from the Markov chain;
wolffd@0 58 % default 100.
wolffd@0 59 %
wolffd@0 60 % OPTIONS(15) is the number of samples omitted from the start of the
wolffd@0 61 % chain; default 0.
wolffd@0 62 %
wolffd@0 63 % OPTIONS(17) defines the momentum used when a persistent update of
wolffd@0 64 % (leap-frog) momentum is used. This is bounded to the interval [0,
wolffd@0 65 % 1).
wolffd@0 66 %
wolffd@0 67 % OPTIONS(18) is the step size used in leap-frogs; default 1/trajectory
wolffd@0 68 % length.
wolffd@0 69 %
wolffd@0 70 % See also
wolffd@0 71 % METROP
wolffd@0 72 %
wolffd@0 73
wolffd@0 74 % Copyright (c) Ian T Nabney (1996-2001)
wolffd@0 75
wolffd@0 76 % Global variable to store state of momentum variables: set by set_state
wolffd@0 77 % Used to initialise variable if set
wolffd@0 78 global HMC_MOM
wolffd@0 79 if nargin <= 2
wolffd@0 80 if ~strcmp(f, 'state')
wolffd@0 81 error('Unknown argument to hmc');
wolffd@0 82 end
wolffd@0 83 switch nargin
wolffd@0 84 case 1
wolffd@0 85 samples = get_state(f);
wolffd@0 86 return;
wolffd@0 87 case 2
wolffd@0 88 set_state(f, x);
wolffd@0 89 return;
wolffd@0 90 end
wolffd@0 91 end
wolffd@0 92
wolffd@0 93 display = options(1);
wolffd@0 94 if (round(options(5) == 1))
wolffd@0 95 persistence = 1;
wolffd@0 96 % Set alpha to lie in [0, 1)
wolffd@0 97 alpha = max(0, options(17));
wolffd@0 98 alpha = min(1, alpha);
wolffd@0 99 salpha = sqrt(1-alpha*alpha);
wolffd@0 100 else
wolffd@0 101 persistence = 0;
wolffd@0 102 end
wolffd@0 103 L = max(1, options(7)); % At least one step in leap-frogging
wolffd@0 104 if options(14) > 0
wolffd@0 105 nsamples = options(14);
wolffd@0 106 else
wolffd@0 107 nsamples = 100; % Default
wolffd@0 108 end
wolffd@0 109 if options(15) >= 0
wolffd@0 110 nomit = options(15);
wolffd@0 111 else
wolffd@0 112 nomit = 0;
wolffd@0 113 end
wolffd@0 114 if options(18) > 0
wolffd@0 115 step_size = options(18); % Step size.
wolffd@0 116 else
wolffd@0 117 step_size = 1/L; % Default
wolffd@0 118 end
wolffd@0 119 x = x(:)'; % Force x to be a row vector
wolffd@0 120 nparams = length(x);
wolffd@0 121
wolffd@0 122 % Set up strings for evaluating potential function and its gradient.
wolffd@0 123 f = fcnchk(f, length(varargin));
wolffd@0 124 gradf = fcnchk(gradf, length(varargin));
wolffd@0 125
wolffd@0 126 % Check the gradient evaluation.
wolffd@0 127 if (options(9))
wolffd@0 128 % Check gradients
wolffd@0 129 feval('gradchek', x, f, gradf, varargin{:});
wolffd@0 130 end
wolffd@0 131
wolffd@0 132 samples = zeros(nsamples, nparams); % Matrix of returned samples.
wolffd@0 133 if nargout >= 2
wolffd@0 134 en_save = 1;
wolffd@0 135 energies = zeros(nsamples, 1);
wolffd@0 136 else
wolffd@0 137 en_save = 0;
wolffd@0 138 end
wolffd@0 139 if nargout >= 3
wolffd@0 140 diagnostics = 1;
wolffd@0 141 diagn_pos = zeros(nsamples, nparams);
wolffd@0 142 diagn_mom = zeros(nsamples, nparams);
wolffd@0 143 diagn_acc = zeros(nsamples, 1);
wolffd@0 144 else
wolffd@0 145 diagnostics = 0;
wolffd@0 146 end
wolffd@0 147
wolffd@0 148 n = - nomit + 1;
wolffd@0 149 Eold = feval(f, x, varargin{:}); % Evaluate starting energy.
wolffd@0 150 nreject = 0;
wolffd@0 151 if (~persistence | isempty(HMC_MOM))
wolffd@0 152 p = randn(1, nparams); % Initialise momenta at random
wolffd@0 153 else
wolffd@0 154 p = HMC_MOM; % Initialise momenta from stored state
wolffd@0 155 end
wolffd@0 156 lambda = 1;
wolffd@0 157
wolffd@0 158 % Main loop.
wolffd@0 159 while n <= nsamples
wolffd@0 160
wolffd@0 161 xold = x; % Store starting position.
wolffd@0 162 pold = p; % Store starting momenta
wolffd@0 163 Hold = Eold + 0.5*(p*p'); % Recalculate Hamiltonian as momenta have changed
wolffd@0 164
wolffd@0 165 if ~persistence
wolffd@0 166 % Choose a direction at random
wolffd@0 167 if (rand < 0.5)
wolffd@0 168 lambda = -1;
wolffd@0 169 else
wolffd@0 170 lambda = 1;
wolffd@0 171 end
wolffd@0 172 end
wolffd@0 173 % Perturb step length.
wolffd@0 174 epsilon = lambda*step_size*(1.0 + 0.1*randn(1));
wolffd@0 175
wolffd@0 176 % First half-step of leapfrog.
wolffd@0 177 p = p - 0.5*epsilon*feval(gradf, x, varargin{:});
wolffd@0 178 x = x + epsilon*p;
wolffd@0 179
wolffd@0 180 % Full leapfrog steps.
wolffd@0 181 for m = 1 : L - 1
wolffd@0 182 p = p - epsilon*feval(gradf, x, varargin{:});
wolffd@0 183 x = x + epsilon*p;
wolffd@0 184 end
wolffd@0 185
wolffd@0 186 % Final half-step of leapfrog.
wolffd@0 187 p = p - 0.5*epsilon*feval(gradf, x, varargin{:});
wolffd@0 188
wolffd@0 189 % Now apply Metropolis algorithm.
wolffd@0 190 Enew = feval(f, x, varargin{:}); % Evaluate new energy.
wolffd@0 191 p = -p; % Negate momentum
wolffd@0 192 Hnew = Enew + 0.5*p*p'; % Evaluate new Hamiltonian.
wolffd@0 193 a = exp(Hold - Hnew); % Acceptance threshold.
wolffd@0 194 if (diagnostics & n > 0)
wolffd@0 195 diagn_pos(n,:) = x;
wolffd@0 196 diagn_mom(n,:) = p;
wolffd@0 197 diagn_acc(n,:) = a;
wolffd@0 198 end
wolffd@0 199 if (display > 1)
wolffd@0 200 fprintf(1, 'New position is\n');
wolffd@0 201 disp(x);
wolffd@0 202 end
wolffd@0 203
wolffd@0 204 if a > rand(1) % Accept the new state.
wolffd@0 205 Eold = Enew; % Update energy
wolffd@0 206 if (display > 0)
wolffd@0 207 fprintf(1, 'Finished step %4d Threshold: %g\n', n, a);
wolffd@0 208 end
wolffd@0 209 else % Reject the new state.
wolffd@0 210 if n > 0
wolffd@0 211 nreject = nreject + 1;
wolffd@0 212 end
wolffd@0 213 x = xold; % Reset position
wolffd@0 214 p = pold; % Reset momenta
wolffd@0 215 if (display > 0)
wolffd@0 216 fprintf(1, ' Sample rejected %4d. Threshold: %g\n', n, a);
wolffd@0 217 end
wolffd@0 218 end
wolffd@0 219 if n > 0
wolffd@0 220 samples(n,:) = x; % Store sample.
wolffd@0 221 if en_save
wolffd@0 222 energies(n) = Eold; % Store energy.
wolffd@0 223 end
wolffd@0 224 end
wolffd@0 225
wolffd@0 226 % Set momenta for next iteration
wolffd@0 227 if persistence
wolffd@0 228 p = -p;
wolffd@0 229 % Adjust momenta by a small random amount.
wolffd@0 230 p = alpha.*p + salpha.*randn(1, nparams);
wolffd@0 231 else
wolffd@0 232 p = randn(1, nparams); % Replace all momenta.
wolffd@0 233 end
wolffd@0 234
wolffd@0 235 n = n + 1;
wolffd@0 236 end
wolffd@0 237
wolffd@0 238 if (display > 0)
wolffd@0 239 fprintf(1, '\nFraction of samples rejected: %g\n', ...
wolffd@0 240 nreject/(nsamples));
wolffd@0 241 end
wolffd@0 242 if diagnostics
wolffd@0 243 diagn.pos = diagn_pos;
wolffd@0 244 diagn.mom = diagn_mom;
wolffd@0 245 diagn.acc = diagn_acc;
wolffd@0 246 end
wolffd@0 247 % Store final momentum value in global so that it can be retrieved later
wolffd@0 248 HMC_MOM = p;
wolffd@0 249 return
wolffd@0 250
wolffd@0 251 % Return complete state of sampler (including momentum)
wolffd@0 252 function state = get_state(f)
wolffd@0 253
wolffd@0 254 global HMC_MOM
wolffd@0 255 state.randstate = rand('state');
wolffd@0 256 state.randnstate = randn('state');
wolffd@0 257 state.mom = HMC_MOM;
wolffd@0 258 return
wolffd@0 259
wolffd@0 260 % Set complete state of sampler (including momentum) or just set randn
wolffd@0 261 % and rand with integer argument.
wolffd@0 262 function set_state(f, x)
wolffd@0 263
wolffd@0 264 global HMC_MOM
wolffd@0 265 if isnumeric(x)
wolffd@0 266 rand('state', x);
wolffd@0 267 randn('state', x);
wolffd@0 268 HMC_MOM = [];
wolffd@0 269 else
wolffd@0 270 if ~isstruct(x)
wolffd@0 271 error('Second argument to hmc must be number or state structure');
wolffd@0 272 end
wolffd@0 273 if (~isfield(x, 'randstate') | ~isfield(x, 'randnstate') ...
wolffd@0 274 | ~isfield(x, 'mom'))
wolffd@0 275 error('Second argument to hmc must contain correct fields')
wolffd@0 276 end
wolffd@0 277 rand('state', x.randstate);
wolffd@0 278 randn('state', x.randnstate);
wolffd@0 279 HMC_MOM = x.mom;
wolffd@0 280 end
wolffd@0 281 return