## Introduction

Welcome to this Julia Jupyter notebook where we will present some likelihood-free inference methods!

The methods that we will cover are: Approximate Bayesian Computation (ABC) rejection sampling, ABC Markov chain Monte Carlo (ABC-MCMC), and particle Markov chain Monte Carlo (PMCMC). We will for each method  present a hands-on case study.

A self-containing introduction to Bayesian inference and the standard Metropolis-Hastings algorithm is provided in this notebook in Section [1](#sec_intro). However, a reader already familiar with these topics can skip this introduction without loss of information.

#### About this notebook

This notebook was originally created as a part of the course *Reproducible and Interactive Data Science* ([course homepage](https://github.com/mlund/jupyter-course)). The author of this notebook is Samuel Wiqvist Ph.D. student in mathematical statistics at Lund University ([homepage](http://www.maths.lu.se/staff/samuel-wiqvist/), [Twitter](https://www.twitter.com/samuel_wiqvist)). If you have any comments or questions, please feel free to contact me via mail or on Twitter.

# Table of contents
1. [Bayesian inference using the Metropolis-Hastings algorithm](#sec_intro)
    1. [Case study - Bayesian linear regression](#subsec_intro)

2. [Likelihood-free inference](#sec_lik_free_inference)

3. [ABC method](#secabc)
    1. [ABC rejection sampling](#subsecabc1)
        1. [Case study - g-and-k distribution](#subsecabc1_case)
    1. [ABC-MCMC](#subsecabcmcmc)
        1. [Case study - g-and-k distribution, again](#subsubsecabc2_case)
            1. [Exact Bayesian inference for the g-and-k distribution](#excat_bayesian_g_and_k)
            2. [Comparing inference results for the g-and-k distribution](#comp_inf_res_g_and_k)
4. [Particle Markov chain Monte Carlo method](#secpmcmc)
    1. [Case study - Ricker model](#subsecpmcmc2)

5. [Current research questions](#secreseach)

6. [Conclusions](#conclusions)

## Bayesian inference using the Metropolis-Hastings algorithm

We will here consider the Bayesian inference problem where the main goal is to compute the posterior distribution $p(\theta | y)$ of the paramters. A Bayesian model in our setting consists of three parts: the prior $p(\theta)$, the likelihood $p(y | \theta)$, and the posterior $p(\theta | y)$. The prior $p(\theta)$ is the probability model for the parameters *before* we have *seen* the data and it incorporates our prior beliefs about the parameters. The likelihood $p(y | \theta)$ is the probability model for the data $y$ *given* the parameters, and in the standard case is this model known analytically. The posterior $p(\theta | y)$ is the probability model for the parameters *given* data, and the main task in the Bayesian inference scheme is to compute (usually using some numerical method) this distribution.

Using Bayes rule, we have that

\begin{align*}
p(\theta | y) = \frac{p(y | \theta) p(\theta)}{p(y)} = \frac{p(y | \theta) p(\theta)}{\int_{}^{} p(y | \theta) p(\theta) d\theta}.
\end{align*}

Hence, the Bayesian inference problem *can* in priciple be solved by simply applying Bayes rule. This, however, only works for simple problems where the integral $\int_{}^{} p(y | \theta) p(\theta) d\theta$ can be computed, or in cases where the functional form of the posterior is known analytically. In practice  is the  integral $\int_{}^{} p(y | \theta) p(\theta) d\theta$ often hard  to compute, or analytical intractable. However, the integral $\int_{}^{} p(y | \theta) p(\theta) d\theta$  is the normalizing constant, and if this constant is not included we have

\begin{align*}
p(\theta | y) \propto p(y | \theta) p(\theta).
\end{align*}

This is an important property for the posterior distribution since the normalizing constant is unimportant in many MCMC algorithms, and this property allows us to compute the posterior distribution up to a normalizing constant. For an overview of the literature see [ [6]](#etz_16), and [ [8]](#gelman_17) for an excellent explanation of the role of the prior distribution.

We will now consider the Metropolis-Hastings (MH) algorithm which is a Markov chain Monte Carlo method. The main idea of a Markov chain Monte Carlo method is to construct a Markov chain that has the posterior distribution as its stationary distribution. The MH algorithm obtains this goal by generating proposals $\theta^{\star}$ from a proposal distribution $g(\cdot|\theta^{i-1})$ and the proposals are accepted in such a manner that the stationary distribution of the chain (under some regulatory conditions) is the posterior distribution (see [ [20]](#yildirim_12) for an accessible introduction to the MH algorithm). The pseudo-code for the MH algorithm is

At iteration $i$:
1. Generate proposal $\theta^{\star} \sim g(\cdot|\theta^{i-1})$.
2. Compute acceptance probability $\alpha = \min(1, \frac{p(y|\theta^{\star})p(\theta^{\star})g(\theta^{i-1}|\theta^{\star})}{p(y|\theta^{i-1})p(\theta^{i-1})g(\theta^{\star}|\theta^{i-1})})$.
3. Draw $u \sim \mathcal{U}(0,1)$.
4. If $u \leq \alpha$ accepte the proposal, and add it to the chain, else reject the proposal, and keep the old $\theta^{i-1}$.

The proposal distribution $g(\cdot|\theta^{i-1})$ plays an inportant role for the preformace of the MH algorithm. A common case is to use a Gaussian distribution for the proposal distribution such that we have $g(\cdot|\theta^{i-1}) \sim \mathcal{N}(\theta^{i-1}, \sigma)$. However, selecting the standard deviation $\sigma$ now plays an important role since  $\sigma$  will have a large impact on the performance of the algorithm. If $\sigma$ is too small will the acceptance rate be very high, but the algorithm will not efficiently explore the parameter space. On the other hand, if $\sigma$ is too high will the acceptance rate be too low, and the chain will mix slowly.

Another popular choice is to adaptively tune the proposal distribution and thereby avoiding the problem of setting the $\sigma$ parameter in the proposal distribution. For further reading on adaptive tuning of the proposal distribution see  [ [10]](#haario_01), [ [2]](#andrieu_08), and [ [12]](#muller_10).

### Case study - Bayesian linear regression

The simple linear regression model is commonly used in statistics, and the model follows

\begin{align*}
y_i = \beta_0 + \beta_1 x_i + \epsilon_i, \, \epsilon_i \stackrel{i.i.d}{\sim} \mathcal{N}(0, \sigma).
\end{align*}

The unknown parameters of interest are $\theta = [\beta_0, \beta_1, \sigma]$, and we will set the ground-truth parameters to $\theta_{\text{true}} = [1.2, 1.5, 2]$.

This model can also be considered in a Bayesian setting by adding prior distributions to the unknown parameters, and we then have following model

\begin{align*}
y_i &= \beta_0 + \beta_1 x_i + \epsilon_i, \, \epsilon_i \sim \mathcal{N}(0, \sigma), \\
\beta_0, \beta_1 &\sim \mathcal{N}(0, 10), \\
\sigma &\sim \text{Gamma}(2,3).
\end{align*}

The prior distribution for the $\beta$ parameters is a Normal distribution with mean 0 and standard deviation 10. Hence, this prior is a wide distribution centered at zero that allows for both positive and negative $\beta$'s. The prior distribution for $\sigma$ is a Gamma distribution with shape parameter 2, and scale parameter 3. This is also a quite conservative prior, but this prior does not support negative values since $\sigma$ must be positive.

We will now estimate the parameter for the simple linear regression model using standard least squares estimation methods. Afterwards for the Bayesian version of the model we will use the MH algorithm.

Load packages.

```julia
using PyPlot # for plotting
using Distributions # function for variuse distributions
using StatsBase # simple stats functions
using KernelDensity # kernel density estimation
using DataFrames # dataframe functionalities
using CSV # to load data
```

    WARNING: Method definition ==(Base.Nullable{S}, Base.Nullable{T}) in module Base at nullable.jl:238 overwritten in module NullableArrays at C:\Users\samuel\.julia\v0.6\NullableArrays\src\operators.jl:99.

Load data (the data is generated from the model using the ground-truth parameters).

```julia
# set model parameters
β_0 = 1.2;
β_1 = 1.5;
σ = 2;
θ_true = [β_0, β_1, σ];

# load data
lin_red_data = CSV.read("data/lin_reg_data.csv", nullable=false);
x = vec(Array(lin_red_data[1,:]));
y = vec(Array(lin_red_data[2,:]));

# set nbr data points
n = length(x);

```

Plot data.

```julia
PyPlot.figure(figsize=(5,5));
PyPlot.scatter(x,y);
PyPlot.xlabel(L"$x$");
PyPlot.ylabel(L"$y$");
```

Before estimating the unknown parameters for the Bayesian model, we estimate the parameters of the simple linear regression model using least squares.

```julia
n = length(y) # set nbr of obs

X = ones(n,2); # set design matrix
X[:,2] = x;

β_hat_least_squares = round.(inv(X'*X)*X'*y,3); # est β'as
σ_hat_least_squares = round.(sqrt((y'*y-β_hat_least_squares'*X'*y)/(n-2)),3); # est σ
β_hat_least_squares_std = σ_hat_least_squares*sqrt.(diag(inv(X'*X)));

# compute conf int for β'as
conf_int_lower_bound = round.(β_hat_least_squares - quantile(TDist(n-2), 0.975)*β_hat_least_squares_std,3);
conf_int_upper_bound = round.(β_hat_least_squares + quantile(TDist(n-2), 0.975)*β_hat_least_squares_std,3);

# compute conf int for σ
Q_0 = sum((y-mean(y)).^2) - sum((x-mean(x)).*(y-mean(y)))^2/sum((x-mean(x)).^2);

conf_int_sigma = round.([sqrt(Q_0/quantile(Chisq(n-2),0.975)), sqrt(Q_0/quantile(Chisq(n-2),0.025))],3);

```

Parameter estimations and 95% confidence intervals in parentheses (note that we only obtain confidence intervals for the $\beta$ parameters).

```julia
df_ls_param_est = DataFrame(parameter = ["β_0"; "β_1";"σ"], true_values = θ_true, param_est  = ["$(β_hat_least_squares[1]) ($(conf_int_lower_bound[1]), $(conf_int_upper_bound[1]))"; "$(β_hat_least_squares[2]) ($(conf_int_lower_bound[2]), $(conf_int_upper_bound[2]))"; "$(σ_hat_least_squares) ($(conf_int_sigma[1]), $(conf_int_sigma[2]))"])
```

	parameter	true_values	param_est

1	β_0	1.2	1.791 (0.652, 2.93)

2	β_1	1.5	1.459 (1.247, 1.671)

3	σ	2.0	1.844 (1.438, 2.594)

We now continue to the Bayesian model, and we first set the parameters for the prior distributions.

```julia
# prior for β's: Normal(0,10)
μ_β_prior = 0;
σ_β_prior = 10;

# prior for σ: Gamma(2,3)
α_σ_prior = 2; # shape parameter
θ_σ_prior = 3; # scale parameter
```

The next step is to set up some functions needed for the MH algorithm.

Function to evaluate the joint log-prior.

```julia
doc"""
    log_prior(θ::Vector)

Evaluates the logarithm of the pdf for the joint prior.
"""
function log_prior(θ::Vector)

  log_β_0_prior = log_normal_pdf(θ[1])
  log_β_1_prior = log_normal_pdf(θ[2])
  log_σ_prior = log_gamma_pdf(θ[3])

  return log_β_0_prior+log_β_1_prior+log_σ_prior

end
```

    log_prior

The logarithm of the probability density function for the Normal distribution. Notice that the normalizing constant, and the term that only depends on $\sigma$ in the Normal distribution, are removed since these terms do not depend on the $\theta$ proposals in the MH algorithm.

```julia
doc"""
    log_normal_pdf(x::Real)

Logarithm of the normal pdf.
"""
function log_normal_pdf(x::Real)
  return -0.5*(x-μ_β_prior)^2/σ_β_prior^2

end
```

    log_normal_pdf

Logarithm of the probability density function for the Gamma distribution. We again remove unnecessary constants, and we also set the probability density function to zero if $x$ is less than zero since the Gamma distribution only supports positive $x$ values.

```julia
doc"""
    log_gamma_pdf(x::Real)

Logarithm of the Gamma pdf.
"""
function log_gamma_pdf(x::Real)
  if x <= 0
    return log(0)
  else
    return (α_σ_prior-1)*log(x)-x/θ_σ_prior
  end
end
```

    log_gamma_pdf

Since we assume Gaussian noise in the simple linear model, we have that the likelihood function for the simple linear model can be written as

\begin{align*}
p(y | \theta) = \prod_{i =1}^{N} \frac{1}{\sqrt{2\pi\sigma^2}}\exp\Big(-\frac{(y_i - \beta_0 - \beta_1 x_i)^2}{2\sigma^2}\Big).
\end{align*}

Where we have that $\theta = [\beta_0, \beta_ 1, \sigma]$. Now taking the logarithm of the likelihood function yields

\begin{align*}
\log p(y | \theta) = \sum_{i =1}^{N}  -\frac{1}{2}\log(2\pi) -\frac{1}{2}\log(\sigma^2) -\frac{(y_i - \beta_0 - \beta_1 x_i)^2}{2\sigma^2}.
\end{align*}

Hence, after removing constants, we can compute the log-likelihood using the function ```loglik```.

```julia
doc"""
    loglik(y::Vector, x::Vector, θ::Vector)

Log-likelihood for the simple linear model.
"""
function loglik(y::Vector, x::Vector, θ::Vector)

  n = length(y)
  loglik = -n*0.5*log(θ[3]^2)

  for i = 1:n
    loglik += -0.5*(y[i]-θ[1]-θ[2]*x[i])^2/θ[3]^2
  end

  return loglik

end
```

    loglik

The MH algorithm. Notice that we compute the acceptance probability on the log-scale and that a random walk proposal with fixed scaling is used. Since the proposal distribution is symmetric (it is a Gaussian distribution in this case) are the two proposal components removed from the calculation of the acceptance probability.

```julia

doc"""
    MH(y::Vector, x::Vector, nbr_iter::Int, σ_mh::Real, θ_0::Vector, print_interval::Int=500)

Runs the Metropolis-Hastings algorithm.
"""
function MH(y::Vector, x::Vector, nbr_iter::Int, σ_mh::Real, θ_0::Vector, print_interval::Int=500)

  # pre-allocate matrices
  chain = zeros(length(θ_0), nbr_iter)
  loglik_vec = zeros(nbr_iter)
  accept_vec = zeros(nbr_iter)

  # set start values
  chain[:,1] = θ_0
  loglik_vec[1] = loglik(y,x,chain[:,1])

  # print start
  @printf "Starting Metropolis-Hastings\n"

  for i = 2:nbr_iter

    # print info
    if mod(i-1,print_interval) == 0
      # print progress
      @printf "Percentage done: %.2f\n" 100*(i-1)/nbr_iter
      # print current acceptance rate
      @printf "Acceptance rate on iteration %d to %d is %.4f\n" i-print_interval i-1  sum(accept_vec[i-print_interval:i-1])/( i-1 - (i-print_interval) )
    end

    # random walk proposal
    θ_proposal = chain[:,i-1] + rand(Normal(0,1),length(θ_0))*σ_mh

    # loglik for proposal
    loglik_proposal = loglik(y,x,θ_proposal)

    # compute logarithm of accaptance probability
    α_log = loglik_proposal + log_prior(θ_proposal) - (loglik(y,x,chain[:,i-1])+ log_prior(chain[:,i-1]))

    # generate log random number
    u_log = log(rand())

    # compute accaptance decision
    accept = u_log < α_log

    # update chain
    if accept
      chain[:,i] = θ_proposal
      loglik_vec[i] = loglik_proposal
      accept_vec[i] = 1
    else
      chain[:,i] = chain[:,i-1]
      loglik_vec[i] = loglik_vec[i-1]
    end

  end

  # print info
  @printf "Ending Metropolis-Hastings\n"
  return chain, loglik_vec, accept_vec

end
```

    MH

Estimate parameters for the Bayesian version of the simple linear regression model.

```julia
nbr_iter = 10000; # nbr iterations
burn_in = 2000; # burn-in
scale_proposal = 0.4; # scaling for proposal dist.
θ_0 = [10,10,10]; # start values

# fix random numbers
srand(100);

chain, loglik_vec, accept_vec = @time MH(y, x, nbr_iter, scale_proposal, θ_0);

```

    Starting Metropolis-Hastings
    Percentage done: 5.00
    Acceptance rate on iteration 1 to 500 is 0.3367
    Percentage done: 10.00
    Acceptance rate on iteration 501 to 1000 is 0.1563
    Percentage done: 15.00
    Acceptance rate on iteration 1001 to 1500 is 0.1062
    Percentage done: 20.00
    Acceptance rate on iteration 1501 to 2000 is 0.2064
    Percentage done: 25.00
    Acceptance rate on iteration 2001 to 2500 is 0.1303
    Percentage done: 30.00
    Acceptance rate on iteration 2501 to 3000 is 0.1283
    Percentage done: 35.00
    Acceptance rate on iteration 3001 to 3500 is 0.1563
    Percentage done: 40.00
    Acceptance rate on iteration 3501 to 4000 is 0.1383
    Percentage done: 45.00
    Acceptance rate on iteration 4001 to 4500 is 0.1202
    Percentage done: 50.00
    Acceptance rate on iteration 4501 to 5000 is 0.1303
    Percentage done: 55.00
    Acceptance rate on iteration 5001 to 5500 is 0.1663
    Percentage done: 60.00
    Acceptance rate on iteration 5501 to 6000 is 0.1583
    Percentage done: 65.00
    Acceptance rate on iteration 6001 to 6500 is 0.1343
    Percentage done: 70.00
    Acceptance rate on iteration 6501 to 7000 is 0.1643
    Percentage done: 75.00
    Acceptance rate on iteration 7001 to 7500 is 0.1784
    Percentage done: 80.00
    Acceptance rate on iteration 7501 to 8000 is 0.1583
    Percentage done: 85.00
    Acceptance rate on iteration 8001 to 8500 is 0.1503
    Percentage done: 90.00
    Acceptance rate on iteration 8501 to 9000 is 0.1443
    Percentage done: 95.00
    Acceptance rate on iteration 9001 to 9500 is 0.1583
    Ending Metropolis-Hastings
      0.392646 seconds (680.64 k allocations: 21.757 MiB, 2.71% gc time)

Set posterior samples, i.e., chain after burn-in.

```julia
posterior_samples = chain[:,burn_in:end]
```

    3×8001 Array{Float64,2}:
     2.09103  2.09103  2.49238  2.49238  …  2.21726  2.21726  2.21726  2.21726
     1.45582  1.45582  1.43895  1.43895     1.50982  1.50982  1.50982  1.50982
     1.9666   1.9666   1.63706  1.63706     1.96168  1.96168  1.96168  1.96168

Parameter estimations (posterior mean), and posterior quantile intervals, 2.5th and 97.5th quantiles in parenthesis.

```julia
# calc posterior mean
post_mean_mh = round.(mean(posterior_samples,2),3)

# calc posterior quantiles
q = round.([quantile(posterior_samples[1,:], [0.025 0.975])
            quantile(posterior_samples[2,:], [0.025 0.975])
            quantile(posterior_samples[3,:], [0.025 0.975])],3)

# create data frame
df_mh_param_est = DataFrame(parameter = ["β_0"; "β_1";"σ"], true_values = θ_true, param_est  = ["$(post_mean_mh[1]) ($(q[1,1]), $(q[1,2]))"; "$(post_mean_mh[2]) ($(q[2,1]), $(q[2,2]))"; "$(post_mean_mh[3]) ($(q[3,1]), $(q[3,2]))"])
```

	parameter	true_values	param_est

1	β_0	1.2	1.789 (0.595, 3.025)

2	β_1	1.5	1.455 (1.221, 1.691)

3	σ	2.0	2.004 (1.509, 2.72)

Plot chains. The chains follow the blue lines, and the true parameter values are indicated with the black line.

```julia
PyPlot.figure(figsize=(10,6));
PyPlot.subplot(311);
PyPlot.plot(chain[1,:]);
PyPlot.plot(ones(size(chain,2),1)*θ_true[1], "k");
PyPlot.ylabel(L"$β_0$");
PyPlot.subplot(312);
PyPlot.plot(chain[2,:]);
PyPlot.plot(ones(size(chain,2),1)*θ_true[2], "k");
PyPlot.ylabel(L"$β_1$");
PyPlot.subplot(313);
PyPlot.plot(chain[3,:]);
PyPlot.plot(ones(size(chain,2),1)*θ_true[3], "k");
PyPlot.xlabel(L"Iteration");
PyPlot.ylabel(L"$σ$");
```

Plot posterior distribution. The marginal posteriors follow the blue lines, the prior distributions follow the green lines, and the true parameter values are indicated with the black vertical lines.

```julia
# calc grid for prior dist
x_c1 = -50:0.5:50;
x_c2 = -50:0.5:50;
x_c3 = 0:0.5:30;

# calc prior dist
priordens_c1 = pdf.(Normal(μ_β_prior, σ_β_prior), x_c1);
priordens_c2 = pdf.(Normal(μ_β_prior, σ_β_prior), x_c2);
priordens_c3 = pdf.(Gamma(α_σ_prior, θ_σ_prior), x_c3);

# calc kernel density approx. for approx. posterior
h1 = kde(posterior_samples[1,:]);
h2 = kde(posterior_samples[2,:]);
h3 = kde(posterior_samples[3,:]);

PyPlot.figure(figsize=(8,6));
subplot(311);
PyPlot.plot(h1.x,h1.density, "b");
PyPlot.plot(x_c1,priordens_c1, "g");
PyPlot.plot((θ_true[1], θ_true[1]), (0, maximum(h1.density)), "k");
PyPlot.xlabel(L"$β_0$");
PyPlot.ylabel("Density");
axis([minimum(h1.x)-0.5, maximum(h1.x)+0.5, 0, maximum(h1.density)+0.1]);
subplot(312);
PyPlot.plot(h2.x,h2.density, "b");
PyPlot.plot(x_c2,priordens_c2, "g");
PyPlot.plot((θ_true[2], θ_true[2]), (0, maximum(h2.density)), "k");
PyPlot.xlabel(L"$β_1$");
PyPlot.ylabel("Density");
axis([minimum(h2.x)-0.5, maximum(h2.x)+0.5, 0, maximum(h2.density)+0.1]);
subplot(313);
PyPlot.plot(h3.x,h3.density, "b");
PyPlot.plot(x_c3,priordens_c3, "g");
PyPlot.plot((θ_true[3], θ_true[3]), (0, maximum(h3.density)), "k");
PyPlot.xlabel(L"$σ$");
PyPlot.ylabel("Density");
axis([minimum(h3.x)-0.5, maximum(h3.x)+0.5, 0, maximum(h3.density)+0.1]);
```

Compare parameter estimations obtained from least squares and the MH algorithm.

```julia
df_param_est = DataFrame(parameter = ["β_0"; "β_1";"σ"], true_values = θ_true, least_squares = ["$(df_ls_param_est[1,3])"; "$(df_ls_param_est[2,3])"; "$(df_ls_param_est[3,3])"], Metropolis_Hastings = ["$(df_mh_param_est[1,3])"; "$(df_mh_param_est[2,3])"; "$(df_mh_param_est[3,3])"])
```

	parameter	true_values	least_squares	Metropolis_Hastings

1	β_0	1.2	1.791 (0.652, 2.93)	1.789 (0.595, 3.025)

2	β_1	1.5	1.459 (1.247, 1.671)	1.455 (1.221, 1.691)

3	σ	2.0	1.844 (1.438, 2.594)	2.004 (1.509, 2.72)

We can conclude that the parameter estimates for both the linear model and the Bayesian linear model are similar. In particular, we notice that both the point estimations and the intervals are similar. However, it is not surprising that the parameter estimations differ slightly since we compare parameter estimations for two different models, and not the same model. That being said, we see that we can cast a familiar statistical model into a Bayesian version of the same model, and still obtain parameter estimates that are similar to the ones we get from a standard estimation scheme.

# Likelihood-free inference

To use the standard MH algorithm is it necessary to be able to evaluate the likelihood function $p(y|\theta)$. However, for some models is the likelihood function analytically of computationally intractable, and the standard MH algorithm can then not be used. But we can still compute Bayesian inference if we use a likelihood-free algorithm, which is an algorithm where we do not need to evaluate the likelihood function. We will here consider the ABC method, and the particle Markov chain Monte Carlo algorithm.

## ABC method

The Approximate Bayesian Computation method is an inexact inference method, meaning that the algorithm generates an approximation of the posterior $p(y|\theta)$. However, the ABC method is still useful since it is a very general method and can be applied to many models since the only real requirement on the model is that we need to be able to generate data from the model. The main idea of the ABC method is to generate parameter value from a proposal distribution, and keep generated parameter values that correspond to data *similar* to the real data. A good introduction to the ABC method is [ [5]](#drovandie_17).

### ABC rejection sampling

The most basic ABC method is the rejection sampling method, and the simplest version of this algorithm follows

At iteration i:
1. Generate $\theta^{\star} \sim p(\theta)$.
2. Generate data set $y^{\star}$ from the model using $\theta^{\star}$.
3. Accept $\theta^{\star}$ if $y^{\star} = y$.

This algorithm will of course only work for discrete data, and for long data sets will this algorithm be *very* inefficient since we require an exact data match to accept the proposal $\theta^{\star}$. Instead of requiring an exact data match we introduce a set of summary statistics $S(y)$ that are informative for the data, and we then have following algorithm

At iteration t
1. Generate $\theta^{\star} \sim p(\theta)$.
2. Generate data set $y^{\star}$ from the model using $\theta^{\star}$.
3. Compute summery statistics $s^{\star} = S(y^{\star})$
3. Accept $\theta^{\star}$ if $\rho(s^{\star}, s) \leq \epsilon$.

Hence, we now have a rejection sampling algorithm where we accept a proposal if the distance between the summary statistics obtained using proposal $s^{\star}$ and the summary statistics for the data $s$ is smaller than some bandwidth $\epsilon$. The posterior that we obtain from this algorithm is an approximate posterior such that $p(\theta | y)_{\bf{1}(\rho(s^{\star}, s) \leq \epsilon)}$.

The problem of selecting summary statistics is of importance for the performance of the ABC  method. The summary statistics should be informative for the data, and a popular method is to simply select statistics that capture features of the data. However, there also exist more advanced semi-automatic methods for selecting the summary statistics. [ [15]](#prangle_15)

We will now walk through the code for the ABC rejection sampling algorithm:

Load the adaptive tuning algorithms for the proposal distribution.

```julia
include("adaptiveupdate.jl")
```

    WARNING: replacing docs for 'FixedKernel :: Union{}' in module 'Main'.
    WARNING: replacing docs for 'AMUpdate :: Union{}' in module 'Main'.

    adaptation (generic function with 3 methods)

Types describing the different parts of the problem.

```julia
"Type for prior distribution"
type PriorDistribution
  dist::String
  prior_parameters::Array{Float64}
end

"Type for the data"
type Data
  y::Array{Float64}
end

"Pararameters for the model"
type ModelParameters
  theta_true::Array{Float64}
  theta_known::Float64
  theta_0::Array{Float64}
end

"type for the algorithm parameters for the ABC-MCMC algorithm"
type AlgorithmParametersABCMCMC
  R::Int64
  burn_in::Int64
  alg::String
  print_interval::Int64
  nbr_summary_stats::Int64
  eps::Vector
  start::String
  w::Vector
end

"Type for the problem (including algorithm parameters) for the PMCMC algorithm"
type ProblemABCMCMC
  data::Data
  alg_param::AlgorithmParametersABCMCMC
  model_param::ModelParameters
  adaptive_update::AdaptationAlgorithm
  prior_dist::PriorDistribution
end

"Type for the results"
type Result
  Theta_est::Array{Float64}
  accept_vec::Array{Float64}
  prior_vec::Array{Float64}
end

```

    WARNING: replacing docs for 'PriorDistribution :: Union{}' in module 'Main'.
    WARNING: replacing docs for 'Data :: Union{}' in module 'Main'.
    WARNING: replacing docs for 'ModelParameters :: Union{}' in module 'Main'.
    WARNING: replacing docs for 'AlgorithmParametersABCMCMC :: Union{}' in module 'Main'.
    WARNING: replacing docs for 'ProblemABCMCMC :: Union{}' in module 'Main'.
    WARNING: replacing docs for 'Result :: Union{}' in module 'Main'.

    Result

The ABC rejection sampling algorithm.

```julia

doc"""
    abcrejectionsampling(problem::ProblemABCMCMC, sample_from_prior, generate_data,calc_summary , prior_parameters::PriorDistribution, N::Int64, eps::Float64)

The standard ABC-rejection sampler.
"""
function abcrejectionsampling(problem::ProblemABCMCMC, sample_from_prior, generate_data,calc_summary , prior_parameters::PriorDistribution, N::Int64, eps::Float64)

  # data
  y = problem.data.y
  y_star = copy(y)

  # pre-allocate matrices and vectors
  theta_0 = problem.model_param.theta_0
  theta_star = similar(theta_0)
  theta_known = problem.model_param.theta_known # NaN
  print_interval = problem.alg_param.print_interval # print accaptance rate and covarince function ever print_interval:th iteration
  samples_approx_posterior = zeros(length(theta_0),N)
  nbr_samples = 0
  w =  problem.alg_param.w # the weigths are already "known" (need method to compute these...)

  # compute summary statistics
  s = calc_summary(y)

  proposals = zeros(length(theta_0),N)
  data_sets = zeros(length(y_star),N)
  distances = zeros(N)

  @printf "Starting ABC rejection sampling \n"
  @printf "Accuracy: ϵ = %f\n" eps

  for n = 1:N

    if mod(n-1,print_interval) == 0
      # print progress
      @printf "Percentage done: %.2f\n" 100*(n-1)/N
    end

    theta_star = sample_from_prior(prior_parameters)
    y_star = generate_data(length(y), theta_star,theta_known)
    s_star = calc_summary(y_star)

    proposals[:,n] = theta_star
    data_sets[:,n] = y_star
    dist = ρ(s,s_star,w)
    distances[n] = dist

    if dist < eps # accept proposal
      nbr_samples = nbr_samples + 1
      samples_approx_posterior[:,nbr_samples] = theta_star
    end

  end

  accaptance_rate = nbr_samples/N

  @printf "Ending ABC rejection sampling \n"
  @printf "Accaptance rate: %f\n" accaptance_rate

  return  samples_approx_posterior[:,1:nbr_samples], accaptance_rate, distances, proposals, data_sets

end
```

    WARNING: replacing docs for 'abcrejectionsampling :: Tuple{ProblemABCMCMC,Any,Any,Any,PriorDistribution,Int64,Float64}' in module 'Main'.

    abcrejectionsampling

The distance function. We will compute the distance as

\begin{align}
\rho(s^{\star}, s, w) = (s^{\star} - s)W^{-1}(s^{\star} - s).
\end{align}

Where $W$ is a diagonal matrix of the weighs $W = \text{diag}\{ w_1, \cdots, w_n \}$. The weights are obtained from a pre-run. The main advantage of computing the distance using this method is that we now can use summary statistics of different magnitudes without a problem. [ [16]](#prangle_17)

```julia
doc"""
    ρ(s::Vector, s_star::Vector, w::Vector)

Distance function.
"""
function ρ(s::Vector, s_star::Vector, w::Vector)

  Δs =  (s_star-s)
  dist = Δs'*inv(diagm(w.^2))*Δs
  return sqrt(dist[1])

end
```

    WARNING: replacing docs for 'ρ :: Tuple{Array{T,1} where T,Array{T,1} where T,Array{T,1} where T}' in module 'Main'.

    ρ

### Case study - g-and-k distribution

The g-and-k distribution is a standard problem to analyze using ABC methods, and we will therefore first consider the problem of estimating the parameters of the g-and-k distribution using the ABC rejection sampling algorithm.

For the g-and-k distribution is the quantile function give by

\begin{align}
    F^{-1}(x \mid A,B,c,g,k) = A + B \Big( 1 + c \frac{1- \exp(-g\cdot r(x))}{1+ \exp(-g\cdot r(x)} \Big)(1+r^{2}(x))^{k}r(x).
\end{align}

Where $A$,$B$,$c$,$g$, and $k$ are the parameters of the g-and-k distribution and $r(x)$ the $x$th standard normal quantile.

We will for the g-and-k distribution follow a setting often used in the literatur (see [ [1]](#allingham_etal_09), and [ [14]](#picchini_17)), and we therefore assume that the unknown parameters are $\theta = (A,B,g,k)$, and set $c = 0.8$. The true parameter value are set to $\theta_{true} = (3,1,2,0.5)$, and the data set $y$ contains 5000 observations. We will follow [ [14]](#picchini_17) and use a flat prior distribution $\mathcal{U}(0,10)$ for all parameters, and the summery statistics: $s(y) = (P_{20},P_{40},P_{50},P_{60},P_{80}, \text{skew}(y))$, where $P_x$ is the $x$th percentile of the data and $\text{skew}$ is the skewness of the data. We do not use any pre-run to estimate the weighs $w$ for the summery statistics, instead we use the same weighs as in [ [14]](#picchini_17) and set $w = (0.22,0.19,0.53,2.29,1.90)$.

Function to set up the ABC rejection sampling problem for the g-and-k distribution.

```julia
doc"""
    set_up_abcmcmc_problem_gk(use_sim_data::Bool=true;nbr_of_unknown_parameters::Int64=2,
  prior_dist::String = "Uniform", adaptiveon::Bool = true, ploton::Bool = false,
  nbr_of_cores::Int64 = 8, T::Int64 = 10000,x0::Float64 = 7.,
  print_interval::Int64 = 500, alg::String="abcmcmc", nbr_summary_stats::Int64=5,
  start::String = "random")

set_up_abcmcmc_problem sets the parameters for the problem defined by the inputs.

# Output
* `problem`: An instance of the type ProblemABCMCMC cointaining all information for the problem
"""
function set_up_abcmcmc_problem_gk(use_sim_data::Bool=true;nbr_of_unknown_parameters::Int64=2,
  prior_dist::String = "Uniform", adaptiveon::Bool = true, ploton::Bool = false,
  nbr_of_cores::Int64 = 8, T::Int64 = 5000,x0::Float64 = 7.,
  print_interval::Int64 = 500, alg::String="abcmcmc", nbr_summary_stats::Int64=5,
  start::String = "random")

  # set algorithm parameters
  theta_true = [3; 1; 2; .5]  # [A,B,g,k]
  theta_0 =  copy(theta_true)

  if start == "non-random"
    theta_0 = [2;2;2;2]
  end

  prior_parameters = [0 10; 0 10; 0 10; 0 10]
  theta_known = .8 # c

  eps = [30*ones(5000); 25*ones(5000); 20*ones(5000); 15*ones(5000); 10*ones(5000); 5*ones(5000); 2.5*ones(5000); 1*ones(5000); 0.3*ones(5000); 0.2*ones(50000)] # ; 0.05*ones(100000)

  # create instance of AlgorithmParametersABCMCMC (set parameters to default values)
  alg_param = AlgorithmParametersABCMCMC(length(eps),length(eps)-35000,alg,print_interval,nbr_summary_stats,eps,start,ones(5)) # hardcoded nbr of summary stats

  # create instance of ModelParameters, all theta paramters are on log-scale
  model_param = ModelParameters(theta_true,theta_known,theta_0)

  # set data
  if use_sim_data
    y = generate_data_gk(T, theta_true[1], theta_true[2], theta_true[3], theta_true[4], theta_known)
  end

  # create instance of Data
  data = Data(y)

  # create instance of PriorDistribution
  prior = PriorDistribution(prior_dist, prior_parameters)

  # create instance of AdaptiveUpdate
  adaptive_update = AMUpdate(eye(length(theta_0)), 2.4/sqrt(length(theta_0)), 1., 0.7, 50)

  # return the an instance of Problem
  return ProblemABCMCMC(data, alg_param, model_param, adaptive_update, prior)

end
```

    WARNING: replacing docs for 'set_up_abcmcmc_problem_gk :: Union{Tuple{Bool}, Tuple{}}' in module 'Main'.

    set_up_abcmcmc_problem_gk

Function to generate data from the g-and-k distribution.

```julia
doc"""
    generate_data(T::Int65=50,r::Float64,phi::Float64,sigma::Float64,x0::Float64)

Generates data from the Ricker model.
"""
function generate_data_gk(T::Int64,A::Float64,B::Float64,g::Float64, k::Float64, c::Float64)

  z = rand(Normal(0,1), T)

  F_inv = similar(z)

  for i = 1:length(F_inv)
    F_inv[i] = A + B*(1 + c*(1-exp(-g*z[i]))/(1+exp(-g*z[i])))*(1+z[i]^2)^k*z[i]
  end

  return F_inv

end

```

    WARNING: replacing docs for 'generate_data_gk :: Tuple{Int64,Float64,Float64,Float64,Float64,Float64}' in module 'Main'.

    generate_data_gk

The general function to generate data.

```julia
function generate_data(N::Int64, theta_star::Vector, theta_known::Float64)

  return generate_data_gk(N,theta_star[1],theta_star[2],theta_star[3], theta_star[4], theta_known)

end

```

    generate_data (generic function with 1 method)

Function to sample from the prior distribution.

```julia
function sample_from_prior(prior_dist::PriorDistribution)

  theta_hat = zeros(size(prior_dist.prior_parameters,1))

  if prior_dist.dist == "Uniform"
    for i = 1:size(prior_dist.prior_parameters,1)
      theta_hat[i] = rand(Uniform(prior_dist.prior_parameters[i,1], prior_dist.prior_parameters[i,2]))
    end
  end

  return theta_hat

end
```

    sample_from_prior (generic function with 1 method)

Function to compute the summary statistics.

```julia
doc"""
    calc_summary(y::Vector)

Computes the summary statistics.
"""
function calc_summary(y::Vector)

  return [percentile(y, [20;40;60;80]);skewness(y)]

end
```

    WARNING: replacing docs for 'calc_summary :: Tuple{Array{T,1} where T}' in module 'Main'.

    calc_summary

We can now set up the g-and-k problem.

```julia
# create instance of problem type and generate data
problem = set_up_abcmcmc_problem_gk(ploton = false,
  start = "non-random", print_interval=1000);

# load data
problem.data.y = Array(CSV.read("data/gandk_data.csv", nullable=false))[:];

# set weigths
problem.alg_param.w = [0.22; 0.19; 0.53; 2.97; 1.90];

# set bandwidth
ϵ = 2.5;

# set nbr of iterations
N = Int64(5*10e3);

# set prior dist
prior = problem.prior_dist;
```

Plot data and empirical cumulative distribution function (CDF).

```julia
# plot simulated data
PyPlot.figure(figsize=(10,4));
subplot(121);
PyPlot.plt[:hist](problem.data.y,100)
PyPlot.ylabel("Freq.");
PyPlot.xlabel("Data");
PyPlot.title("Hist. of simulated data");

# compute empercial CDF
ecdf_func = ecdf(problem.data.y);
x = linspace(0, 30, 1000);

# plot emperical CDF
subplot(122);
PyPlot.plot(x,ecdf_func(x));
PyPlot.ylabel("Percent");
PyPlot.xlabel("Data");
PyPlot.title("Empirical CDF");

```

Run the ABC rejection sampling algorithm. WARNING: This can take a few minutes to run.

```julia
# fix random numbers
srand(100);

res = @time abcrejectionsampling(problem, sample_from_prior, generate_data, calc_summary, prior, N, ϵ)

```

    Starting ABC rejection sampling
    Accuracy: ϵ = 2.500000
    Percentage done: 0.00
    Percentage done: 2.00
    Percentage done: 4.00
    Percentage done: 6.00
    Percentage done: 8.00
    Percentage done: 10.00
    Percentage done: 12.00
    Percentage done: 14.00
    Percentage done: 16.00
    Percentage done: 18.00
    Percentage done: 20.00
    Percentage done: 22.00
    Percentage done: 24.00
    Percentage done: 26.00
    Percentage done: 28.00
    Percentage done: 30.00
    Percentage done: 32.00
    Percentage done: 34.00
    Percentage done: 36.00
    Percentage done: 38.00
    Percentage done: 40.00
    Percentage done: 42.00
    Percentage done: 44.00
    Percentage done: 46.00
    Percentage done: 48.00
    Percentage done: 50.00
    Percentage done: 52.00
    Percentage done: 54.00
    Percentage done: 56.00
    Percentage done: 58.00
    Percentage done: 60.00
    Percentage done: 62.00
    Percentage done: 64.00
    Percentage done: 66.00
    Percentage done: 68.00
    Percentage done: 70.00
    Percentage done: 72.00
    Percentage done: 74.00
    Percentage done: 76.00
    Percentage done: 78.00
    Percentage done: 80.00
    Percentage done: 82.00
    Percentage done: 84.00
    Percentage done: 86.00
    Percentage done: 88.00
    Percentage done: 90.00
    Percentage done: 92.00
    Percentage done: 94.00
    Percentage done: 96.00
    Percentage done: 98.00
    Ending ABC rejection sampling
    Accaptance rate: 0.001780
     57.712953 seconds (3.99 M allocations: 7.650 GiB, 2.32% gc time)

    ([2.84974 2.94921 … 2.53447 2.75429; 0.681838 1.28116 … 1.01928 2.23327; 3.86498 4.79759 … 8.30333 7.63495; 1.2853 0.812489 … 0.62598 0.503674], 0.00178, [3.00715, 37.7178, 27.5114, 58.5651, 154.443, 4.88324, 575.386, 1079.82, 20.2528, 142.42  …  37.9548, 78.2507, 46.2149, 50.5769, 360.353, 377.713, 37.9846, 158.317, 42.8971, 481.848], [2.60125 8.21009 … 8.79719 1.08342; 1.90313 1.62376 … 0.605185 2.4887; 6.60911 4.29838 … 2.7316 1.34658; 0.671932 0.375648 … 0.16352 7.92383], [15.1322 17.2229 … 10.5828 15.6328; 23.4947 25.3245 … 8.92231 -24.5435; … ; 3.22889 8.59126 … 9.8293 0.815958; 6.71508 8.0637 … 8.7209 -62600.5])

Set values for approximate posterior distribution.

```julia
approx_posterior_samples = res[1]
```

    4×89 Array{Float64,2}:
     2.84974   2.94921   2.80699  3.2394    …  3.0402    2.53447  2.75429
     0.681838  1.28116   1.5441   3.25771      1.35707   1.01928  2.23327
     3.86498   4.79759   4.18922  3.57153      4.25702   8.30333  7.63495
     1.2853    0.812489  1.25101  0.198029     0.290269  0.62598  0.503674

Parameter estimations (posterior mean), and posterior quantile intervals, 2.5th and 97.5th quantiles in parenthesis.

```julia
# calc posterior mean
post_mean_abcrs = round.(mean(approx_posterior_samples,2),3)

# calc quantiles
q_abcrs = round.([quantile(approx_posterior_samples[1,:], [0.025 0.975])
            quantile(approx_posterior_samples[2,:], [0.025 0.975])
            quantile(approx_posterior_samples[3,:], [0.025 0.975])
            quantile(approx_posterior_samples[4,:], [0.025 0.975])],3)

# create data frame
df_abcrs_param_est = DataFrame(parameter = ["A"; "B";"g";"k"], true_values = problem.model_param.theta_true, param_est  = ["$(post_mean_abcrs[1]) ($(q_abcrs[1,1]), $(q_abcrs[1,2]))"; "$(post_mean_abcrs[2]) ($(q_abcrs[2,1]), $(q_abcrs[2,2]))"; "$(post_mean_abcrs[3]) ($(q_abcrs[3,1]), $(q_abcrs[3,2]))"; "$(post_mean_abcrs[4]) ($(q_abcrs[4,1]), $(q_abcrs[4,2]))"])
```

	parameter	true_values	param_est

1	A	3.0	2.952 (2.535, 3.257)

2	B	1.0	1.194 (0.1, 2.745)

3	g	2.0	5.281 (0.382, 9.871)

4	k	0.5	0.647 (0.013, 1.375)

Acceptance rate.

```julia
print("$(round(res[2],4)*100) %")
```

    0.18 %

Plot approximate posterior distribution. The approximate marginal posteriors follow blue lines, the uniform prior distributions follow the green lines, and the true parameter values are indicated with the black vertical lines.

```julia

# plot approx. posterior dist
prior_parameters = prior.prior_parameters;

# calc grid for prior dist
x_c1 = prior_parameters[1,1]-0.5:0.01:prior_parameters[1,2]+0.5;
x_c2 = prior_parameters[2,1]-0.5:0.01:prior_parameters[2,2]+0.5;
x_c3 = prior_parameters[3,1]-0.5:0.01:prior_parameters[3,2]+0.5;
x_c4 = prior_parameters[4,1]-0.5:0.01:prior_parameters[4,2]+0.5;

# calc prior dist
priordens_c1 = pdf.(Uniform(prior_parameters[1,1], prior_parameters[1,2]), x_c1);
priordens_c2 = pdf.(Uniform(prior_parameters[2,1], prior_parameters[2,2]), x_c2);
priordens_c3 = pdf.(Uniform(prior_parameters[3,1], prior_parameters[3,2]), x_c3);
priordens_c4 = pdf.(Uniform(prior_parameters[4,1], prior_parameters[4,2]), x_c4);

# calc kernel density approx. for approx. posterior
h1_abc_reject = kde(approx_posterior_samples[1,:]);
h2_abc_reject = kde(approx_posterior_samples[2,:]);
h3_abc_reject = kde(approx_posterior_samples[3,:]);
h4_abc_reject = kde(approx_posterior_samples[4,:]);

PyPlot.figure(figsize=(10,8));
subplot(221);
PyPlot.plot(h1_abc_reject.x,h1_abc_reject.density, "b");
PyPlot.plot(x_c1,priordens_c1, "g");
PyPlot.plot((problem.model_param.theta_true[1], problem.model_param.theta_true[1]), (0, maximum(h1_abc_reject.density)), "k");
PyPlot.xlabel(L"$A$");
axis([minimum(h1_abc_reject.x), maximum(h1_abc_reject.x), 0, maximum(h1_abc_reject.density)+0.1]);
subplot(222);
PyPlot.plot(h2_abc_reject.x,h2_abc_reject.density, "b");
PyPlot.plot(x_c2,priordens_c2, "g");
PyPlot.plot((problem.model_param.theta_true[2], problem.model_param.theta_true[2]), (0, maximum(h2_abc_reject.density)), "k");
PyPlot.xlabel(L"$B$");
axis([minimum(h2_abc_reject.x), maximum(h2_abc_reject.x), 0, maximum(h2_abc_reject.density)+0.1]);
subplot(223);
PyPlot.plot(h3_abc_reject.x,h3_abc_reject.density, "b");
PyPlot.plot(x_c3,priordens_c3, "g");
PyPlot.plot((problem.model_param.theta_true[3], problem.model_param.theta_true[3]), (0, maximum(h3_abc_reject.density)), "k");
PyPlot.xlabel(L"$g$");
axis([minimum(h3_abc_reject.x), maximum(h3_abc_reject.x), 0, maximum(h3_abc_reject.density)+0.1]);
subplot(224);
PyPlot.plot(h4_abc_reject.x,h4_abc_reject.density, "b");
PyPlot.plot(x_c4,priordens_c4, "g");
PyPlot.plot((problem.model_param.theta_true[4], problem.model_param.theta_true[4]), (0, maximum(h4_abc_reject.density)), "k");
PyPlot.xlabel(L"$k$");
axis([minimum(h4_abc_reject.x), maximum(h4_abc_reject.x), 0, maximum(h4_abc_reject.density)+0.1]);

```

We see that we can estimate all parameters quite well, except $g$.

## ABC-MCMC

The ABC-MCMC algorithm is a MCMC type algorithm where the likelihood ratio of the standard MH algorithm is replaced with an indicator function that determines if the distance between the summary statistics for the proposal $s^{\star}$ and the data $s$ is sufficiently small (see [ [11]](#marjoram_03), and [ [18]](#scott_10) for a more detailed introduction to the algorithm). The pseudo-code for the algorithm is

At iteration t:
1. Generate $\theta^{\star} \sim g(\cdot|\theta^{i-1})$.
2. Generate data set $y^{\star}$ from the model using $\theta^{\star}$.
3. Compute summery statistics $s^{\star} = S(y^{\star})$
4. Compute  $\alpha = \min\big(1, \frac{\pi(\theta^{\star})}{\pi(\theta^{i-1})}\frac{q(\theta^{i-1} \mid \theta^{\star})}{q(\theta^{\star}  \mid \theta^{r-1})} \mathbb{1}(\rho(s,s^{\star},w) < \epsilon^{i-1})\big)$.
5. Draw $u \sim \mathcal{U}(0,1)$.
6. If $u \leq \alpha$ accepte the proposal, and add it tothe chain, else reject the proposal, and keep the old $\theta^{i-1}$.

The sequence $\epsilon^{i-1}$ is a sequence of bandwidths. In practice is this sequence a decreasing sequence of bandwidths allowing us to both explore the parameter space at the beginning of the algorithm and also obtaining a good approximation of the posterior distribution.

Since we already loaded all functions for an ABC type algorithm, we only have to load the ABC-MCMC function and its help functions.

```julia

doc"""
    abcmcmc(problem::ProblemABCMCMC, sample_from_prior, evaluate_prior, generate_data, calc_summary)

The ABC-MCMC algorithm.
"""
function abcmcmc(problem::ProblemABCMCMC, sample_from_prior, evaluate_prior, generate_data, calc_summary)

  # data
  y = problem.data.y
  y_star = copy(y)
  N = length(y) # length of data set

  # algorithm parameters
  R = problem.alg_param.R # number of iterations
  burn_in = problem.alg_param.burn_in # burn in
  print_interval = problem.alg_param.print_interval # print accaptance rate and covarince function ever print_interval:th iteration
  start = problem.alg_param.start

  # model parameters
  theta_true = problem.model_param.theta_true # [log(r) log(phi) log(sigma)]
  theta_known = problem.model_param.theta_known # NaN
  theta_0 = problem.model_param.theta_0 # [log(r_0) log(phi_0) log(sigma_0)]

  # ABC parameters
  nbr_summary_stats = problem.alg_param.nbr_summary_stats
  s = zeros(nbr_summary_stats)
  s_star = zeros(nbr_summary_stats)
  eps = problem.alg_param.eps
  w =  problem.alg_param.w
  s_matrix = zeros(length(s_star), R)

  # pre-allocate matrices and vectors
  Theta = zeros(length(theta_0),R)
  loglik = zeros(R)
  accept_vec = zeros(R)
  prior_vec = zeros(R)
  theta_star = zeros(length(theta_0))
  a_log = 0.

  # training data
  X = zeros(length(theta_0),R)
  Y = zeros(R)

  # parameters for adaptive update
  adaptive_update_params = set_adaptive_alg_params(problem.adaptive_update, length(theta_0),Theta[:,1], R)

  # parameters for prior dist
  dist_type = problem.prior_dist.dist
  prior_parameters = problem.prior_dist.prior_parameters

  # print information at start of algorithm
  @printf "Starting ABC-MCMC estimating %d parameters\n" length(theta_true)
  @printf "Adaptation algorithm: %s\n" typeof(problem.adaptive_update)
  @printf "Prior distribution: %s\n" problem.prior_dist.dist

  # first iteration
  @printf "Iteration: %d\n" 1
  @printf "Covariance:\n"
  print_covariance(problem.adaptive_update,adaptive_update_params, 1)

  s = calc_summary(y)

  # initial iteration
  if start == "random"
    while true
      theta_star = sample_from_prior(problem.prior_dist)
      y_star = generate_data(N, theta_star,theta_known)
      s_star = calc_summary(y_star)
      if ρ(s,s_star,w) < eps[1]
        break
      end
    end
  else
    theta_star = theta_0
  end

  dist_vec = zeros(R)
  ind_vec = zeros(R)
  Theta[:,1] = theta_star
  accept_vec[1] = 1

  @printf "Start value:\n"
  show(theta_star)

  X[:,1] = theta_star
  Y[1] = 1

  s_matrix[:,1] = calc_summary(y_star)

  for r = 2:R

    # set print_on to false, only print each print_interval:th iteration
    print_on = false

    # print acceptance rate for the last print_interval iterations
    if mod(r-1,print_interval) == 0
      print_on = true # print ESS and Nbr resample each print_interval:th iteration
      # print progress
      @printf "Percentage done: %.2f\n" 100*(r-1)/R
      # print accaptace rate
      @printf "Acceptance rate on iteration %d to %d is %.4f\n" r-print_interval r-1  sum(accept_vec[r-print_interval:r-1])/( r-1 - (r-print_interval) )
      # print covaraince function
      @printf "Covariance:\n"
      print_covariance(problem.adaptive_update,adaptive_update_params, r)
    end

    # Gaussian random walk
    (theta_star, ) = gaussian_random_walk(problem.adaptive_update, adaptive_update_params, Theta[:,r-1], r)

    # store theta_star
    X[:,r] = theta_star

    # compute accaptance probability
    if dist_type == "Uniform" # uniform priors
      prior_log_star = evaluate_prior(theta_star,prior_parameters)
      if prior_log_star == -Inf # reject if the proposed theta is outside the prior
        prior_vec[r] = 1
        accept = false
        Y[r] = 0 # store prob val
      else
        # Generate data
        y_star = generate_data(N, theta_star, theta_known)

        # Compute summary stats
        s_star = calc_summary(y_star)
        s_matrix[:,r] = s_star

        a = indicator(s , s_star, w, eps[r])
        a_log = log(a)
        accept =  a == 1
        Y[r] = a # store prob val
      end
    end

    # update chain
    if accept # the proposal is accapted
      Theta[:,r] = theta_star # update chain with new proposals
      accept_vec[r] = 1
    else
      dist_vec[r] = dist_vec[r-1]
      ind_vec[r] = ind_vec[r-1]
      Theta[:,r] = Theta[:,r-1] # keep old values
    end

    # adaptation of covaraince matrix for the proposal distribution
    adaptation(problem.adaptive_update, adaptive_update_params, Theta, r,a_log)

  end

  @printf "Ending ABC-MCMC with adaptive RW estimating %d parameters\n" length(theta_true)
  @printf "Adaptation algorithm: %s\n" typeof(problem.adaptive_update)
  @printf "Prior distribution: %s\n" problem.prior_dist.dist

  cov_prop_kernel = get_covariance(problem.adaptive_update,adaptive_update_params, R)

  return return_results(Theta,accept_vec,prior_vec, problem,adaptive_update_params),X,Y, cov_prop_kernel, s_matrix

end

# help functions for abcmcmc

doc"""
    indicator(s::Vector, s_star::Vector, w::Vector, eps::Float64)

Indicator function for the ABC-MCMC updating step.
"""
function indicator(s::Vector, s_star::Vector, w::Vector, eps::Float64)

  if ρ(s,s_star,w) < eps
    return 1.
  else
    return 0.
  end

end

doc"""
    return_results(Theta,loglik,accept_vec,prior_vec, problem,adaptive_update_params)

Constructs the return type of the resutls from the MCWH and PMCMC algorithm.
"""
function return_results(Theta,accept_vec,prior_vec, problem,adaptive_update_params)
  return Result(Theta, accept_vec, prior_vec)
end

```

    WARNING: replacing docs for 'abcmcmc :: Tuple{ProblemABCMCMC,Any,Any,Any,Any}' in module 'Main'.
    WARNING: replacing docs for 'indicator :: Tuple{Array{T,1} where T,Array{T,1} where T,Array{T,1} where T,Float64}' in module 'Main'.
    WARNING: replacing docs for 'return_results :: NTuple{5,Any}' in module 'Main'.

    return_results

### Case study - g-and.k distribution, again

We will now again consider the g-and-k distribution, but we now use the ABC-MCMC algorithm to compute the inference.

Function to set up the ABC-MCMC problem for the g-and-k distribution.

```julia
doc"""
    set_up_abcmcmc_problem_gk(use_sim_data::Bool=true;nbr_of_unknown_parameters::Int64=2,
  prior_dist::String = "Uniform", adaptiveon::Bool = true, ploton::Bool = false,
  nbr_of_cores::Int64 = 8, T::Int64 = 10000,x0::Float64 = 7.,
  print_interval::Int64 = 500, alg::String="abcmcmc", nbr_summary_stats::Int64=5,
  start::String = "random")

set_up_abcmcmc_problem sets the parameters for the problem defined by the inputs.

# Output
* `problem`: An instance of the type ProblemABCMCMC cointaining all information for the problem
"""
function set_up_abcmcmc_problem_gk(use_sim_data::Bool=true;nbr_of_unknown_parameters::Int64=2,
  prior_dist::String = "Uniform", adaptiveon::Bool = true, ploton::Bool = false,
  nbr_of_cores::Int64 = 8, T::Int64 = 5000,x0::Float64 = 7.,
  print_interval::Int64 = 500, alg::String="abcmcmc", nbr_summary_stats::Int64=5,
  start::String = "random")

  # set algorithm parameters
  theta_true = [3; 1; 2; .5]  # [A,B,g,k]
  theta_0 =  copy(theta_true)  # start at true values

  if start == "non-random"
    theta_0 = [2;2;2;2]
  end

  prior_parameters = [0 10; 0 10; 0 10; 0 10]
  theta_known = .8 # c

  eps = [30*ones(5000); 25*ones(5000); 20*ones(5000); 15*ones(5000); 10*ones(5000); 5*ones(5000); 2.5*ones(5000); 1*ones(5000); 0.3*ones(5000); 0.2*ones(50000)] # ; 0.05*ones(100000)

  # create instance of AlgorithmParametersABCMCMC (set parameters to default values)
  alg_param = AlgorithmParametersABCMCMC(length(eps),length(eps)-35000,alg,print_interval,nbr_summary_stats,eps,start,ones(5)) # hardcoded nbr of summary stats

  # create instance of ModelParameters, all theta paramters are on log-scale
  model_param = ModelParameters(theta_true,theta_known,theta_0)

  # set data
  if use_sim_data
    y = generate_data_gk(T, theta_true[1], theta_true[2], theta_true[3], theta_true[4], theta_known)
  end

  # create instance of Data
  data = Data(y)

  # create instance of PriorDistribution
  prior = PriorDistribution(prior_dist, prior_parameters)

  # create instance of AdaptiveUpdate
  adaptive_update = AMUpdate(eye(length(theta_0)), 2.4/sqrt(length(theta_0)), 1., 0.7, 50)

  # return the an instance of Problem
  return ProblemABCMCMC(data, alg_param, model_param, adaptive_update, prior)

end

```

    WARNING: replacing docs for 'set_up_abcmcmc_problem_gk :: Union{Tuple{Bool}, Tuple{}}' in module 'Main'.

    set_up_abcmcmc_problem_gk

Function to evaluate the prior.

```julia
function  evaluate_prior(theta_star::Vector, prior_parameters::Matrix, dist_type::String = "Uniform")

  # set start value for loglik
  log_likelihood = 0.

  if dist_type == "Uniform"
    for i = 1:length(theta_star)
      # Update loglik, i.e. add the loglik for each model paramter in theta
      log_likelihood = log_likelihood + log_unifpdf( theta_star[i], prior_parameters[i,1], prior_parameters[i,2] )
    end
  else
    # add other priors
  end

  return log_likelihood # return log_lik

end

# help function

doc"""
    log_unifpdf(x::Float64, a::Float64,b::Float64)

Computes log(unifpdf(x,a,b)).
"""
function log_unifpdf(x::Float64, a::Float64, b::Float64)

  if  x >= a && x<= b
    return -log(b-a);
  else
    return log(0);
  end

end

```

    WARNING: replacing docs for 'log_unifpdf :: Tuple{Float64,Float64,Float64}' in module 'Main'.

    log_unifpdf

Since we already specified the functions `sample_from_prior`, `evaluate_prior`, `generate_data`, and `calc_summary` for the g-and-k distribution we can now directly set up the problem. Here we set the sequence of $\epsilon$'s to start at a large value, and this value is then decreased at every 5000:th iteration until we reach the $\epsilon$ value that we want to use when collecting the values for the approximate posterior, in this case, $\epsilon = 0.2$. We also use an adaptive random walk proposal now.

```julia
problem = set_up_abcmcmc_problem_gk(ploton = true,
  start = "non-random", print_interval=50000);

# load data
problem.data.y = Array(CSV.read("data/gandk_data.csv", nullable=false))[:];

# set weigths
problem.alg_param.w  =  [0.22; 0.19; 0.53; 2.97; 1.90];

# run @eps=0.2
problem.alg_param.eps = [30*ones(5000); 25*ones(5000); 20*ones(5000); 15*ones(5000); 10*ones(5000); 5*ones(5000); 2.5*ones(5000); 1*ones(5000); 0.3*ones(5000); 0.2*ones(110000)];

problem.alg_param.burn_in = length(problem.alg_param.eps)-100000;
problem.alg_param.R = length(problem.alg_param.eps);
```

Run the ABC-MCMC algorithm. WARNING: This can take a few minutes to run.

```julia
# fix random numbers
srand(100);

res, X, Y, cov_prop_kernel = @time abcmcmc(problem, sample_from_prior, evaluate_prior, generate_data, calc_summary);
```

    Starting ABC-MCMC estimating 4 parameters
    Adaptation algorithm: AMUpdate
    Prior distribution: Uniform
    Iteration: 1
    Covariance:
    [1.44 0.0 0.0 0.0; 0.0 1.44 0.0 0.0; 0.0 0.0 1.44 0.0; 0.0 0.0 0.0 1.44]
    Start value:
    [2.0, 2.0, 2.0, 2.0]Percentage done: 32.26
    Acceptance rate on iteration 1 to 50000 is 0.1746
    Covariance:
    [0.00125403 0.000608318 -0.0348073 0.0013069; 0.000608318 0.00550366 0.0183142 0.000136405; -0.0348073 0.0183142 1.81946 -0.0472756; 0.0013069 0.000136405 -0.0472756 0.00856726]
    Percentage done: 64.52
    Acceptance rate on iteration 50001 to 100000 is 0.1023
    Covariance:
    [0.000798999 0.00123812 -0.00112941 -0.000344872; 0.00123812 0.0106433 0.0187522 -0.00213175; -0.00112941 0.0187522 0.0795797 0.0075236; -0.000344872 -0.00213175 0.0075236 0.0080143]
    Percentage done: 96.77
    Acceptance rate on iteration 100001 to 150000 is 0.1142
    Covariance:
    [0.000754935 0.00117772 -0.00167982 -0.000434249; 0.00117772 0.00905662 0.0158346 -0.000811657; -0.00167982 0.0158346 0.0799335 0.00892584; -0.000434249 -0.000811657 0.00892584 0.00672843]
    Ending ABC-MCMC with adaptive RW estimating 4 parameters
    Adaptation algorithm: AMUpdate
    Prior distribution: Uniform
    151.037127 seconds (55.39 M allocations: 16.388 GiB, 1.72% gc time)

Set values for obtained results.

```julia
Theta = res.Theta_est;
accept_vec = res.accept_vec;
prior_vec = res.prior_vec;
burn_in = problem.alg_param.burn_in;
prior_parameters = problem.prior_dist.prior_parameters;
theta_true = problem.model_param.theta_true;
```

Parameter estimations (posterior mean), and posterior quantile intervals, 2.5th and 97.5th quantiles in parenthesis.

```julia
# calc posterior mean
post_mean_abcmcmc = round.(mean(Theta[:,burn_in+1:end],2),3)

# calc quantiles
q_abcmcmc = round.([quantile(Theta[1,burn_in:end], [0.025 0.975])
    quantile(Theta[2,burn_in:end], [0.025 0.975])
    quantile(Theta[3,burn_in:end], [0.025 0.975])
    quantile(Theta[4,burn_in:end], [0.025 0.975])],3)

# create data frame
df_abcmcmc_param_est = DataFrame(parameter = ["A"; "B";"g";"k"], true_values = problem.model_param.theta_true, param_est  = ["$(post_mean_abcmcmc[1]) ($(q_abcmcmc[1,1]), $(q_abcmcmc[1,2]))"; "$(post_mean_abcmcmc[2]) ($(q_abcmcmc[2,1]), $(q_abcmcmc[2,2]))"; "$(q_abcmcmc[3]) ($(q_abcmcmc[3,1]), $(q_abcmcmc[3,2]))"; "$(post_mean_abcmcmc[4]) ($(q_abcmcmc[4,1]), $(q_abcmcmc[4,2]))"])
```

	parameter	true_values	param_est

1	A	3.0	3.093 (2.102, 5.122)

2	B	1.0	1.435 (0.454, 6.649)

3	g	2.0	1.591 (1.591, 9.849)

4	k	0.5	0.719 (0.202, 2.361)

Acceptance rate.

```julia
acceptance_rate = round(sum(accept_vec[burn_in:end])/length(accept_vec[burn_in:end]),4)
print("$(acceptance_rate*100) %")
```

    12.72 %

Plot chains.

```julia
# plot chains
PyPlot.figure(figsize=(10,8));
PyPlot.subplot(221);
PyPlot.plot(Theta[1,:]);
PyPlot.plot(ones(size(Theta,2),1)*problem.model_param.theta_true[1], "k");
PyPlot.ylabel(L"$A$");
PyPlot.subplot(222);
PyPlot.plot(Theta[2,:]);
PyPlot.plot(ones(size(Theta,2),1)*problem.model_param.theta_true[2], "k");
PyPlot.ylabel(L"$B$");
PyPlot.subplot(223);
PyPlot.plot(Theta[3,:]);
PyPlot.plot(ones(size(Theta,2),1)*problem.model_param.theta_true[3], "k");
PyPlot.ylabel(L"$g$");
PyPlot.xlabel(L"Iteration");
PyPlot.subplot(224);
PyPlot.plot(Theta[4,:]);
PyPlot.plot(ones(size(Theta,2),1)*problem.model_param.theta_true[4], "k");
PyPlot.xlabel(L"Iteration");
PyPlot.ylabel(L"$k$");
```

Plot approximate marginal posteriors.

```julia
# plot posterior dist

h1_abcmcmc = kde(Theta[1,burn_in:end]);
h2_abcmcmc = kde(Theta[2,burn_in:end]);
h3_abcmcmc = kde(Theta[3,burn_in:end]);
h4_abcmcmc = kde(Theta[4,burn_in:end]);

PyPlot.figure(figsize=(10,8));
subplot(221);
PyPlot.plot(h1_abcmcmc.x,h1_abcmcmc.density, "b");
PyPlot.plot(x_c1,priordens_c1, "g");
PyPlot.plot((problem.model_param.theta_true[1], problem.model_param.theta_true[1]), (0, maximum(h1_abcmcmc.density)), "k");
PyPlot.ylabel("Density");
PyPlot.xlabel(L"$A$");
axis([minimum(h1_abcmcmc.x), maximum(h1_abcmcmc.x), 0, maximum(h1_abcmcmc.density)+0.1]);
subplot(222);
PyPlot.plot(h2_abcmcmc.x,h2_abcmcmc.density, "b");
PyPlot.plot(x_c2,priordens_c2, "g");
PyPlot.plot((problem.model_param.theta_true[2], problem.model_param.theta_true[2]), (0, maximum(h2_abcmcmc.density)), "k");
PyPlot.xlabel(L"$B$")
axis([minimum(h2_abcmcmc.x), maximum(h2_abcmcmc.x), 0, maximum(h2_abcmcmc.density)+0.1]);
subplot(223);
PyPlot.plot(h3_abcmcmc.x,h3_abcmcmc.density, "b");
PyPlot.plot(x_c3,priordens_c3, "g");
PyPlot.plot((problem.model_param.theta_true[3], problem.model_param.theta_true[3]), (0, maximum(h3_abcmcmc.density)), "k");
PyPlot.ylabel("Density");
PyPlot.xlabel(L"$g$");
axis([minimum(h3_abcmcmc.x), maximum(h3_abcmcmc.x), 0, maximum(h3_abcmcmc.density)+0.1]);
subplot(224);
PyPlot.plot(h4_abcmcmc.x,h4_abcmcmc.density, "b");
PyPlot.plot(x_c4,priordens_c4, "g");
PyPlot.plot((problem.model_param.theta_true[4], problem.model_param.theta_true[4]), (0, maximum(h4_abcmcmc.density)), "k");
PyPlot.xlabel(L"$k$");
axis([minimum(h4_abcmcmc.x), maximum(h4_abcmcmc.x), 0, maximum(h4_abcmcmc.density)+0.1]);

```

####  Exact Bayesian inference for the g-and-k distribtuion

For the g-and-k distribution is the probability density function analytically unknown since the model is specified via the quantile function, and not the probability density function. However, the probability density function can be computed numerically by inverting the quantile function [ [13]](#rayner_02). Hence, the exact posterior can be computed using the numerically inverse of the quantile function (also see following [blog post](https://statisfaction.wordpress.com/2017/06/11/likelihood-calculation-for-the-g-and-k-distribution/) on the topic). We here utilize this approach to compute the exact posterior distribution for the g-and-k distribution.

We first set up the code necessary to numerically compute the probability density function for the g-and-k function. The code is inspired by, and has a similar structure as the R-package *gk* ([link to package](https://cran.r-project.org/web/packages/gk/index.html)) (see also [ [17]](#prangle_17_gk)).

Load Julia's root finding package.

```julia
using Roots # needed to inverte the quantile functon
```

Quantile function for the g-and-k distribution.

```julia
doc"""
    Q(z::Real,A::Real,B::Real,g::Real, k::Real, c::Real)

Quantile function for the g-and-k distribution.
"""
function Q(z::Real,A::Real,B::Real,g::Real, k::Real, c::Real)

  return A + B*(1 + c*(1-exp(-g*z))/(1+exp(-g*z)))*(1+z^2)^k*z

end
```

    WARNING: replacing docs for 'Q :: NTuple{6,Real}' in module 'Main'.

    Q

The derivative of the quantile function for the g-and-k distribution.

```julia
doc"""
    Qprime(z::Real,A::Real,B::Real,g::Real, k::Real, c::Real)

Derivitie of the quantile function for the g-and-k distribution.
"""
function Qprime(z::Real,A::Real,B::Real,g::Real, k::Real, c::Real)

  return B*(1+z^2)^k*R(z,g,k)

end

doc"""
    R(z::Real,g::Real, k::Real)

Help function for the Q' function
"""
function R(z::Real,g::Real, k::Real)
  return (1+c*tanh(g*z/2))*((1+(2*k+1)*z^2)/(1+z^2))+((c*g*z)/(2*cosh(g*z/2)^2))
end
```

    WARNING: replacing docs for 'Qprime :: NTuple{6,Real}' in module 'Main'.
    WARNING: replacing docs for 'R :: Tuple{Real,Real,Real}' in module 'Main'.

    R

The logarithm of the derivative of the quantile function for the g-and-k distribution.

```julia
doc"""
    logQprime(z::Real,A::Real,B::Real,g::Real, k::Real, c::Real)

Logarithm of the derivitie of the quantile function for the g-and-k distribution.
"""
function logQprime(z::Real,A::Real,B::Real,g::Real, k::Real, c::Real)

  return log(B)+k*log(1+z^2)+logR(z,g,k)

end

doc"""
    logR(z::Real,g::Real, k::Real)

Help function for the logarithm of the Q' function
"""
function logR(z::Real,g::Real, k::Real)
  return log(R(z,g,k))
end
```

    WARNING: replacing docs for 'logQprime :: NTuple{6,Real}' in module 'Main'.
    WARNING: replacing docs for 'logR :: Tuple{Real,Real,Real}' in module 'Main'.

    logR

The function to numerically evaluate the pdf function of the g-and-k distribution.

```julia
doc"""
    pdfgandk(x::Real, A::Real,B::Real,g::Real, k::Real, c::Real,logscale::Bool=true)

Numerical evaluating the pdf for the g-and-k distribution.
"""
function pdfgandk(x::Real, A::Real,B::Real,g::Real, k::Real, c::Real,logscale::Bool=true)

  # find z using rootfinder
  z = rootfinder(x,A,B,g,k,c)

  # calc pdf
  if !logscale
    return pdf(Normal(0,1), z)/Qprime(z,A,B,g,k,c)
  else
    return -0.5*log(2*pi) - 0.5*z^2  - logQprime(z,A,B,g,k,c)
  end

end

doc"""
    rootfinder(x::Real,A::Real,B::Real,g::Real, k::Real, c::Real)

Help function for pdfgandk.
"""
function rootfinder(x::Real,A::Real,B::Real,g::Real, k::Real, c::Real)

  f(z) = Q(z, A,B,g, k, c) - x
  z = fzero(f, -100, 100, no_pts=200)
  return z

end
```

    WARNING: replacing docs for 'pdfgandk :: Union{NTuple{6,Real}, Tuple{Real,Real,Real,Real,Real,Real,Bool}}' in module 'Main'.
    WARNING: replacing docs for 'rootfinder :: NTuple{6,Real}' in module 'Main'.

    rootfinder

Function for computing the (log-)likelihood for an entire data set.

```julia

doc"""
    pdfgandkdataset(y::Vector, A::Real,B::Real,g::Real, k::Real, c::Real,logscale::Bool=true)

Computes the (log)likelihood of the entire data set.
"""
function pdfgandkdataset(y::Vector, A::Real,B::Real,g::Real, k::Real, c::Real,logscale::Bool=true)

  if !logscale

    likelihood = 0.0

    for i = 1:length(y)
      likelihood = likelihood*pdfgandk(y[i], A,B,g, k, c,logscale)
    end

    return likelihood

  else

    loglikelihood = 0.0

    for i = 1:length(y)
      loglikelihood = loglikelihood + pdfgandk(y[i], A,B,g, k, c)
    end

    return loglikelihood

  end
end
```

    WARNING: replacing docs for 'pdfgandkdataset :: Union{Tuple{Array{T,1} where T,Real,Real,Real,Real,Real,Bool}, Tuple{Array{T,1} where T,Real,Real,Real,Real,Real}}' in module 'Main'.

    pdfgandkdataset

We can now compare the kernel density estimation of the pdf (blue line) to the numerical pdf (red dashed line).

```julia
h1 = kde(problem.data.y);

x = linspace(minimum(problem.data.y), maximum(problem.data.y), 100);

# set parameters
(A,B,g, k) = problem.model_param.theta_true
c = problem.model_param.theta_known

pdf_vec = zeros(length(x));

for i = 1:length(x)
  pdf_vec[i] = pdfgandk(x[i], A,B,g, k, c, false)
end

# plot simulated data
PyPlot.figure(figsize=(10,4));
subplot(121);
PyPlot.plot(h1.x,h1.density);
PyPlot.plot(x,pdf_vec, "r--");
PyPlot.ylabel("Probability");
PyPlot.xlabel("Data");

```

We use an adaptive MH algorithm to estiamte the parameters for the g-and-k distribution.

```julia
doc"""
    adaptiveMH(y::Vector, nbr_iter::Int, adaptive_update, θ_0::Vector, c::Float64, print_interval::Int=100)

Runs the adaptive Metropolis-Hastings algorithm.
"""
function adaptiveMH(y::Vector, nbr_iter::Int, adaptive_update, θ_0::Vector, c::Float64, print_interval::Int=1000)

  # pre-allocate matrices
  chain = zeros(length(θ_0), nbr_iter)
  loglik_vec = zeros(nbr_iter)
  accept_vec = zeros(nbr_iter)

  # set start values
  chain[:,1] = θ_0
  loglik_vec[1] = pdfgandkdataset(y,chain[1,1],chain[2,1],chain[3,1],chain[4,1],c)

  adaptive_update_params = set_adaptive_alg_params(adaptive_update, length(θ_0),chain[:,1], nbr_iter)

  # print start
  @printf "Starting adaptive Metropolis-Hastings\n"

  for i = 2:nbr_iter

    # print info
    if mod(i-1,print_interval) == 0
      # print progress
      @printf "Percentage done: %.2f\n" 100*(i-1)/nbr_iter
      # print current acceptance rate
      @printf "Acceptance rate on iteration %d to %d is %.4f\n" i-print_interval i-1  sum(accept_vec[i-print_interval:i-1])/( i-1 - (i-print_interval) )
      @printf "Covariance:\n"
      print_covariance(adaptive_update,adaptive_update_params, i)
      # print loglik
      @printf "Loglik: %.4f \n" loglik_vec[i-1]

    end

    # random walk proposal
    # θ_proposal = chain[:,i-1] + rand(Normal(0,1),length(θ_0))*σ_mh

    # Gaussian random walk
    (θ_proposal, ) = gaussian_random_walk(problem.adaptive_update, adaptive_update_params, chain[:,i-1], i)

    # loglik for proposal
    loglik_proposal = pdfgandkdataset(y,θ_proposal[1,1],θ_proposal[2,1],θ_proposal[3,1],θ_proposal[4,1],c)

    # compute logarithm of accaptance probability
    α_log = loglik_proposal + log_prior(θ_proposal) - (pdfgandkdataset(y,chain[1,i-1],chain[2,i-1],chain[3,i-1],chain[4,i-1],c) + log_prior(chain[:,i-1]))

    # generate log random number
    u_log = log(rand())

    # compute accaptance decision
    accept = u_log < α_log

    # update chain
    if accept
      chain[:,i] = θ_proposal
      loglik_vec[i] = loglik_proposal
      accept_vec[i] = 1
    else
      chain[:,i] = chain[:,i-1]
      loglik_vec[i] = loglik_vec[i-1]
    end

    adaptation(adaptive_update, adaptive_update_params, chain, i, α_log)

  end

  # print info
  @printf "Ending Metropolis-Hastings\n"
  return chain, loglik_vec, accept_vec

end

# help functions for adaptiveMH

function log_prior(θ::Vector)

  loglik = 0.0
  for i = 1:length(θ)
    loglik = loglik + log_unifpdf( θ[i],0,10)
  end

  return loglik

end

function log_unifpdf(x::Real, a::Real, b::Real)

  if  x >= a && x<= b
    return -log(b-a);
  else
    return log(0);
  end

end

```

    WARNING: replacing docs for 'adaptiveMH :: Union{Tuple{Array{T,1} where T,Int64,Any,Array{T,1} where T,Float64,Int64}, Tuple{Array{T,1} where T,Int64,Any,Array{T,1} where T,Float64}}' in module 'Main'.

    log_unifpdf (generic function with 2 methods)

We can now run the adaptive MH algorithm. WARNING this can take up to 20 minutes to run.

```julia
nbr_iter = 10000; # nbr iterations
burn_in = 2000; # burn-in
θ_0 =  [5;5;3; 2.]; # start values

adaptive_update = AMUpdate_gen(eye(4), 2.4/sqrt(4), 0.2, 1., 0.8, 25);

# fix random numbers
srand(100);

chain, loglik_vec, accept_vec = @time adaptiveMH(problem.data.y, nbr_iter, adaptive_update, θ_0, c);

```

    Starting adaptive Metropolis-Hastings
    Percentage done: 10.00
    Acceptance rate on iteration 1 to 1000 is 0.2132
    Covariance:
    [0.0286021 0.0678645 -0.00137465 -0.0134885; 0.0678645 0.180363 0.0194115 -0.0286241; -0.00137465 0.0194115 0.0446497 0.00678554; -0.0134885 -0.0286241 0.00678554 0.00752407]
    Loglik: -8081.5449
    Percentage done: 20.00
    Acceptance rate on iteration 1001 to 2000 is 0.2893
    Covariance:
    [0.0036309 0.00713424 -0.00271986 -0.00178273; 0.00713424 0.0189985 0.00247484 -0.00382074; -0.00271986 0.00247484 0.0192257 0.00139743; -0.00178273 -0.00382074 0.00139743 0.00165354]
    Loglik: -8079.0901
    Percentage done: 30.00
    Acceptance rate on iteration 2001 to 3000 is 0.3864
    Covariance:
    [0.0021893 0.00377419 -0.00150441 -0.00129993; 0.00377419 0.0101693 0.00259232 -0.00301878; -0.00150441 0.00259232 0.0143274 0.00057393; -0.00129993 -0.00301878 0.00057393 0.00176295]
    Loglik: -8077.2030
    Percentage done: 40.00
    Acceptance rate on iteration 3001 to 4000 is 0.3183
    Covariance:
    [0.00263064 0.00436083 -0.00223914 -0.00189332; 0.00436083 0.0109555 0.00141283 -0.00449369; -0.00223914 0.00141283 0.0168298 0.00125818; -0.00189332 -0.00449369 0.00125818 0.00306527]
    Loglik: -8073.8566
    Percentage done: 50.00
    Acceptance rate on iteration 4001 to 5000 is 0.3403
    Covariance:
    [0.00345172 0.00521678 -0.00317281 -0.00232357; 0.00521678 0.013183 0.00223891 -0.00556962; -0.00317281 0.00223891 0.0219801 0.00136274; -0.00232357 -0.00556962 0.00136274 0.00379815]
    Loglik: -8075.2644
    Percentage done: 60.00
    Acceptance rate on iteration 5001 to 6000 is 0.2452
    Covariance:
    [0.00294326 0.00478683 -0.00223618 -0.00224363; 0.00478683 0.0132222 0.00391751 -0.0056959; -0.00223618 0.00391751 0.0258437 0.00167884; -0.00224363 -0.0056959 0.00167884 0.00423653]
    Loglik: -8074.7781
    Percentage done: 70.00
    Acceptance rate on iteration 6001 to 7000 is 0.2733
    Covariance:
    [0.00382108 0.00654519 -0.00233709 -0.00296993; 0.00654519 0.0172309 0.00501942 -0.00725691; -0.00233709 0.00501942 0.0292049 0.00113818; -0.00296993 -0.00725691 0.00113818 0.0047333]
    Loglik: -8076.5891
    Percentage done: 80.00
    Acceptance rate on iteration 7001 to 8000 is 0.2362
    Covariance:
    [0.00374904 0.00574275 -0.00324858 -0.00258958; 0.00574275 0.0152153 0.00411057 -0.00624365; -0.00324858 0.00411057 0.0286116 0.00177363; -0.00258958 -0.00624365 0.00177363 0.0043325]
    Loglik: -8075.5514
    Percentage done: 90.00
    Acceptance rate on iteration 8001 to 9000 is 0.2533
    Covariance:
    [0.00388085 0.00612649 -0.00289451 -0.00290764; 0.00612649 0.0158392 0.00357071 -0.00678899; -0.00289451 0.00357071 0.0272574 0.00220132; -0.00290764 -0.00678899 0.00220132 0.00488618]
    Loglik: -8076.2213
    Ending Metropolis-Hastings
    1406.076733 seconds (5.20 G allocations: 166.922 GiB, 3.31% gc time)

Parameter estimations (posterior mean), and posterior quantile intervals, 2.5th and 97.5th quantiles in parenthesis.

```julia
posterior_samples = chain[:,burn_in:end] # set posterior samples

# calc posterior mean
post_mean_mh = round.(mean(posterior_samples,2),3)

# calc posterior quantiles
q = round.([quantile(posterior_samples[1,:], [0.025 0.975])
            quantile(posterior_samples[2,:], [0.025 0.975])
            quantile(posterior_samples[3,:], [0.025 0.975])
            quantile(posterior_samples[4,:], [0.025 0.975])],3)

# create data frame
df_mcmc_param_est = DataFrame(parameter = ["A"; "B";"g";"k"], true_values = problem.model_param.theta_true, param_est  = ["$(post_mean_mh[1]) ($(q[1,1]), $(q[1,2]))"; "$(post_mean_mh[2]) ($(q[2,1]), $(q[2,2]))"; "$(post_mean_mh[3]) ($(q[3,1]), $(q[3,2]))"; ; "$(post_mean_mh[4]) ($(q[4,1]), $(q[4,2]))"])

```

	parameter	true_values	param_est

1	A	3.0	3.019 (2.986, 3.052)

2	B	1.0	1.022 (0.957, 1.09)

3	g	2.0	1.994 (1.91, 2.09)

4	k	0.5	0.494 (0.459, 0.531)

Acceptance rate.

```julia
acceptance_rate = round.(sum(accept_vec[burn_in:end])/length(accept_vec[burn_in:end]),2)
print("$(acceptance_rate*100) %")
```

    28.999999999999996 %

Plot chains.

```julia
PyPlot.figure(figsize=(10,8));
PyPlot.subplot(221);
PyPlot.plot(chain[1,:]);
PyPlot.plot(ones(size(chain,2),1)*problem.model_param.theta_true[1], "k");
PyPlot.ylabel(L"$A$");
PyPlot.subplot(222);
PyPlot.plot(chain[2,:]);
PyPlot.plot(ones(size(chain,2),1)*problem.model_param.theta_true[2], "k");
PyPlot.ylabel(L"$B$");
PyPlot.subplot(223);
PyPlot.plot(chain[3,:]);
PyPlot.plot(ones(size(chain,2),1)*problem.model_param.theta_true[3], "k");
PyPlot.ylabel(L"$g$");
PyPlot.xlabel(L"Iteration");
PyPlot.subplot(224);
PyPlot.plot(chain[4,:]);
PyPlot.plot(ones(size(chain,2),1)*problem.model_param.theta_true[4], "k");
PyPlot.xlabel(L"Iteration");
PyPlot.ylabel(L"$k$");

```

Plot posterior.

```julia
h1_mcmc = kde(chain[1,burn_in:end]);
h2_mcmc = kde(chain[2,burn_in:end]);
h3_mcmc = kde(chain[3,burn_in:end]);
h4_mcmc = kde(chain[4,burn_in:end]);

PyPlot.figure(figsize=(10,8));
subplot(221);
PyPlot.plot(h1_mcmc.x,h1_mcmc.density, "b");
PyPlot.plot(x_c1,priordens_c1, "g");
PyPlot.plot((problem.model_param.theta_true[1], problem.model_param.theta_true[1]), (0, maximum(h1_mcmc.density)), "k");
PyPlot.ylabel("Density");
PyPlot.xlabel(L"$A$");
axis([minimum(h1_mcmc.x), maximum(h1_mcmc.x), 0, maximum(h1_mcmc.density)+0.1]);
subplot(222);
PyPlot.plot(h2_mcmc.x,h2_mcmc.density, "b");
PyPlot.plot(x_c2,priordens_c2, "g");
PyPlot.plot((problem.model_param.theta_true[2], problem.model_param.theta_true[2]), (0, maximum(h2_mcmc.density)), "k");
PyPlot.xlabel(L"$B$");
axis([minimum(h2_mcmc.x), maximum(h2_mcmc.x), 0, maximum(h2_mcmc.density)+0.1]);
subplot(223);
PyPlot.plot(h3_mcmc.x,h3_mcmc.density, "b");
PyPlot.plot(x_c3,priordens_c3, "g");
PyPlot.plot((problem.model_param.theta_true[3], problem.model_param.theta_true[3]), (0, maximum(h3_mcmc.density)), "k");
PyPlot.ylabel("Density");
PyPlot.xlabel(L"$g$");
axis([minimum(h3_mcmc.x), maximum(h3_mcmc.x), 0, maximum(h3_mcmc.density)+0.1]);
subplot(224);
PyPlot.plot(h4_mcmc.x,h4_mcmc.density, "b");
PyPlot.plot(x_c4,priordens_c4, "g");
PyPlot.plot((problem.model_param.theta_true[4], problem.model_param.theta_true[4]), (0, maximum(h4_mcmc.density)), "k");
PyPlot.xlabel(L"$k$");
axis([minimum(h4_mcmc.x), maximum(h4_mcmc.x), 0, maximum(h4_mcmc.density)+0.1]);

```

####  Comparing inference results for the g-and-k distribution

Posterior for ABC rejection sampling (dashed blue line), ABC-MCMC (solid blue line), and MH (red line).

```julia
PyPlot.figure(figsize=(10,8));
subplot(221);
PyPlot.plot(h1_abc_reject.x,h1_abc_reject.density, "b--");
PyPlot.plot(h1_abcmcmc.x,h1_abcmcmc.density, "b");
PyPlot.plot(h1_mcmc.x,h1_mcmc.density, "r");
PyPlot.plot(x_c1,priordens_c1, "g");
PyPlot.plot((problem.model_param.theta_true[1], problem.model_param.theta_true[1]), (0, maximum(h1_mcmc.density)), "k");
axis([minimum(h1_abc_reject.x), maximum(h1_abc_reject.x), 0, maximum(h1_mcmc.density)+0.5]);
PyPlot.ylabel("Density");
PyPlot.xlabel(L"$A$");
subplot(222);
PyPlot.plot(h2_abc_reject.x,h2_abc_reject.density, "b--");
PyPlot.plot(h2_abcmcmc.x,h2_abcmcmc.density, "b");
PyPlot.plot(h2_mcmc.x,h2_mcmc.density, "r");
PyPlot.plot(x_c2,priordens_c2, "g");
PyPlot.plot((problem.model_param.theta_true[2], problem.model_param.theta_true[2]), (0, maximum(h2_mcmc.density)), "k");
axis([minimum(h2_abc_reject.x), maximum(h2_abc_reject.x), 0, maximum(h2_mcmc.density)+0.5]);
PyPlot.xlabel(L"$B$");
subplot(223);
PyPlot.plot(h3_abc_reject.x,h3_abc_reject.density, "b--");
PyPlot.plot(h3_abcmcmc.x,h3_abcmcmc.density, "b");
PyPlot.plot(h3_mcmc.x,h3_mcmc.density, "r");
PyPlot.plot(x_c3,priordens_c3, "g");
PyPlot.plot((problem.model_param.theta_true[3], problem.model_param.theta_true[3]), (0, maximum(h3_mcmc.density)), "k");
axis([minimum(h3_abc_reject.x), maximum(h3_abc_reject.x), 0, maximum(h3_mcmc.density)+0.5]);
PyPlot.ylabel("Density");
PyPlot.xlabel(L"$g$");
subplot(224);
PyPlot.plot(h4_abc_reject.x,h4_abc_reject.density, "b--");
PyPlot.plot(h4_abcmcmc.x,h4_abcmcmc.density, "b");
PyPlot.plot(h4_mcmc.x,h4_mcmc.density, "r");
PyPlot.plot(x_c4,priordens_c4, "g");
PyPlot.plot((problem.model_param.theta_true[4], problem.model_param.theta_true[4]), (0, maximum(h4_mcmc.density)), "k");
PyPlot.xlabel(L"$k$");
axis([minimum(h4_abc_reject.x), maximum(h4_abc_reject.x), 0, maximum(h4_mcmc.density)+0.5]);

```

Compare parameter estimations obtained from ABC rejection sampling, ABC-MCMC, and MH.

```julia
df_param_est = DataFrame(parameter = ["A"; "B";"g"; "k"], true_values = problem.model_param.theta_true, ABC_rs = df_abcrs_param_est[:,3], ABC_MCMC = df_abcmcmc_param_est[:,3], MH = df_mcmc_param_est[:,3])
```

	parameter	true_values	ABC_rs	ABC_MCMC	MH

1	A	3.0	2.952 (2.535, 3.257)	3.093 (2.102, 5.122)	3.019 (2.986, 3.052)

2	B	1.0	1.194 (0.1, 2.745)	1.435 (0.454, 6.649)	1.022 (0.957, 1.09)

3	g	2.0	5.281 (0.382, 9.871)	1.591 (1.591, 9.849)	1.994 (1.91, 2.09)

4	k	0.5	0.647 (0.013, 1.375)	0.719 (0.202, 2.361)	0.494 (0.459, 0.531)

We can conclude that the parameter estimations computed using the ABC-MCMC algorithm are much better compared to the estimates obtained using the ABC rejection sampling algorithm since the ABC-MCMC algorithm allows us to capture all parameters. The posterior distribution obtained using the ABC-MCMC algorithm is also much more informative compared to the posterior distribution obtained from the ABC rejection sampling algorithm.

The ABC-MCMC algorithm produces better inference results since the proposal distribution changes during the algorithm and hence allows us to use a smaller $\epsilon$ threshold while still obtaining a reasonable high acceptance rate. For the ABC rejection sampling algorithm is the proposal distribution during the entire algorithm the prior distribution and we, therefore, must use a large $\epsilon$ to get any accepted proposals at all.

The posterior obtain for the ABC-MCMC algorithm is also quite similar to the posterior obtain for the MCMC algorithm. However, the approximative posterior produced by the ABC-MCMC algorithm is still a conservative estimation of the posterior distribution, in particular in comparison with the true posterior distribution computed using the MH algorithm.

## Particle Markov chain Monte Carlo

The particle Markov chain Monte Carlo method (also denoted as pseudo-marginal Markov chain Monte Carlo) is an algorithm where Markov chain Monte Carlo methods are mixed with sequential Monte Carlo methods (i.e., particle filters). The idea is to use a particle filter to compute an unbiased estimator of the likelihood $p(y | \theta)$ and plug this estimator into the usual Metropolis-Hastings updating scheme. It has been shown that this strategy indeed results in a valid Markov chain Monte Carlo method, and the PMCMC method is therefore a sound method (paper where the the properties of the unbiased estimator is discussed  [ [3]](#ref_andrieu_et_al_09), paper discussing the PMCMC applied to state-space models  [[4]](#ref_andrieu_et_al_10)). Two excellent blog posts where the PMCMC algorithm is introduced  can be found [here](https://darrenjw.wordpress.com/2011/05/15/mcmc-monte-carlo-likelihood-estimation-and-the-bootstrap-particle-filter/) and [here](https://darrenjw.wordpress.com/2010/09/20/the-pseudo-marginal-approach-to-exact-approximate-mcmc-algorithms/).

We will use the PMCMC to estimate the parameters for a state-space model, and we will therefore briefly discuss how to compute the unbiased estimaton of the likelihood $p(y | \theta)$ in the state-space setting. A state-space model can be written as

\begin{equation*}
\begin{cases}
y_t\sim p(y_t | x_t;\theta_y), \\
x_t\sim p(x_t | x_s,\theta_x),\quad x_0\sim p(x_0),\quad t_0\leq s<t.
\end{cases}
\end{equation*}

Where $x_0$ is the initial state of the system. The (unknown) parameters that we are interested in estimating are $\theta = [\theta_y, \theta_x]$. The likelihood function for the state-space model can be written as

\begin{equation*}
p(y_{1:T}|\theta)=p(y_1|\theta)\prod_{t=2}^Tp(y_t | y_{1:t-1};\theta).
\end{equation*}

Where each of the partial likelihoods can be computed as

\begin{equation*}
p(y_t|y_{1:t-1};\theta) = \int p(y_t|x_t;\theta)p(x_t|y_{1:t-1};\theta)dx_t.
\end{equation*}

This integral is a high-dimensional integral that is tricky to evaluate. However, the integral can be approximated by drawing $N$ particles $x_t^n\sim p(x_t|y_{1:t-1};\cdot)$, and then compute the sample average over these particles

\begin{equation*}
\tilde{p}(y_t|y_{1:t-1};\theta) =  \sum_{n=1}^N p(y_t|x_t^n;\cdot)/N.
\end{equation*}

The entire likelihood can then be estimated by combining the Monte Carlo estimations of each partial likelihood. We will use the bootstrap particle filter  [[8]](#ref_gordon_et_al_93) to estimate the likelihood. The pseudo-code for the bootstrap particle filter is,

At iteration $i$

1. *Re-sampling:* Re-sample $N$ times with replacement from $(x_{t-1}^{1},...,x_{t-1}^{N})$ with associated probabilities $(\tilde{w}_{t-1}^{1},...,\tilde{w}_{t-1}^{N})$ to obtain a new sample $(\tilde{x}_{t-1}^{1},...,\tilde{x}_{t-1}^{N})$.
2. *Propagate particles:* Propagate particles ${x}^{n}_{t} \sim p( \, \cdot \mid \tilde{x}^{n}_{t-1})$.
3. *Evaluate importance weigths:* Evaluate importance weights $w_t^{n} = p(y_t \mid {x}^{n}_t)$.
4. *Estiamte partial likelihood:*  $\hat{p}(y_t \mid y_{1:t-1}; \theta) = \frac{\sum_{n = 1}^{N}w_{t}^{n}}{N}$.
5. *Normalize importance weigths:* $\tilde{w}_t^{n} = \frac{w_t^{n}}{\sum_{n = 1}^{N} w_t^{n}}$.

After estimating all the partial likelihoods, we estimate the likelihood as

\begin{equation*}
\tilde{p}(y |\theta) =  \hat{p}(y_1  \mid \theta) \prod_{t = 2}^{T} \hat{p}(y_t \mid y_{1:t-1}; \theta).
\end{equation*}

###   Case study - Ricker model
The Ricker model is used in ecology to describe how the size of a population varies in time and follows

\begin{align}
\begin{cases}
y_{t+1}\sim \mathcal{P}(\phi x_{t+1}),\\
x_{t+1}= r x_t e^{-x_t + \epsilon_t}, \, \epsilon_t \overset{iid}{\sim}  \mathcal{N}(0,\sigma), %\sim_{iid}
\end{cases}
\end{align}

where $\mathcal{P}(\lambda)$ is the  Poisson distribution with mean $\lambda$.
The $\{x_t\}$ process is a latent (i.e. unobservable) Markov process and realizations from the observable process $\{y_t\}$ are conditionally independent given the latent states, since the $\epsilon_t$ are assumed independent. Even though the model is fairly simple is its dynamics highly non-linear and close to chaotic for some choice of the parameter values [[19]](#wood_10).

The inference problem for the Ricker model is non-trivial since the likelihood is intractable for some combinations of parameter values, and we will therefore use the PMCMC algorithm to estimate the parameters of the Ricker model. For an overview of other inference methods for the Ricker model, and detailed discussion on the properties of the likelihood function of the Ricker model see [[7]](#ref_fasiolo_et_al_16).

We first set up some functions that we need to run the PMCMC algorithm for the Ricker model.

Quit kernel.

```julia
quit()
```

Start kernel.

```julia
2+2
```

    4

Load packages.

```julia
using PyPlot # for plotting
using Distributions # function for variuse distributions
using StatsBase # simple stats functions
using KernelDensity # kernel density estimation
using DataFrames # dataframe functionalities
using CSV # read data
```

    WARNING: Method definition ==(Base.Nullable{S}, Base.Nullable{T}) in module Base at nullable.jl:238 overwritten in module NullableArrays at C:\Users\samuel\.julia\v0.6\NullableArrays\src\operators.jl:99.

Load adaptive updating algorithms.

```julia
include("adaptiveupdate.jl")
```

    adaptation (generic function with 3 methods)

Types for the different part of the problem.

```julia
"Type for prior distribution"
type PriorDistribution
  dist::String
  prior_parameters::Array{Float64}
end

"Type for the data"
type Data
  y::Array{Float64}
end

"Pararameters for the model"
type ModelParameters
  theta_true::Array{Float64} # [log(r) log(phi) log(sigma)]
  theta_known::Float64 # NaN
  theta_0::Array{Float64} # [log(r_0) log(phi_0) log(sigma_0)]
end

"Type for algorithm parameters for PMCMC"
type AlgorithmParameters
  R::Int64
  N::Int64
  burn_in::Int64
  alg::String
  pf_alg::String
  print_interval::Int64
end

"Type for the problem (including algorithm parameters) for the PMCMC algorithm"
type Problem
  data::Data
  alg_param::AlgorithmParameters
  model_param::ModelParameters
  adaptive_update::AdaptationAlgorithm
  prior_dist::PriorDistribution
end

"Type for the results"
type Result
  Theta_est::Array{Float64}
  loglik_est::Array{Float64}
  accept_vec::Array{Float64}
  prior_vec::Array{Float64}
end
```

    Result

Function to generate data from the Ricker model.

```julia
doc"""
    generate_data(T::Int65=50,r::Float64,phi::Float64,sigma::Float64,x0::Float64,ploton::Bool)

Generates data from the Ricker model.
"""
function generate_data(T::Int64,r::Float64,phi::Float64,sigma::Float64,x0::Float64=7.0,ploton::Bool=false)

  e = rand(Normal(0,sigma),T)
  y = zeros(T)
  x = zeros(T)

  # first iteration

  x[1] = r*x0*exp(-x0+e[1])

  y[1] = rand(Poisson(phi*x[1]))

  @simd for t = 2:T
    @inbounds x[t] = r*x[t-1]*exp(-x[t-1]+e[t])
    y[t] = rand(Poisson(phi*x[t]))
  end

  return y
end

```

    generate_data

Set up function for the Ricker model.

```julia
doc"""
    set_up_problem(use_sim_data::Bool=true;nbr_of_unknown_parameters::Int64=2,
  prior_dist::String = "Uniform", adaptiveon::Bool = true, ploton::Bool = false,
  nbr_of_cores::Int64 = 8, pf_algorithm::String = "bootstrap", T::Int64 = 50,x0::Float64 = 7.,
  print_interval::Int64 = 500, alg::String="PMCMC")

set_up_problem sets the parameters for the problem defined by the inputs.

# Output
* `problem`: An instance of the type Problem cointaining all information for the problem
"""
function set_up_problem(use_sim_data::Bool=true;nbr_of_unknown_parameters::Int64=2,
  prior_dist::String = "Uniform", adaptiveon::Bool = true, ploton::Bool = false,
  nbr_of_cores::Int64 = 8, pf_algorithm::String = "bootstrap", T::Int64 = 50,x0::Float64 = 7.,
  print_interval::Int64 = 500, alg::String="PMCMC")

  # set algorithm parameters
  theta_true = log.([44.7; 10; 0.3])
  theta_0 =  log.([3;3;10])
  prior_parameters = [0 10; 0 4;-10 1]
  theta_known = NaN

  # create instance of AlgorithmParameters (set parameters to default values)
  alg_param = AlgorithmParameters(10000,500,5000,alg,pf_algorithm,print_interval)

  # create instance of ModelParameters, all theta paramters are on log-scale
  model_param = ModelParameters(theta_true,theta_known,theta_0)

  # set data
  if use_sim_data
    y = generate_data(T, exp(theta_true[1]),exp(theta_true[2]),exp(theta_true[3]),x0,ploton)
  end

  # create instance of Data
  data = Data(y)

  # create instance of PriorDistribution
  prior = PriorDistribution(prior_dist, prior_parameters)

  # create instance of AdaptiveUpdate
  adaptive_update = AMUpdate(eye(length(theta_0)), 2.4/sqrt(length(theta_0)), 1., 0.7, 50)

  # return the an instance of Problem
  return Problem(data, alg_param, model_param, adaptive_update, prior)

end
```

    set_up_problem

The particle filter.

```julia
doc"""
    pf(y::Array{Float64}, theta::Array{Float64},theta_known::Float64,N::Int64,plotflag::Bool=false)

pf runs the bootstrap particle filter for the Ricker model and computes an unbiased
estimation of the loglikelihood function.
"""
function pf(y::Array{Float64}, theta::Array{Float64},theta_known::Float64,N::Int64,
plotflag::Bool=false)

  # set parameter values
  r = exp(theta[1])
  phi = exp(theta[2])
  sigma = exp(theta[3])

  # set startvalue for loglik
  loglik = 0.

  # set length pf data
  T = length(y)

  # pre-allocate matriceis
  x = zeros(N,T) # particels
  w = zeros(N,T) # weigts

  # set start values
  xint = rand(Uniform(1,30),N,1)
  #xint = rand(Uniform(1,200),N,1)

  #x_anc[:,1] = xint # set anc particels for t = 1

  # set gaussian noise
  e = rand(Normal(0,sigma), N,T)

  for t = 1:T

    if t == 1 # first iteration

      # propagate particels
      x[:,1] = r*xint.*exp.(-xint .+ e[:,1]);

      # calc weigths and update loglik
      (w[:,t], loglik) = calc_weigths(y[t],x[:,t],phi,loglik,N)

    else

      # resample particels
      ind = stratresample(w[:,t-1], N)
      x_resample = x[ind,t-1]

      # propagate particels
      x[:,t] = r*x_resample.*exp.(-x_resample .+ e[:,t])

      # calc weigths and update loglik
      (w[:,t], loglik) = calc_weigths(y[t],x[:,t],phi,loglik,N)
    end

  end

  if plotflag # plot ESS at last iteration
    @printf "ESS: %.4f\n" 1/sum(w[:,end].^2)
  end

  # return loglik
  return loglik
end

# help functions

doc"""
    calc_weigths(y::Array{Float64},x::Array{Float64},phi::Float64,loglik::Float64,N::Int64)

Calculates the weigths in the particel filter and the estiamtes the loglikelihood value.
"""
function calc_weigths(y::Float64,x::Array{Float64},phi::Float64,loglik::Float64,N::Int64)
  logweigths = y*log.(x.*phi)  .- x*phi # compute logweigths
  constant = maximum(logweigths) # find largets wegith
  weigths = exp.(logweigths - constant) # subtract largets weigth and compute weigths
  loglik =  loglik + constant + log(sum(weigths)) - log(N) # update loglik
  return weigths/sum(weigths), loglik
end

doc"""
    stratresample(p , N)

Stratified resampling.

Sample N times with repetitions from a distribution on [1:length(p)] with probabilities p. See [link](http://www.cornebise.com/julien/publis/isba2012-slides.pdf).
"""
function stratresample(p , N)

  p = p/sum(p)  # normalize, just in case...

  cdf_approx = cumsum(p)
  cdf_approx[end] = 1
  #I = zeros(N,1)
  indx = zeros(Int64, N)
  U = rand(N,1)
  U = U/N + (0:(N - 1))/N
  index = 1
  for k = 1:N
    while (U[k] > cdf_approx[index])
      index = index + 1
    end
    indx[k] = index
  end

  return indx

end

```

    stratresample

PMCMC algorithm.

```julia
doc"""
    MCMC(problem::Problem, store_data::Bool=false, return_cov_matrix::Bool=false)

Runs the particle Markov chain Monte Carlo algorithm.
"""
function MCMC(problem::Problem, store_data::Bool=false, return_cov_matrix::Bool=false) # this function should be merged with the generate_training_test_data function!

  # data
  y = problem.data.y

  # algorithm parameters
  R = problem.alg_param.R # number of iterations
  N = problem.alg_param.N # number of particels
  burn_in = problem.alg_param.burn_in # burn in
  alg = problem.alg_param.alg # use PMCMC or MCWM
  pf_alg = problem.alg_param.pf_alg # pf algorithm bootsrap of apf
  print_interval = problem.alg_param.print_interval # print accaptance rate and covarince function ever print_interval:th iteration
  loglik_star = zeros(Float64)

  # model parameters
  theta_true = problem.model_param.theta_true # [log(r) log(phi) log(sigma)]
  theta_known = problem.model_param.theta_known # NaN
  theta_0 = problem.model_param.theta_0 # [log(r_0) log(phi_0) log(sigma_0)]

  # pre-allocate matricies and vectors
  Theta = zeros(length(theta_0),R)
  loglik = zeros(R)
  accept_vec = zeros(R)
  prior_vec = zeros(R)
  theta_star = zeros(length(theta_0),1)

  if store_data
    Theta_val = zeros(length(theta_0),R-burn_in)
    loglik_val = zeros(R-burn_in)
  end

  # draw u's for checking if u < a
  u_log = log.(rand(R))
  a_log = 0

  # parameters for adaptive update
  adaptive_update_params = set_adaptive_alg_params(problem.adaptive_update, length(theta_0),Theta[:,1], R)

  # parameters for prior dist
  dist_type = problem.prior_dist.dist
  prior_parameters = problem.prior_dist.prior_parameters

  # print information at start of algorithm
  @printf "Starting PMCMC with adaptive RW estimating %d parameters\n" length(theta_true)
  @printf "MCMC algorithm: %s\n" alg
  @printf "Adaptation algorithm: %s\n" typeof(problem.adaptive_update)
  @printf "Prior distribution: %s\n" problem.prior_dist.dist
  @printf "Particel filter: %s\n" pf_alg

  # first iteration
  @printf "Iteration: %d\n" 1
  @printf "Covariance:\n"
  print_covariance(problem.adaptive_update,adaptive_update_params, 1)

  Theta[:,1] = theta_0

  if pf_alg == "apf"
    error("The auxiliary particle filter is not implemented")
  elseif pf_alg == "bootstrap"
    loglik[1] = pf(y, Theta[:,1],theta_known,N,true)
  end

  # print start loglik
  @printf "Loglik: %.4f \n" loglik[1]

  for r = 2:R

    # set print_on to false, only print each print_interval:th iteration
    print_on = false

    # print acceptance rate for the last print_interval iterations
    if mod(r-1,print_interval) == 0
      print_on = true # print ESS and Nbr resample each print_interval:th iteration
      # print accaptace rate
      @printf "Acceptance rate on iteration %d to %d is %.4f\n" r-print_interval r-1  sum(accept_vec[r-print_interval:r-1])/( r-1 - (r-print_interval) )
      # print covaraince function
      @printf "Covariance:\n"
      print_covariance(problem.adaptive_update,adaptive_update_params, r)
      # print loglik
      @printf "Loglik: %.4f \n" loglik[r-1]
    end

    # Gaussian random walk
    (theta_star, ) = gaussian_random_walk(problem.adaptive_update, adaptive_update_params, Theta[:,r-1], r)

    # calc loglik using proposal
    if pf_alg == "apf"
      error("The auxiliary particle filter is not implemented")
    elseif pf_alg == "bootstrap"
      loglik_star = pf(y, theta_star,theta_known, N,print_on)
    end

    if dist_type == "Uniform" # uniform priors
      prior_log_star = evaluate_prior(theta_star,prior_parameters)
      if prior_log_star == -Inf # reject if the proposed theta is outside the prior
        prior_vec[r] = 1
        accept = false
      else
        if alg == "MCWM"
          # calc accaptace probability for the MCWM algorithm
          a_log = loglik_star - pf(y, Theta[:,r-1],theta_known,N,print_on)
        else
          # calc accaptace probability for the PMCMC algorithm
          a_log = loglik_star  -  loglik[r-1]
        end
        accept = u_log[r] < a_log # calc accaptace decision
      end
    end

    if store_data && r > burn_in # store data
      Theta_val[:,r-burn_in] = theta_star
      loglik_val[r-burn_in] = loglik_star
    end

    if accept # the proposal is accapted
      Theta[:,r] = theta_star # update chain with new proposals
      loglik[r] = loglik_star
      accept_vec[r] = 1
    else
      Theta[:,r] = Theta[:,r-1] # keep old values
      loglik[r] = loglik[r-1]
    end

    # adaptation of covaraince matrix for the proposal distribution
    adaptation(problem.adaptive_update, adaptive_update_params, Theta, r,a_log)

  end

  @printf "Ending MCMC with adaptive RW estimating %d parameters\n" length(theta_true)
  @printf "Algorithm: %s\n" alg
  @printf "Adaptation algorithm: %s\n" typeof(problem.adaptive_update)
  @printf "Prior distribution: %s\n" problem.prior_dist.dist
  @printf "Particel filter: %s\n" pf_alg

  if store_data && return_cov_matrix
    cov_prop_kernel = get_covariance(problem.adaptive_update,adaptive_update_params, R)
    return return_results(Theta,loglik,accept_vec,prior_vec, problem,adaptive_update_params), Theta_val, loglik_val, cov_prop_kernel
  elseif store_data
    return return_results(Theta,loglik,accept_vec,prior_vec, problem,adaptive_update_params), Theta_val, loglik_val

  else
    return_results(Theta,loglik,accept_vec,prior_vec, problem,adaptive_update_params)
  end

end

# Help functions

doc"""
    return_results(Theta,loglik,accept_vec,prior_vec, problem,adaptive_update_params)

Constructs the return type of the resutls from the MCWM and PMCMC algorithm.
"""
function return_results(Theta,loglik,accept_vec,prior_vec)
  return Result(Theta, loglik, accept_vec, prior_vec)
end

doc"""
    return_results(Theta,loglik,accept_vec,prior_vec, problem,adaptive_update_params)

Constructs the return type of the resutls from the MCWH and PMCMC algorithm.
  """
function return_results(Theta,loglik,accept_vec,prior_vec, problem,adaptive_update_params)
  if typeof(problem.adaptive_update) == AMUpdate_gen
    return (Result(Theta, loglik, accept_vec, prior_vec), adaptive_update_params[6])
  else
    return Result(Theta, loglik, accept_vec, prior_vec)
  end
end
```

    return_results

Function to evaluate the joint prior distribution.

```julia
doc"""
    evaluate_prior(theta_star, Theta_bounds)
"""
function  evaluate_prior(theta_star, Theta_parameters, dist_type = "Unifrom")

  # set start value for loglik
  log_likelihood = 0.

  if dist_type == "Uniform"
    for i = 1:length(theta_star)
      # Update loglik, i.e. add the loglik for each model paramter in theta
      log_likelihood = log_likelihood + log_unifpdf( theta_star[i], Theta_parameters[i,1], Theta_parameters[i,2] )
    end
  else
    # add other priors
  end

  return log_likelihood # return log_lik

end

# Help fuction

doc"""
    log_unifpdf(x::Float64, a::Float64,b::Float64)

Computes log(unifpdf(x,a,b)).
"""
function log_unifpdf(x::Float64, a::Float64, b::Float64)
  if  x >= a && x<= b
    return -log(b-a);
  else
    return log(0);
  end
end

```

    log_unifpdf

Set up PMCMC problem.

```julia
problem = set_up_problem(ploton = false);

# load data
problem.data.y = Array(CSV.read("data/rickermodel_data.csv", nullable=false))[:,1]

problem.alg_param.N = 1000;
problem.alg_param.R = 10000;
problem.alg_param.burn_in = 2000;
problem.alg_param.alg = "PMCMC";
problem.adaptive_update = AMUpdate_gen(eye(3), 2.4/sqrt(3), 0.2, 1., 0.8, 25);
problem.alg_param.print_interval = 2000;
```

We can now run the PMCMC algorithm. WARNING this can take a few minutes to run.

```julia
# fix random numbers
srand(100)

res_MCMC = @time MCMC(problem);
```

    Starting PMCMC with adaptive RW estimating 3 parameters
    MCMC algorithm: PMCMC
    Adaptation algorithm: AMUpdate_gen
    Prior distribution: Uniform
    Particel filter: bootstrap
    Iteration: 1
    Covariance:
    [1.92 0.0 0.0; 0.0 1.92 0.0; 0.0 0.0 1.92]
    ESS: 9.7671
    Loglik: 6279.0758
    Acceptance rate on iteration 1 to 2000 is 0.2626
    Covariance:
    [0.0230086 -0.00534994 0.0197145; -0.00534994 0.00258669 -0.00124117; 0.0197145 -0.00124117 0.210006]
    Loglik: 6404.2601
    ESS: 27.3850
    Acceptance rate on iteration 2001 to 4000 is 0.2391
    Covariance:
    [0.0320822 -0.00770549 0.0175223; -0.00770549 0.00363055 -0.00764602; 0.0175223 -0.00764602 0.286838]
    Loglik: 6404.1382
    ESS: 108.8778
    Acceptance rate on iteration 4001 to 6000 is 0.2041
    Covariance:
    [0.0350834 -0.00827546 0.0302912; -0.00827546 0.00370262 -0.00822502; 0.0302912 -0.00822502 0.331766]
    Loglik: 6402.7178
    ESS: 182.5104
    Acceptance rate on iteration 6001 to 8000 is 0.2011
    Covariance:
    [0.0314133 -0.00805598 0.0171343; -0.00805598 0.00369989 -0.00403035; 0.0171343 -0.00403035 0.342864]
    Loglik: 6404.1264
    ESS: 5.6726
    Ending MCMC with adaptive RW estimating 3 parameters
    Algorithm: PMCMC
    Adaptation algorithm: AMUpdate_gen
    Prior distribution: Uniform
    Particel filter: bootstrap
     62.209933 seconds (16.06 M allocations: 86.537 GiB, 9.74% gc time)

Set results.

```julia
res = res_MCMC[1];

Theta = res.Theta_est;
loglik = res.loglik_est;
accept_vec = res.accept_vec;
prior_vec = res.prior_vec;
```

Parameter estimations (posterior mean), and posterior quantile intervals, 2.5th and 97.5th quantiles in parenthesis.

```julia
# calc posterior mean
post_mean = round.(mean(Theta[:,problem.alg_param.burn_in+1:end],2),3)

# calc quantiles
q = round.([quantile(Theta[1,problem.alg_param.burn_in+1:end], [0.025 0.975])
            quantile(Theta[2,problem.alg_param.burn_in+1:end], [0.025 0.975])
            quantile(Theta[3,problem.alg_param.burn_in+1:end], [0.025 0.975])],3)

# create data frame
df_mcmc_param_est = DataFrame(parameter = [L"$\log r$"; L"$\log \phi$";L"$\log \sigma$"], true_values = round.(problem.model_param.theta_true,3), param_est  = ["$(post_mean[1]) ($(q[1,1]), $(q[1,2]))"; "$(post_mean[2]) ($(q[2,1]), $(q[2,2]))"; "$(post_mean[3]) ($(q[3,1]), $(q[3,2]))";])

```

	parameter	true_values	param_est

1	$\log r$	3.8	3.726 (3.532, 3.955)

2	$\log \phi$	2.303	2.295 (2.224, 2.37)

3	$\log \sigma$	-1.204	-1.589 (-2.283, -0.937)

Plot chains.

```julia
# plot chains
PyPlot.figure(figsize=(10,8));
PyPlot.subplot(311);
PyPlot.plot(Theta[1,:]);
PyPlot.plot(ones(size(Theta,2),1)*problem.model_param.theta_true[1], "k");
PyPlot.ylabel(L"$\log r$");
PyPlot.subplot(312);
PyPlot.plot(Theta[2,:]);
PyPlot.plot(ones(size(Theta,2),1)*problem.model_param.theta_true[2], "k");
PyPlot.ylabel(L"$\log \phi$");
PyPlot.subplot(313);
PyPlot.plot(Theta[3,:]);
PyPlot.plot(ones(size(Theta,2),1)*problem.model_param.theta_true[3], "k");
PyPlot.ylabel(L"$\log \sigma$");
PyPlot.xlabel("Iteration");
```

Plot posterior.

```julia
x_c1 = problem.prior_dist.prior_parameters[1,1]-0.1:0.01:problem.prior_dist.prior_parameters[1,2]+0.1;
x_c2 = problem.prior_dist.prior_parameters[2,1]-0.1:0.01:problem.prior_dist.prior_parameters[2,2]+0.1;
x_c3 = problem.prior_dist.prior_parameters[3,1]-0.1:0.01:problem.prior_dist.prior_parameters[3,2]+0.1;

x_c1_kerneldens = x_c1;
x_c2_kerneldens = x_c2;
x_c3_kerneldens = x_c3;

# calc prior dist
priordens_c1 = pdf.(Uniform(problem.prior_dist.prior_parameters[1,1], problem.prior_dist.prior_parameters[1,2]), x_c1);
priordens_c2 = pdf.(Uniform(problem.prior_dist.prior_parameters[2,1], problem.prior_dist.prior_parameters[2,2]), x_c2);
priordens_c3 = pdf.(Uniform(problem.prior_dist.prior_parameters[3,1], problem.prior_dist.prior_parameters[3,2]), x_c3);

h1 = kde(Theta[1,problem.alg_param.burn_in:end]);
h2 = kde(Theta[2,problem.alg_param.burn_in:end]);
h3 = kde(Theta[3,problem.alg_param.burn_in:end]);

PyPlot.figure(figsize=(10,8));
PyPlot.subplot(311);
PyPlot.plot(h1.x,h1.density, "b");
PyPlot.plot(x_c1,priordens_c1, "g");
PyPlot.plot((problem.model_param.theta_true[1], problem.model_param.theta_true[1]), (0, maximum(h1.density)), "k");
PyPlot.ylabel(L"log $r$");
axis([minimum(h1.x), maximum(h1.x), 0, maximum(h1.density)+0.5]);
PyPlot.subplot(312);
PyPlot.plot(h2.x,h2.density, "b");
PyPlot.plot(x_c2,priordens_c2, "g");
PyPlot.plot((problem.model_param.theta_true[2], problem.model_param.theta_true[2]), (0, maximum(h2.density)), "k");
PyPlot.ylabel(L"log $\phi$");
axis([minimum(h2.x), maximum(h2.x), 0, maximum(h2.density)+0.5]);
PyPlot.subplot(313);
PyPlot.plot(h3.x,h3.density, "b");
PyPlot.plot(x_c3,priordens_c3, "g");
PyPlot.plot((problem.model_param.theta_true[3], problem.model_param.theta_true[3]), (0, maximum(h3.density)), "k");
PyPlot.ylabel(L"log $\sigma$");
axis([minimum(h3.x), maximum(h3.x), 0, maximum(h3.density)+0.5]);

```

We can conclude that we can estimate all parameters for the Ricker model. We also see that the parameter with the highest posterior variance is $\sigma$, which is not surprising since the parameter that governs the noise level in a system often is the hardest parameter to estimate.

## Current research questions

A problem with the PMCMC method, and also the ABC-MCMC method, is that these methods can be very computational challenging for large data sets (i.e. when the data consists of a long time series). It can therfore be of interest to use delayed-acceptance schemes that try to avoid estimating the likelihood in the PMCMC case, of generating the data in the ABC case. An ongoing research task is therefore to construct these delayed-acceptance schemes considering both PMCMC and the ABC-MCMC setting.

## Conclusions

We have here given a general introduction to the Bayesian inference, and in particular an introduction to some likelihood-free inference methods.

We see that the ABC method can be using an MCMC setting, allowing us to construct more efficient algorithms, in comparison to using the rejection sampling scheme, and still using a likelihood-free setting.

We also present the PMCMC algorithm which uses a different approach compared to the ABC method.

Some research questions are also briefly discussed.

## References

1. Allingham, David, R. A. R. King, and Kerrie L. Mengersen. "Bayesian estimation of quantile distributions." Statistics and Computing 19, no. 2 (2009): 189-201.

2. Andrieu, Christophe, and Johannes Thoms. "A tutorial on adaptive MCMC." Statistics and computing 18, no. 4 (2008): 343-373.

3. Andrieu, Christophe, and Gareth O. Roberts. "The pseudo-marginal approach for efficient Monte Carlo computations." The Annals of Statistics (2009): 697-725.

4. Andrieu, Christophe, Arnaud Doucet, and Roman Holenstein. "Particle markov chain monte carlo methods." Journal of the Royal Statistical Society: Series B (Statistical Methodology) 72, no. 3 (2010): 269-342.

5. Drovandie, Christopher C. "Approximate Bayesian Computation." In wiley StatsRef: Statistics References Online. John Wiley & Sons Lt,Ltd. pp 1-9, 2017.

6.  Etz, Alexander, Quentin Frederik Gronau, Fabian Dablander, Peter Edelsbrunner, and Beth Baribault. "How to become a Bayesian in eight easy steps: An annotated reading list." (2016)

7. Fasiolo, Matteo, Natalya Pya, and Simon N. Wood. "A comparison of inferential methods for highly nonlinear state space models in ecology and epidemiology." Statistical Science 31, no. 1 (2016): 96-118.

8. Gelman, Andrew, Daniel Simpson, and Michael Betancourt. "The prior can generally only be understood in the context of the likelihood." arXiv preprint arXiv:1708.07487 (2017).

9. Gordon, Neil J., David J. Salmond, and Adrian FM Smith. "Novel approach to nonlinear/non-Gaussian Bayesian state estimation." In IEE Proceedings F (Radar and Signal Processing), vol. 140, no. 2, pp. 107-113. IET Digital Library, 1993.

10. Haario, Heikki, Eero Saksman, and Johanna Tamminen. "An adaptive Metropolis algorithm." Bernoulli 7, no. 2 (2001): 223-242.

11. Marjoram, Paul, John Molitor, Vincent Plagnol, and Simon Tavaré. "Markov chain Monte Carlo without likelihoods." Proceedings of the National Academy of Sciences 100, no. 26 (2003): 15324-15328.

12. Mueller, Christian Lorenz. "Exploring the common concepts of adaptive MCMC and Covariance Matrix Adaptation schemes." In Dagstuhl Seminar Proceedings. Schloss Dagstuhl-Leibniz-Zentrum fÃ¼r Informatik, 2010.

13. Rayner, Glen D., and Helen L. MacGillivray. "Numerical maximum likelihood estimation for the g-and-k and generalized g-and-h distributions." Statistics and Computing 12, no. 1 (2002): 57-75.

14. Picchini, Umberto, and Rachele Anderson. "Approximate maximum likelihood estimation using data-cloning ABC." Computational Statistics & Data Analysis 105 (2017): 166-183..

15. Prangle, Dennis. "Summary statistics in approximate Bayesian computation." arXiv preprint arXiv:1512.05633 (2015).

16. Prangle, Dennis. "Adapting the ABC distance function." Bayesian Analysis 12.1 (2017): 289-309.

18. Prangle, Dennis. "gk: An R Package for the g-and-k and generalised g-and-h Distributions." arXiv preprint arXiv:1706.06889 (2017).

17. Scott A. Sisson, Yanan Fan. "Likelihood-free Markov chain Monte Carlo." arXiv preprint arXiv:1001.2058v1 (2010).

18. Wood, Simon N. "Statistical inference for noisy nonlinear ecological dynamic systems." Nature 466, no. 7310 (2010): 1102-1104.

19. Yildirim, Ilker. "Bayesian Inference: Metropolis-Hastings Sampling." Dept. of Brain and Cognitive Sciences, Univ. of Rochester, Rochester, NY (2012).

.ipynb_checkpoints/An introduction to likelihood-free inference-checkpoint.ipynb