An example using PyMultiNest
Here we show a standalone example of using PyMultiNest to
estimate the parameters of a straight line model in data with Gaussian noise. The
data and model used in this example are defined in createdata.py, which can be downloaded
from here. The
script shown below can be downloaded from here.
Example code
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Example of running PyMultiNest to fit the parameters of a straight line.
"""
from __future__ import print_function, division
import os
import sys
from scipy.special import ndtri
import numpy as np
try:
import matplotlib as mpl
mpl.use('Agg')
except ImportError:
pass
# import PyMultiNest Solver class
from pymultinest.solve import Solver
# import model and data
from createdata import *
LN2PI = np.log(2.*np.pi)
LNSIGMA = np.log(sigma)
# create Solver class
class StraightLineModelPyMultiNest(Solver):
"""
A simple straight line model, with a Gaussian likelihood.
Args:
data (:class:`numpy.ndarray`): an array containing the observed data
abscissa (:class:`numpy.ndarray`): an array containing the points at which the data were taken
modelfunc (function): a function defining the model
sigma (float): the standard deviation of the noise in the data
**kwargs: keyword arguments for the run method
"""
# define the prior parameters
cmin = -10. # lower range on c (the same as the uniform c prior lower bound)
cmax = 10. # upper range on c (the same as the uniform c prior upper bound)
mmu = 0. # mean of the Gaussian prior on m
msigma = 10. # standard deviation of the Gaussian prior on m
def __init__(self, data, abscissa, modelfunc, sigma, **kwargs):
# set the data
self._data = data # oberserved data
self._abscissa = abscissa # points at which the observed data are taken
self._sigma = sigma # standard deviation(s) of the data
self._logsigma = np.log(sigma) # log sigma here to save computations in the likelihood
self._ndata = len(data) # number of data points
self._model = modelfunc # model function
Solver.__init__(self, **kwargs)
def Prior(self, cube):
"""
The prior transform going from the unit hypercube to the true parameters. This function
has to be called "Prior".
Args:
cube (:class:`numpy.ndarray`): an array of values drawn from the unit hypercube
Returns:
:class:`numpy.ndarray`: an array of the transformed parameters
"""
# extract values
mprime = cube[0]
cprime = cube[1]
m = self.mmu + self.msigma*ndtri(mprime) # convert back to m
c = cprime*(self.cmax-self.cmin) + self.cmin # convert back to c
return np.array([m, c])
def LogLikelihood(self, cube):
"""
The log likelihood function. This function has to be called "LogLikelihood".
Args:
cube (:class:`numpy.ndarray`): an array of parameter values.
Returns:
float: the log likelihood value.
"""
# extract parameters
m = cube[0]
c = cube[1]
# calculate the model
model = self._model(x, m, c)
# normalisation
norm = -0.5*self._ndata*LN2PI - self._ndata*self._logsigma
# chi-squared
chisq = np.sum(((self._data - model)/(self._sigma))**2)
return norm - 0.5*chisq
nlive = 1024 # number of live points
ndim = 2 # number of parameters
tol = 0.5 # stopping criterion
# run the algorithm
solution = StraightLineModelPyMultiNest(data, x, straight_line, sigma, n_dims=ndim,
n_live_points=nlive, evidence_tolerance=tol);
logZpymnest = solution.logZ # value of log Z
logZerrpymnest = solution.logZerr # estimate of the statistcal uncertainty on logZ
print('Marginalised evidence is ± {}'.format(logZpymnest, logZerrpymnest))
mchain_pymnest = solution.samples[:,0] # extract chain of m values
cchain_pymnest = solution.samples[:,1] # extract chain if c values
postsamples = np.vstack((mchain_pymnest, cchain_pymnest)).T
print('Number of posterior samples is {}'.format(postsamples.shape[0]))
# plot posterior samples (if corner.py is installed)
try:
import corner # import corner.py
except ImportError:
sys.exit(1)
fig = corner.corner(postsamples, labels=[r"$m$", r"$c$"], truths=[m, c])
fig.savefig('PyMultiNest.png')
Running the code
A description of installing PyMultiNest is given here. If you have downloaded the createdata.py and test_PyMultiNest.py scripts into the directory ${HOME}, then you can run it using:
python test_PyMultiNest.py
If you have Matplotlib installed then the script will produce a plot of the posterior distributions on the straight line parameters $m$ and $c$.
A Python 3 Docker image with PyMultiNest installed is available, which can be used with:
docker run -it -v ${HOME}:/work mattpitkin/samplers:python3
to enter an interactive container, and then within the container the test script can be run with:
python test_PyMultiNest.py