0001 function [positionMatrix probabilityVector res] = sampleMetropolis(par, nSample)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 fHandle = par.metroHandle;
0033
0034
0035
0036
0037
0038 metroX = par.metroInit;
0039
0040
0041
0042 metroCov = par.metroCov;
0043
0044
0045
0046 metroVal = fHandle(metroX);
0047
0048
0049
0050 metroState = 1;
0051
0052 nNonAdaptive = par.metroNonAdaptive;
0053
0054
0055
0056
0057
0058
0059
0060 nNoHistory = par.metroNoHistory;
0061
0062
0063
0064
0065
0066
0067 nHistory = par.metroHistory;
0068 if nHistory < nNonAdaptive
0069 nHistory = nNonAdaptive;
0070 end
0071
0072
0073 nLag = par.metroLag;
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085 nSampleDelayFraction = par.metroSpacing;
0086
0087
0088
0089
0090 nSampleBatch = par.metroSampleBatch;
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102 relTol = par.metroRelTol;
0103 nIntegralBatch = par.metroIntegralBatch;
0104
0105
0106 metroIntegral = par.metroIntegral;
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116 nDim = length(par.metroInit);
0117
0118
0119 nMetroIter = 0;
0120 nAdaptCounter = 0;
0121 nAccepted = 0;
0122 metroCholCov = chol(metroCov);
0123 historyMatrix = nan(nDim, nHistory);
0124
0125 sampleMatrix = nan(nDim, nSample);
0126 sampleValueVector = nan(1, nSample);
0127
0128
0129
0130 verbose = par.verbose;
0131 clear par
0132
0133
0134 cumulativeTime = zeros(1, 5);tic;
0135 nBatch = 1;
0136 if verbose,disp('Started: Metropolis algorithm.');end
0137 while metroState
0138
0139 nMetroIter = nMetroIter + nBatch;
0140
0141
0142
0143
0144
0145 for i = 1:10
0146 try
0147 metroNewX = metroCholCov*randn(nDim, nBatch) + metroX;
0148 metroNewVal = fHandle(metroNewX);
0149 break
0150 catch
0151
0152 end
0153 end
0154
0155
0156 acceptFilter = rand(1, nBatch) < ...
0157 min(ones(1, nBatch), metroNewVal./metroVal);
0158 nAccepted = nAccepted + sum(acceptFilter);
0159 metroX(:, acceptFilter) = metroNewX(:, acceptFilter);
0160 metroVal(acceptFilter) = metroNewVal(acceptFilter);
0161
0162
0163
0164
0165
0166
0167
0168
0169 if metroState <= 3
0170 historyMatrix(:, mod(nMetroIter-1, nHistory)+1) = metroX;
0171 end
0172
0173
0174 if metroState == 2 || metroState == 3
0175 nAdaptCounter = nAdaptCounter + 1;
0176 p1 = (nAdaptCounter - 1) / nAdaptCounter;
0177 p2 = 1/nAdaptCounter;
0178
0179 metroPreMean = metroMean;
0180 metroMean = p1*metroMean + p2*metroX;
0181
0182 metroCov = p1 * metroCov + covFactor*p2*(...
0183 nAdaptCounter * (metroPreMean*(metroPreMean')) - ...
0184 (nAdaptCounter + 1)*(metroMean*(metroMean')) + ...
0185 metroX*metroX' + covMargin);
0186
0187 try
0188 metroCholCov = chol(metroCov);
0189 catch
0190 error('elk:distribution:numericalError', ['Adaptive part of ' ...
0191 'Metropolis algorithm failed. Usually, your guess for the ' ...
0192 'initial point or the initial covariance is bad. Change ' ...
0193 'them, or if you are already close, try increasing the ' ...
0194 'number of non-adaptive cycles.']);
0195 end
0196 end
0197
0198
0199 if metroState == 4 && iStepElapsedForSampling == nSampleDelay
0200 sampleMatrix(:, iSample + (1:nBatch)) = metroX;
0201 sampleValueVector(iSample + (1:nBatch)) = metroVal;
0202 iSample = iSample + nBatch;
0203 if verbose,disp(['Metropolis: sample ' num2str(iSample) ' generated.']);end
0204
0205
0206 nBatch = min(nBatch, nSample - iSample);
0207 metroX = metroX(:, 1:nBatch);
0208 metroVal = metroVal(1:nBatch);
0209 iStepElapsedForSampling = 1;
0210 elseif metroState == 4
0211 iStepElapsedForSampling = iStepElapsedForSampling + 1;
0212 end
0213
0214
0215 if metroState == 1 && nMetroIter == nNonAdaptive
0216 if verbose,disp(['Metropolis: state 1 finished after ' ...
0217 num2str(nMetroIter) ' steps.']);end
0218 cumulativeTime(1) = toc;
0219
0220 metroMean = mean(historyMatrix(:, 1:nMetroIter), 2);
0221
0222 covFactor = 2.4^2 / nDim;
0223 metroCov = covFactor * cov(historyMatrix(:, 1:nMetroIter)');
0224
0225
0226 if verbose > 1
0227 disp('So far, the estimated mean is:')
0228 disp(metroMean')
0229 disp('.. the estimated covariance is:')
0230 disp(metroCov)
0231 disp('.. the determinant caclucates to:')
0232 disp(det(metroCov))
0233 disp('..the acceptance rate is:')
0234 disp(nAccepted/nMetroIter)
0235 end
0236
0237 metroCholCov = chol(metroCov);
0238
0239 covMargin = 1e-6 * diag(diag(metroCov));
0240
0241 nAdaptCounter = nMetroIter;
0242
0243
0244 metroState = 2;
0245 end
0246 if metroState == 2 && nMetroIter == nNonAdaptive + nNoHistory
0247 if verbose,disp('Metropolis: state 2 finished');end
0248 cumulativeTime(2) = toc;
0249
0250 nMetroIter = 0;
0251 metroState = 3;
0252 end
0253 if metroState == 3 && nMetroIter == nHistory
0254 if verbose,disp('Metropolis: state 3 finished');end
0255 cumulativeTime(3) = toc;
0256
0257 metroAcMatrix = computeAcMatrix(historyMatrix, nLag);
0258
0259
0260
0261 lastZeroVector = nan(1, nDim);
0262 for iDim = 1:nDim
0263 thisLagTime = find(metroAcMatrix(iDim, :) < 0, 1, 'first');
0264 if isempty(thisLagTime)
0265 lastZeroVector(iDim) = nLag;
0266 else
0267 lastZeroVector(iDim) = thisLagTime;
0268 end
0269 end
0270
0271
0272 if mean(lastZeroVector) < 0.9*nLag
0273
0274 nStepsLastZero = mean(lastZeroVector);
0275 nSampleDelay = round(nStepsLastZero * nSampleDelayFraction);
0276 iSample = 0;
0277 else
0278 if verbose > 1
0279 disp('For the following error, the estimated mean is:')
0280 disp(metroMean')
0281 disp('And the estimated covariance is:')
0282 disp(metroCov)
0283 end
0284 error('elk:distribution:adaptiveMetropolis', ...
0285 ['The adaptive Metropolis algorithm did not converge ' ...
0286 'properly. Look, if metroInit and metroCov are ' ...
0287 'appropriately chosen.']);
0288 end
0289
0290
0291 nBatch = min(nSampleBatch, nSample);
0292 metroX = metroX * ones(1, nBatch);
0293 metroVal = metroVal * ones(1, nBatch);
0294
0295
0296 nMetroIter = 0;
0297 nAccepted = 0;
0298 iStepElapsedForSampling = 0;
0299 metroState = 4;
0300 if verbose,disp(['Metropolis: generating samples every ' ...
0301 num2str(nSampleDelay) ' step.']);end
0302
0303 end
0304 if metroState == 4 && iSample >= nSample
0305 if verbose,disp('Metropolis: state 4 finished');end
0306 cumulativeTime(4) = toc;
0307 metroState = 0;
0308 end
0309
0310 end
0311
0312 positionMatrix = sampleMatrix;
0313
0314
0315
0316 if ~isempty(metroIntegral)
0317 y = metroIntegral;
0318 yErr = 0;
0319 else
0320 [y yErr] = integrateNormal(fHandle, metroMean, metroCov/covFactor, ...
0321 relTol, nIntegralBatch, verbose);
0322 end
0323 probabilityVector = sampleValueVector / y;
0324 cumulativeTime(5) = toc;
0325
0326
0327 res.acMatrix = metroAcMatrix;
0328 res.acceptanceRate = nAccepted / nMetroIter;
0329 res.rejectionRate = 1 - res.acceptanceRate;
0330 res.sampleDelay = nSampleDelay;
0331 res.integralValue = y;
0332 res.integralRelErr = yErr;
0333 res.mean = metroMean;
0334 res.cov = metroCov;
0335 res.cumulativeTime = cumulativeTime;
0336
0337 end
0338
0339 function acMatrix = computeAcMatrix(dataMatrix, nLag)
0340 acMatrix = dataMatrix(:, 1:nLag);
0341 meanVector = mean(dataMatrix, 2);
0342
0343
0344
0345 for iDim = 1:size(dataMatrix, 1)
0346 thisDataVector = dataMatrix(iDim, :) - meanVector(iDim);
0347
0348 for iK = 1:nLag
0349 acMatrix(iDim, iK) = thisDataVector(1:(end-(iK-1))) * ...
0350 thisDataVector(iK:end)';
0351 end
0352 acMatrix(iDim, :) = acMatrix(iDim, :) / acMatrix(iDim, 1);
0353
0354
0355
0356 end
0357
0358
0359
0360
0361
0362 end
0363
0364 function [y yErr] = integrateNormal(fHandle, parMean, parCov, relTol, nBatch, verbose)
0365
0366 intStatus = 1;
0367 nNew = nBatch;
0368 valueVector = [];
0369 probVector = [];
0370
0371 if verbose,disp(['Metropolis: phase 5 started.']);end
0372 relTol = relTol
0373 while intStatus
0374
0375 disD = obtainDistributionDiscrete('normal', 'nSample', nNew, ...
0376 'mean', parMean, 'cov', parCov);
0377
0378
0379 probVector = [probVector disD.probabilityVector];
0380
0381
0382 valueVector = [valueVector fHandle(disD.positionMatrix)];
0383
0384
0385 nSample = length(valueVector);
0386 y = 1/nSample * sum(valueVector ./ probVector);
0387
0388
0389 yErr = sqrt(1/nSample/(nSample-1) * sum((...
0390 valueVector ./ probVector - y).^2));
0391 yErr = yErr / y;
0392
0393
0394
0395 if yErr < relTol
0396 intStatus = 0;
0397 else
0398
0399
0400
0401
0402
0403 nNew = round(nSample * (yErr/(0.9*relTol))^2 - nSample);
0404 nNew = min(nNew, nBatch);
0405 if verbose,disp(['Metropolis: integration error now at ' ...
0406 num2str(yErr) ', using ' num2str(nNew) ...
0407 ' new sample points']);
0408 end
0409 end
0410 end
0411
0412
0413 end