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

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