├── multiEval.m ├── RWM.m ├── EnKF.m ├── example.m ├── MCMC.m ├── evolve.m ├── cage.m ├── DEMC.m ├── ABCPMC.m ├── ModAv.m └── README.md /multiEval.m: -------------------------------------------------------------------------------- 1 | function fitness = multiEval(func, inds) 2 | para = num2cell(inds,2); 3 | fitness = cellfun(func, para); -------------------------------------------------------------------------------- /RWM.m: -------------------------------------------------------------------------------- 1 | function bead = RWM(bead) 2 | 3 | %% Create proposal 4 | loc = bead.funcProp(bead.loc); 5 | %% Check bound 6 | if isfield(bead,'bound') 7 | pop.inds = loc; pop.bound = bead.bound; 8 | pop = cage(pop); 9 | loc = pop.inds; 10 | end 11 | 12 | %% Calculate and compare Metropolis ratio 13 | p = bead.func(loc); 14 | if p/bead.p > rand() 15 | bead.loc = loc; 16 | bead.p = p; 17 | end 18 | 19 | %% Register sequence 20 | bead.gen = bead.gen+1; -------------------------------------------------------------------------------- /EnKF.m: -------------------------------------------------------------------------------- 1 | function ensemb = EnKF(ensemb) 2 | % Ensemble Kalman filter. Updated forecast and analysis states using 3 | % observation and ensemble Kalman filter. 4 | % 5 | % Input fields 6 | % R : measurement error (sigma). 7 | % Fstates : forecast states. 1 X n matrix, n = number of state 8 | % Astates : analysis states. 1 X n matrix. 9 | % obs : observation states. Scaler. 10 | % func : model operator, from current state to next state. 11 | % 12 | % Output the same structue with updated Fstates and Astates, as well as 13 | % estimation of model error (C). 14 | 15 | %% Update forecast states 16 | N = numel(ensemb.Fstates); 17 | Acell = num2cell(ensemb.Astates); 18 | ensemb.Fstates = cellfun(ensemb.func,Acell); 19 | 20 | %% Estimate model error 21 | E = mean(ensemb.Fstates); 22 | A = ensemb.Fstates-E; 23 | ensemb.C = A*A.'/(N-1); 24 | 25 | %% Perturb observation with measurement eror 26 | D = ones(1,N)*ensemb.obs + normrnd(0,ensemb.R,[1,N]); 27 | 28 | %% Kalman gain 29 | K = ensemb.C/(ensemb.C+ensemb.R); 30 | 31 | %% Update analysis states 32 | ensemb.Astates = ensemb.Fstates + K*(D-ensemb.Fstates); -------------------------------------------------------------------------------- /example.m: -------------------------------------------------------------------------------- 1 | %% Finding global minimum with DE 2 | 3 | % Test function: 2d Ackley's function 4 | pop.func = @(x) -20*exp(-.2*sqrt(.5*sum(x.^2)))... 5 | -exp(.5*sum(cos(2*pi*x)))+exp(1)+20; 6 | pop.bound = [-5,-5;5,5]; 7 | 8 | % Setup the DE settings 9 | pop.size = 50; pop.life = 200; pop.type = 'DE'; 10 | result = DEMC(pop); 11 | disp(['Global minimum from DE: ' num2str(result.best)]) 12 | 13 | %% Mapping posterior with MCMC and DEMC 14 | 15 | % Test function: wide spread mixture of two normal distributions: 1/3 of 16 | % N(-5,1) and 2/3 of N(5,1). We expect a mean of 1.67 and a std of 4.82 17 | pop.func = @(x) 1/3*normpdf(x,-5,1)+2/3*normpdf(x,5,1); 18 | pop.bound = [-100;100]+1.67; 19 | 20 | % Using DEMC. It should only be able to sample both peaks. 21 | pop.type = 'DEMC'; pop.life = 1500; 22 | result = DEMC(pop); burnt = result.chain(pop.life/2:end,:); 23 | disp(['Mean estimated by DEMC: ' num2str(mean(burnt(:)))]) 24 | disp(['Std estimated by DEMC: ' num2str(std(burnt(:)))]) 25 | 26 | % Using MCMC. It should only be able to sample one peak. 27 | pop.life = 10000; pop.loc = 0; 28 | result = MCMC(pop); burnt = result.chain(pop.life/2:end,:); 29 | disp(['Mean estimated by MCMC: ' num2str(mean(burnt))]) 30 | disp(['Std estimated by MCMC: ' num2str(std(burnt))]) 31 | -------------------------------------------------------------------------------- /MCMC.m: -------------------------------------------------------------------------------- 1 | function result = MCMC(bead) 2 | % Markov Chain Monte Carlo with Random-Walk Metropolis. 3 | % 4 | % Input fields 5 | % One of 'loc', 'funcPrior', 'bound'(in descending priority) must be 6 | % specified. 7 | % life : length of Markov Chain. 8 | % func : liklihood function. Calculates the liklihood from parameter. 9 | % funcProp : (optional) proposal distribution function. Make new proposal 10 | % according to parameter. Default is normal distribution with sigma = 1. 11 | % loc : (optional) initial parameter. 12 | % funcPrior : (optional) prior function to generate initial parameter. 13 | % bound : (optional) 2 X n matrix, where n is the parameter dimension. 14 | % Lower(first row) and upper(second row) bounds of parameter. 15 | % 16 | % Output fields 17 | % chain : m X n matrix, where m = length and n = parameter dimension. 18 | % time : m X 1 matrix, time stamp of each step. 19 | % 20 | % Warning : Using 'bound' might break detailed balance and result in 21 | % gibberish posterior. Not recommended. 22 | 23 | %% Set default proposal distribution function to normal distribution. 24 | if ~isfield(bead,'funcProp') 25 | bead.funcProp = @ (x) normrnd(x,1); 26 | end 27 | 28 | %% Retrive bead.loc and bead.dms (parameter dimension) 29 | if ~isfield(bead,'loc') 30 | if isfield(bead,'funcPrior') 31 | bead.loc = bead.funcPrior(); 32 | else 33 | bead.dms = size(bead.bound,2); 34 | bead.loc = rand(1,bead.dms)*(bead.bound(2,:)-bead.bound(1,:))+... 35 | bead.bound(1,:); 36 | end 37 | end 38 | bead.dms = numel(bead.loc); 39 | 40 | %% Create empty matrixes 41 | rng('shuffle'); 42 | result.chain = NaN(bead.life, bead.dms); 43 | result.time = NaN(bead.life, 1); 44 | 45 | %% Initialize the first bead 46 | bead.p = bead.func(bead.loc); 47 | bead.gen = 1; 48 | 49 | %% Start Markov Chian and record 50 | tic; 51 | result.chain(bead.gen) = bead.loc; 52 | result.time(bead.gen) = toc; 53 | while bead.gen<=bead.life 54 | bead = RWM(bead); 55 | result.chain(bead.gen) = bead.loc; 56 | result.time(bead.gen) = toc; 57 | end 58 | end -------------------------------------------------------------------------------- /evolve.m: -------------------------------------------------------------------------------- 1 | function pop = evolve(pop) 2 | rng('shuffle'); 3 | grePcn = 90; % percentile of paerent in greedy method 4 | lambda = 0.4; % strength of greedy jump 5 | %% Define gamma 6 | if mod(pop.gen,10)==0 7 | gamma = 1; 8 | else 9 | gamma = 2.4/sqrt(2*pop.dms); 10 | end 11 | 12 | %% Generate parent matrix p, without repeating 13 | s = (1:pop.size)'; 14 | p1 = mod(randi([0 pop.size-2],pop.size,1)+s,pop.size)+1; 15 | p2 = randi([1,pop.size-2],pop.size,1); 16 | p2 = (p2>=s|p2>=p1)+p2; p2 = (p2>=s&p2>=p1)+p2; 17 | 18 | %% Greedy or gentle 19 | if isfield(pop,'greedy') && (mod(pop.gen,10)~=0) 20 | starPool = find(pop.fitness>=prctile(pop.fitness,grePcn)); 21 | ps = starPool(randi(numel(starPool),pop.size,1)); 22 | pad = lambda*(pop.inds(ps,:)-pop.inds); 23 | else 24 | pad = normrnd(0,1e-6,[pop.size,pop.dms]); 25 | end 26 | 27 | %% Create offspring embryo 28 | embryo = pop.inds + gamma*(pop.inds(p1,:) - pop.inds(p2,:)) + pad; 29 | 30 | %% Add crossover to offspring 31 | if isfield(pop,'CR') 32 | trandition = rand(pop.size,pop.dms) > pop.CR; 33 | embryo(trandition) = pop.inds(trandition); 34 | end 35 | 36 | %% Add random (yet within range) mutations to offspring 37 | if isfield(pop,'mutation') 38 | weirdos = rand(pop.size,pop.dms) < pop.mutation; 39 | pool = rand(pop.size, pop.dms).*(pop.range(:,:,2)... 40 | - pop.range(:,:,1))+pop.range(:,:,1); 41 | embryo(weirdos) = pool(weirdos); 42 | end 43 | 44 | %% Reflect back outliers and meet simplex requirement 45 | shell = pop; shell.inds = embryo; 46 | shell = cage(shell); embryo = shell.inds; 47 | 48 | %% Evaluate and substitue offspring 49 | fitness = multiEval(pop.func, embryo); 50 | switch pop.type 51 | case 'DEMC' 52 | if pop.logFlag 53 | snob = exp(fitness-pop.fitness)>rand(pop.size,1); 54 | else 55 | snob = fitness./pop.fitness>rand(pop.size,1); 56 | end 57 | case 'DE' 58 | snob = fitness pop.top; 35 | if any([any(low),any(upp)]) % 36 | if ~isfield(pop,'method') 37 | pop.method = 'reflect'; 38 | end 39 | 40 | switch pop.method 41 | case 'reflect' %reflect back the distance 42 | pop.inds(low)= 2 * pop.but(low) - pop.inds(low); 43 | pop.inds(upp)= 2 * pop.top(upp) - pop.inds(upp); 44 | 45 | case 'bound' %set to bound 46 | pop.inds(low)= pop.but(low); 47 | pop.inds(upp)= pop.top(upp); 48 | 49 | case 'fold' %circle back from the other bound 50 | pop.inds(low) = pop.top(low) - (pop.but(low) - pop.inds(low)); 51 | pop.inds(upp) = pop.but(upp) + (pop.inds(upp) - pop.top(upp)); 52 | 53 | otherwise 54 | warning('Method in function cage not recognized.'); return 55 | end 56 | %% Recursively avoid still out-of-bounds values 57 | pop = cage(pop); 58 | end 59 | end -------------------------------------------------------------------------------- /DEMC.m: -------------------------------------------------------------------------------- 1 | function result = DEMC(pop) 2 | % Differential Evolution / Differential Evolution Markov Chain. In the 3 | % case of 'DE', this function also plot a figure for the objective function 4 | % of all generations. 5 | % 6 | % Input fields 7 | % func : evaluation (objective) function. 8 | % bound : 2 X n matrix, where n is the parameter dimension. Lower 9 | % (first row) and upper(second row) bounds of parameter. 10 | % size : size of population. 11 | % life : maximum generation of population. 12 | % funcPrior :(optional) prior distribution function to generate first 13 | % generation. Default is uninformative prior within bounds. 14 | % type :(optional) 'DE' or 'DEMC'. The former seek the global 15 | % minimum, the later maps the posterior. Default is 'DEMC'. 16 | % greedy :(optional) logical scalar, faster convergence but less 17 | % stable. Breaks detailed balance and should not be used with 'DEMC'. 18 | % logFlag :(optional) logical scalar, use log liklihood or not. Default 19 | % is 'false'. 20 | % mutation :(optional) scalar, mutation rate. 21 | % CR :(optional) scalar, crossover rate. 22 | % simplex :(optional) 1 X n logical maxtrix. 'true' specifies the 23 | % parameters that should be positive and sum up to 1. 24 | % name :(optional) name of output figure. Default 'DEMCtest'. 25 | % 26 | % Output fields 27 | % chain : population at each generation. 28 | % obj : evaluation (objective) function value at each generation. 29 | % best : best individual at last generation. 30 | 31 | %% Set defaul parameters 32 | if ~isfield(pop,'type') 33 | pop.type = 'DEMC'; 34 | end 35 | if ~isfield(pop,'name') 36 | pop.name = [pop.type,'test']; 37 | end 38 | if ~isfield(pop,'logFlag') 39 | pop.logFlag = false; %logFlag default false 40 | end 41 | 42 | %% Initialize parameters 43 | pop.dms = size(pop.bound,2); %Parameter dimension 44 | pop.but = repmat(pop.bound(1,:),pop.size,1); 45 | pop.top = repmat(pop.bound(2,:),pop.size,1); 46 | pop = rmfield(pop, 'bound'); 47 | 48 | %% Initialize population 49 | pop.gen = 1; rng('shuffle'); 50 | if isfield(pop,'funcPrior') 51 | pop.inds = pop.funcPrior(); 52 | else 53 | pop.inds = rand(pop.size, pop.dms).*(pop.top-pop.but)+pop.but; 54 | end 55 | pop = cage(pop); 56 | 57 | %% Evaluate first generation 58 | pop.fitness = multiEval(pop.func, pop.inds); 59 | 60 | %% Evolve population 61 | result.chain = NaN(pop.life,pop.size,pop.dms); 62 | result.obj = NaN(pop.life,pop.size); 63 | while pop.gen<=pop.life 64 | result.chain(pop.gen,:,:) = pop.inds; 65 | result.obj(pop.gen,:) = pop.fitness; 66 | pop = evolve(pop); 67 | end 68 | 69 | %% Find best individual 70 | fit = multiEval(pop.func, reshape(result.chain(end,:,:),[pop.size,pop.dms])); 71 | if strcmp(pop.type,'DE') 72 | [~,idx] = min(fit); 73 | %% Plot the objective function 74 | figure; 75 | plot(1:pop.life,result.obj,'.'); 76 | xlabel('Step'); ylabel('Objective Function'); 77 | set(findall(gcf,'-property','FontSize'),'FontSize',18) 78 | saveas(gcf, [pop.name,'.png']); 79 | close(gcf); 80 | else 81 | [~,idx] = max(fit); 82 | end 83 | result.best = reshape(result.chain(end,idx,:),[1,pop.dms]); 84 | end -------------------------------------------------------------------------------- /ABCPMC.m: -------------------------------------------------------------------------------- 1 | function pop = ABCPMC(pop) 2 | % Approximate Bayesian Computing-Population Monte Carlo method. 3 | % 4 | % Input fields 5 | % obs : 1 X d, d = dimension of target 6 | % bound : 2 X n matrix, where n is the parameter dimension. Lower 7 | % (first row) and upper(second row) bounds of parameter. 8 | % funcPrior : prior distribution function to generate parameter. 9 | % funcSummar : function to model target from parameter. 10 | % funcDist : function to calculate distance between modeled and observed 11 | % target. 12 | % epsl : 1 X i epsilon matrix, where i is the number of generations. 13 | % size : population size 14 | % 15 | % Output the same strucuture with extra fields 16 | % inds : individuals (parameters) for all generations. 17 | % summar : modeled target at all generations. 18 | % weight : weight matrix for all generations. 19 | % C : Covariance matrix for all geneations. 20 | % acRate : overall acceptance rate. 21 | 22 | %% Expand parameters 23 | pop.life = numel(pop.epsl); 24 | pop.dms = numel(pop.funcPrior()); 25 | pop.but = repmat(pop.bound(1,:),pop.size,1); 26 | pop.top = repmat(pop.bound(2,:),pop.size,1); 27 | 28 | %% Create empty matrixes 29 | pop.inds = NaN(pop.size,pop.dms,pop.life); 30 | pop.summar = NaN(pop.size,numel(pop.obs),pop.life); 31 | pop.weight = NaN(pop.size,pop.life); 32 | pop.C = NaN(pop.dms,pop.dms,pop.life); %Covariance matix 33 | count = 0; 34 | 35 | %% First iteration 36 | for i = 1:pop.size 37 | flag = true; 38 | while flag 39 | theta = pop.funcPrior(); 40 | Y = pop.funcSummar(theta); 41 | rho = pop.funcDist(Y); 42 | flag = rho > pop.epsl(1); 43 | count = count + 1; 44 | end 45 | pop.inds(i,:,1) = theta; 46 | pop.summar(i,:,1) = Y; 47 | pop.weight(i,1) = 1/pop.size; 48 | disp(['Generation 1, individual ' num2str(i)]) 49 | end 50 | pop.C(:,:,1) = 2*cov(pop.inds(:,:,1)); 51 | 52 | %% Second and later iterations 53 | q_d = NaN(pop.size,1); %probability of theta(j-1) to theta(j) 54 | for j = 2:pop.life 55 | for i = 1:pop.size 56 | flag = true; 57 | while flag 58 | idx = randsample(1:pop.size,1,true,pop.weight(:,j-1)); 59 | theta = pop.inds(idx,:,j-1); 60 | thetaP = mvnrnd(theta, pop.C(:,:,j-1)); 61 | %% Check for out-off-bound 62 | if isfield(pop,'bound') 63 | thetaP = cage(thetaP,pop); 64 | end 65 | Y = pop.funcSummar(thetaP); 66 | rho = pop.funcDist(Y); 67 | flag = rho > pop.epsl(j); 68 | count = count + 1; 69 | disp(['Searching... ' num2str(count) '. ' num2str(((j-1)*... 70 | pop.size+i)/(pop.size*pop.life)*100) '% done.']) 71 | end 72 | pop.inds(i,:,j) = thetaP; 73 | pop.summar(i,:,j) = Y; 74 | for u=1:pop.size 75 | q_d(u) = mvnpdf(pop.inds(u,:,j-1),thetaP,pop.C(:,:,j-1)); 76 | end 77 | bot = pop.weight(:,j-1)'*q_d; 78 | pop.weight(i,j) = 1./bot; 79 | disp(['Generation ' num2str(j) ', individual ' num2str(i)]) 80 | end 81 | pop.C(:,:,j) = 2*cov(pop.inds(:,:,j)); 82 | end 83 | pop.acRate = pop.size*pop.life/count; 84 | -------------------------------------------------------------------------------- /ModAv.m: -------------------------------------------------------------------------------- 1 | function result = ModAv(ensemb) 2 | % Multi-model averaging function. Supported methods: 3 | % EWA : Equal Weights Averaging 4 | % BGA : Bates-Granger Averaging 5 | % AICA : Akaike's Information Criterion Averaging 6 | % BICA : Bayes Information Criterion Averaging 7 | % GRA : Granger-Ramanathan Averaging 8 | % BMA : Bayesian Model Averaging 9 | % MMA : Mallows Model Averaging 10 | % MMAd : Mallows Model Averaging (lie on simplex) 11 | % 12 | % Input fields 13 | % Xcali : m1 X n model prediction matrix for calibration period. m1 = time 14 | % length of calibration period, n = model number. 15 | % Ycali : m1 X 1 observation matrix for calibration period. 16 | % Xeval : m2 X n model prediction matrix for evaluation period. 17 | % Yeval : m2 X 1 observation matrix for evaluation period. 18 | % p : 1 X n matrix of model parameter numbers. 19 | % method : abbreviation of method. 20 | % 21 | % Output fields 22 | % weight : model weights. 23 | % RMSEcali : RMSE of calibration period. 24 | % RMSEeval : RMSE of evaluation period. 25 | % chain : (BMA, MMA and MMAd) model weights in all iterations. 26 | % obj : (BMA, MMA and MMAd) objective function value for all iterations. 27 | % sigma : (BMA) optimized model sigma. 28 | % 29 | % Warning: Method BMA could be slow and unstable. 30 | 31 | %% Unpack 32 | [n,k] = size(ensemb.Xcali); % length of times series, number of models 33 | Y = ensemb.Ycali; p = ensemb.p; method = ensemb.method; 34 | Xeval = ensemb.Xeval; Yeval = ensemb.Yeval; t = size(Yeval,1); 35 | 36 | %% Settings of DEMC 37 | sigMaxBMA = sqrt(50); % Maximum sigma for BMA 38 | sizeMMA = 50; lifeMMA = 800; mutMMA = 0.1; 39 | sizeBMA = 100; lifeBMA = 20000; mutBMA = 0.1; 40 | 41 | %% Bias correction 42 | Xc = NaN(size(ensemb.Xcali)); 43 | result.bias = NaN(2,k); 44 | for i=1:k 45 | x = [ensemb.Xcali(:,i),ones(n,1)]; 46 | result.bias(:,i) = (x'*x)\x'*Y; 47 | Xc(:,i) = x*result.bias(:,i); 48 | Xeval(:,i) = [Xeval(:,i),ones(t,1)]*result.bias(:,i); 49 | end 50 | clear ensemb 51 | 52 | %% Calculation of different methods 53 | rmse = sqrt(mean((Xc-repmat(Y,[1,k])).^2)); % root mean square error 54 | result.RMSEcali = rmse; 55 | switch method 56 | %% Equal Weights Averaging 57 | case 'EWA' 58 | result.weight = rmse.^0/numel(rmse); 59 | %% Bates-Granger Averaging 60 | case 'BGA' 61 | result.weight = 1./rmse.^2./sum(1./rmse.^2); 62 | %% Akaike's Information Criterion Averaging 63 | case 'AICA' 64 | I = n*log(rmse.^2) + n + 2*p; 65 | Iscale = I - min(I); 66 | result.weight = exp(-Iscale/2)/sum(exp(-Iscale/2)); 67 | %% Bayes Information Criterion Averaging 68 | case 'BICA' 69 | I = n*log(rmse.^2) + n + p*log(n); 70 | Iscale = I - min(I); 71 | result.weight = exp(-Iscale/2)/sum(exp(-Iscale/2)); 72 | %% Granger-Ramanathan Averaging 73 | case 'GRA' 74 | result.weight = ((Xc'*Xc)\Xc'*Y)'; 75 | %% Optimazation-required methods 76 | case {'BMA','MMA','MMAd'} 77 | pop.type = 'DEMC'; 78 | pop.logFlag = true; 79 | %% Bayesian Model Averaging 80 | if strcmp(method,'BMA') 81 | pop.size = sizeBMA; 82 | pop.life = lifeBMA; 83 | pop.mutation = mutBMA; 84 | pop.name = 'ModAv_BMA'; 85 | f = @(sig) normpdf(repmat(Y,[1,k]),Xc,repmat(sig,[n,1])); 86 | pop.func = @(x)... % beta and sigma, half and half 87 | sum(log(sum(repmat(x(1:k),[n,1]).*f(x(k+1:end)),2))); 88 | pop.bound = [zeros(1,2*k);[ones(1,k),ones(1,k)*sigMaxBMA]]; 89 | pop.simplex = [true(1,k),false(1,k)]; 90 | DEMCout = DEMC(pop); 91 | result.sigma = DEMCout.best(k+1:end); 92 | %% Mallows Model Averaging 93 | else 94 | pop.size = sizeMMA; 95 | pop.life = lifeMMA; 96 | pop.mutation = mutMMA; 97 | pop.greedy = true; 98 | [~,idx] = max(p); 99 | S2 = rmse(idx)^2; 100 | pop.func = ... 101 | @(beta) -0.5*(sum((Y-Xc*beta').^2)+2*sum(beta.*p.*S2)); 102 | %% Mallows Model Averaging (simplex version) 103 | if strcmp(method,'MMAd') % Weight that lie on the simplex 104 | pop.simplex = true(1,k); 105 | pop.bound = [zeros(1,k);ones(1,k)]; 106 | pop.name = 'ModAv_MMAd'; 107 | else 108 | pop.bound = [-ones(1,k);ones(1,k)]; 109 | pop.name = 'ModAv_MMA'; 110 | end 111 | DEMCout = DEMC(pop); 112 | end 113 | result.weight = DEMCout.best(1:k); 114 | result.chain = DEMCout.chain; 115 | result.obj = DEMCout.obj; 116 | 117 | otherwise 118 | warning('Method in function ModAv not recongized.');return 119 | end 120 | 121 | Ypred = sum(repmat(result.weight,[t,1]).*Xeval,2); 122 | result.RMSEeval = sqrt(mean((Ypred-Yeval).^2)); 123 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Optimizer tools written in Matlab. Including MCMC, DEMC, Ensemble Kalman filter, Approximate Bayesian Computing-Population Monte Carlo, and modeling averaging methods. Most of the algorithms are based on class CEE 290 taught by Prof. [Jasper A. Vrugt](http://faculty.sites.uci.edu/jasper/) @ UCI. 2 | 3 | All input and output of functions are single structures with multiple fields. Same field names were used across different functions and can be piped together for testing purpose. 4 | 5 | 6 | ## Documentation 7 | 8 | #### function DEMC 9 | Differential Evolution / Differential Evolution Markov Chain. In the case of **'DE'**, this function also plot a figure for the objective function of all generations. 10 | ##### Input fields 11 | - func : evaluation (objective) function. 12 | - bound : 2 X n matrix, where n is the parameter dimension. Lower (first row) and upper(second row) bounds of parameter. 13 | - size : size of population. 14 | - life : maximum generation of population. 15 | - funcPrior :(optional) prior distribution function to generate first 16 | generation. Default is uninformative prior within bounds. 17 | - type :(optional) 'DE' or 'DEMC'. The former seek the global minimum, the later maps the posterior. Default is 'DEMC'. 18 | - greedy :(optional) logical scalar, faster convergence but less stable. Breaks detailed balance and should not be used with 'DEMC'. 19 | - logFlag :(optional) logical scalar, use log liklihood or not. Default is 'false'. 20 | - mutation :(optional) scalar, mutation rate. 21 | - CR :(optional) scalar, crossover rate. 22 | - simplex :(optional) 1 X n logical maxtrix. 'true' specifies the parameters that should be positive and sum up to 1. 23 | - name :(optional) name of output figure. Default 'DEMCtest'. 24 | 25 | ##### Output fields 26 | - chain : population at each generation. 27 | - obj : evaluation (objective) function value at each generation. 28 | - best : best individual at last generation. 29 | 30 | 31 | 32 | #### function MCMC 33 | Markov Chain Monte Carlo with Random-Walk Metropolis. 34 | ##### Input fields 35 | One of 'loc', 'funcPrior', 'bound'(in descending priority) must be specified. 36 | - life : length of Markov Chain. 37 | - func : liklihood function. Calculates the liklihood from parameter. 38 | - funcProp : (optional) proposal distribution function. Make new proposal 39 | - according to parameter. Default is normal distribution with sigma = 1. 40 | - loc : (optional) initial parameter. 41 | - funcPrior : (optional) prior function to generate initial parameter. 42 | - bound : (optional) 2 X n matrix, where n is the parameter dimension. 43 | - Lower(first row) and upper(second row) bounds of parameter. 44 | 45 | ##### Output fields 46 | - chain : m X n matrix, where m = length and n = parameter dimension. 47 | - time : m X 1 matrix, time stamp of each step. 48 | 49 | ##### Warning : Using 'bound' might break detailed balance and result in gibberish posterior. Not recommended. 50 | 51 | 52 | #### function EnKF 53 | Ensemble Kalman filter. Updated forecast and analysis states using observation and ensemble Kalman filter. 54 | 55 | ##### Input fields 56 | - R : measurement error (sigma). 57 | - Fstates : forecast states. 1 X n matrix, n = number of state 58 | - Astates : analysis states. 1 X n matrix. 59 | - obs : observation states. Scaler. 60 | - func : model operator, from current state to next state. 61 | 62 | ##### Output 63 | The same structue with updated Fstates and Astates, as well as estimation of model error (C). 64 | 65 | 66 | 67 | #### function ModAv 68 | Multi-model averaging function. Supported methods: 69 | - EWA : Equal Weights Averaging 70 | - BGA : Bates-Granger Averaging 71 | - AICA : Akaike's Information Criterion Averaging 72 | - BICA : Bayes Information Criterion Averaging 73 | - GRA : Granger-Ramanathan Averaging 74 | - BMA : Bayesian Model Averaging 75 | - MMA : Mallows Model Averaging 76 | - MMAd : Mallows Model Averaging (lie on simplex) 77 | 78 | ##### Input fields 79 | - Xcali : m1 X n model prediction matrix for calibration period. m1 = time 80 | - length of calibration period, n = model number. 81 | - Ycali : m1 X 1 observation matrix for calibration period. 82 | - Xeval : m2 X n model prediction matrix for evaluation period. 83 | - Yeval : m2 X 1 observation matrix for evaluation period. 84 | - p : 1 X n matrix of model parameter numbers. 85 | - method : abbreviation of method. 86 | 87 | ##### Output fields 88 | - weight : model weights. 89 | - RMSEcali : RMSE of calibration period. 90 | - RMSEeval : RMSE of evaluation period. 91 | - chain : (BMA, MMA and MMAd) model weights in all iterations. 92 | - obj : (BMA, MMA and MMAd) objective function value for all iterations. 93 | - sigma : (BMA) optimized model sigma. 94 | 95 | ##### Warning: Method BMA could be slow and unstable. 96 | 97 | 98 | 99 | #### function ABCPMC 100 | Approximate Bayesian Computing-Population Monte Carlo method. 101 | 102 | ##### Input fields 103 | - obs : 1 X d, d = dimension of target 104 | - bound : 2 X n matrix, where n is the parameter dimension. Lower 105 | - (first row) and upper(second row) bounds of parameter. 106 | - funcPrior : prior distribution function to generate parameter. 107 | - funcSummar : function to model target from parameter. 108 | - funcDist : function to calculate distance between modeled and observed 109 | - target. 110 | - epsl : 1 X i epsilon matrix, where i is the number of generations. 111 | - size : population size 112 | 113 | #### Output 114 | The same strucuture with extra fields. 115 | - inds : individuals (parameters) for all generations. 116 | - summar : modeled target at all generations. 117 | - weight : weight matrix for all generations. 118 | - C : Covariance matrix for all geneations. 119 | - acRate : overall acceptance rate. 120 | 121 | 122 | ## Minimal Working Example 123 | For DEMC and MCMC: 124 | ``` 125 | %% Finding global minimum with DE 126 | 127 | % Test function: 2d Ackley's function 128 | pop.func = @(x) -20*exp(-.2*sqrt(.5*sum(x.^2)))... 129 | -exp(.5*sum(cos(2*pi*x)))+exp(1)+20; 130 | pop.bound = [-5,-5;5,5]; 131 | 132 | % Setup the DE settings 133 | pop.size = 50; pop.life = 200; pop.type = 'DE'; 134 | result = DEMC(pop); 135 | disp(['Global minimum from DE: ' num2str(result.best)]) 136 | 137 | 138 | %% Mapping posterior with MCMC and DEMC 139 | 140 | % Test function: wide spread mixture of two normal distributions: 1/3 of 141 | % N(-5,1) and 2/3 of N(5,1). We expect a mean of 1.67 and a std of 4.82 142 | pop.func = @(x) 1/3*normpdf(x,-5,1)+2/3*normpdf(x,5,1); 143 | pop.bound = [-100;100]+1.67; 144 | 145 | % Using DEMC. It should be able to sample both peaks. 146 | pop.type = 'DEMC'; pop.life = 1500; 147 | result = DEMC(pop); burnt = result.chain(pop.life/2:end,:); 148 | disp(['Mean estimated by DEMC: ' num2str(mean(burnt(:)))]) 149 | disp(['Std estimated by DEMC: ' num2str(std(burnt(:)))]) 150 | 151 | % Using MCMC. It should only be able to sample one peak (-5 or 5). 152 | pop.life = 10000; pop.loc = 0; 153 | result = MCMC(pop); burnt = result.chain(pop.life/2:end,:); 154 | disp(['Mean estimated by MCMC: ' num2str(mean(burnt))]) 155 | disp(['Std estimated by MCMC: ' num2str(std(burnt))]) 156 | ``` 157 | --------------------------------------------------------------------------------