Run-tests requires nbconvert, not listed in user dependencies
Causes issue on fresh ubuntu 14.04 install, as found by @mirams 
diff --git a/.github/workflows/unit-test-python-coverage.yml b/.github/workflows/unit-test-python-coverage.yml
index 55c20dab..0e9ed8a9 100644
--- a/.github/workflows/unit-test-python-coverage.yml
+++ b/.github/workflows/unit-test-python-coverage.yml
@@ -21,7 +21,7 @@ jobs:
 
     strategy:
       matrix:
-        python-version: ['3.6', '3.7', '3.8', '3.9']  # Latest version is tested by coverage test and os tests
+        python-version: ['3.7', '3.8', '3.9', '3.10']  # Latest version is tested by coverage test and os tests
 
     steps:
       - uses: actions/checkout@v3
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c4906b66..9818607c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file.
 
 ## Unreleased
 
+- [#1479](https://github.com/pints-team/pints/pull/1479) PINTS is no longer tested on Python 3.6.
+
 ### Added
 - [#1466](https://github.com/pints-team/pints/pull/1466) Added a `TransformedRectangularBoundaries` class that preserves the `RectangularBoundaries` methods after transformation.
 - [#1462](https://github.com/pints-team/pints/pull/1461) The `OptimisationController` now has a stopping criterion `max_evaluations`.
@@ -17,6 +19,7 @@ All notable changes to this project will be documented in this file.
 - [#1378](https://github.com/pints-team/pints/pull/1378) Added a class `pints.LogNormalLogLikelihood`.
 
 ### Changed
+- [#1479](https://github.com/pints-team/pints/pull/1479) The `asyncio.coroutine` decorators have been removed from all of NUTS's coroutines in order to be compatible with Python 3.11.
 - [#1466](https://github.com/pints-team/pints/pull/1466) `Transformation.convert_boundaries` will now return a `TransformedRectangularBoundaries` object if the transformation is element-wise and the given boundaries extend `RectangularBoundaries`.
 - [#1458](https://github.com/pints-team/pints/pull/1458) The `GradientDescent` optimiser now sets its default learning rate as `min(sigma0)` (it can still be changed afterwards with `set_learning_rate()`).
 - [#1445](https://github.com/pints-team/pints/pull/1445) Allowed multiple LogPDFs to be supplied to the MCMCController (one for each MCMC chain), and added an evaluator which evaluates each position on a separate callable.
diff --git a/LICENSE.md b/LICENSE.md
index f8bc744d..e69a9593 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,6 +1,6 @@
 BSD 3-Clause License
 
-Copyright (c) 2017-2022, University of Oxford (University of Oxford means the
+Copyright (c) 2017-2023, University of Oxford (University of Oxford means the
 Chancellor, Masters and Scholars of the University of Oxford, having an
 administrative office at Wellington Square, Oxford OX1 2JD, UK).
 All rights reserved.
diff --git a/examples/stats/custom-prior.ipynb b/examples/stats/custom-prior.ipynb
index 91d09383..afe763e1 100644
--- a/examples/stats/custom-prior.ipynb
+++ b/examples/stats/custom-prior.ipynb
@@ -110,7 +110,7 @@
     "        r = np.sqrt(p[0]*p[0] + p[1]*p[1])\n",
     "        \n",
     "        # Return\n",
-    "        return self._c if r < self._r else -float('inf')\n",
+    "        return self._c if r < self._r else -np.inf\n",
     "        "
    ]
   },
diff --git a/pints/_boundaries.py b/pints/_boundaries.py
index 8aa80ff0..c32c99bb 100644
--- a/pints/_boundaries.py
+++ b/pints/_boundaries.py
@@ -144,7 +144,7 @@ class LogPDFBoundaries(Boundaries):
         A threshold to determine whether a given log-prior value counts as
         within bounds. Anything _above_ the threshold counts as within bounds.
     """
-    def __init__(self, log_pdf, threshold=-float('inf')):
+    def __init__(self, log_pdf, threshold=-np.inf):
         super(LogPDFBoundaries, self).__init__()
 
         # Check log pdf
diff --git a/pints/_log_pdfs.py b/pints/_log_pdfs.py
index cbf45bb3..6457f12d 100644
--- a/pints/_log_pdfs.py
+++ b/pints/_log_pdfs.py
@@ -206,7 +206,7 @@ class PooledLogPDF(LogPDF):
                 'as the number of parameters of the individual log-pdfs.')
 
         # Check that pooled contains only booleans
-        if self._pooled.dtype != np.bool:
+        if self._pooled.dtype != np.dtype('bool'):
             raise ValueError(
                 'The array-like input `pooled` passed to PooledLogPDFs '
                 'has to contain booleans exclusively.')
@@ -375,7 +375,7 @@ class LogPosterior(LogPDF):
         self._log_likelihood = log_likelihood
 
         # Store -inf, for later use
-        self._minf = -float('inf')
+        self._minf = -np.inf
 
     def __call__(self, x):
         # Evaluate log-prior first, assuming this is very cheap
diff --git a/pints/_mcmc/_monomial_gamma_hamiltonian.py b/pints/_mcmc/_monomial_gamma_hamiltonian.py
index 705a9e05..d5e49748 100644
--- a/pints/_mcmc/_monomial_gamma_hamiltonian.py
+++ b/pints/_mcmc/_monomial_gamma_hamiltonian.py
@@ -189,7 +189,7 @@ class MonomialGammaHamiltonianMCMC(pints.SingleChainMCMC):
         Auxillary kinetic energy cumulative density defined in [1]_.
         """
         return integrate.quad(lambda p1: self._pdf(p1, a, c, m, z),
-                              -float('Inf'), p)[0]
+                              -np.inf, p)[0]
 
     def divergent_iterations(self):
         """
@@ -223,7 +223,7 @@ class MonomialGammaHamiltonianMCMC(pints.SingleChainMCMC):
         """
         z = integrate.quad(
             lambda p: np.exp(-self._K_indiv(p, self._a, self._c, self._m)),
-            -float('Inf'), float('Inf'))[0]
+            -np.inf, np.inf)[0]
         self._f = self._inverse_cdf_calculator(self._a, self._c,
                                                self._m, z)
 
diff --git a/pints/_mcmc/_nuts.py b/pints/_mcmc/_nuts.py
index c7e3c168..b665b346 100644
--- a/pints/_mcmc/_nuts.py
+++ b/pints/_mcmc/_nuts.py
@@ -7,7 +7,6 @@
 #
 import _pickle as cPickle
 
-import asyncio
 import pints
 import numpy as np
 
@@ -207,7 +206,6 @@ def kinetic_energy(r, inv_mass_matrix):
 # see main coroutine function ``nuts_sampler`` for more details
 
 
-@asyncio.coroutine
 def leapfrog(theta, L, grad_L, r, epsilon, inv_mass_matrix):
     """
     performs a leapfrog step using a step_size ``epsilon`` and an inverse mass
@@ -227,7 +225,6 @@ def leapfrog(theta, L, grad_L, r, epsilon, inv_mass_matrix):
     return L_new, grad_L_new, theta_new, r_new
 
 
-@asyncio.coroutine
 def build_tree(state, v, j, adaptor, hamiltonian0, hamiltonian_threshold):
     """
     Implicitly build up a subtree of depth ``j`` for the NUTS sampler.
@@ -253,7 +250,7 @@ def build_tree(state, v, j, adaptor, hamiltonian0, hamiltonian_threshold):
             - kinetic_energy(r_dash, adaptor.get_inv_mass_matrix())
 
         if np.isnan(hamiltonian_dash):
-            comparison = float('-inf')
+            comparison = -np.inf
         else:
             comparison = hamiltonian_dash - hamiltonian0
         n_dash = comparison
@@ -283,7 +280,6 @@ def build_tree(state, v, j, adaptor, hamiltonian0, hamiltonian_threshold):
         return state_dash
 
 
-@asyncio.coroutine
 def initialise_adaptor(
         theta, L, grad_L, num_adaption_steps, delta, sigma0,
         use_dense_mass_matrix):
@@ -316,7 +312,6 @@ def initialise_adaptor(
         num_adaption_steps, delta, epsilon, init_inv_mass_matrix)
 
 
-@asyncio.coroutine
 def find_reasonable_epsilon(theta, L, grad_L, inv_mass_matrix):
     """
     Pick a reasonable value of epsilon close to when the acceptance
@@ -346,7 +341,7 @@ def find_reasonable_epsilon(theta, L, grad_L, inv_mass_matrix):
         yield from leapfrog(theta, L, grad_L, r, epsilon, inv_mass_matrix)
     hamiltonian_dash = L_dash - kinetic_energy(r_dash, inv_mass_matrix)
     if np.isnan(hamiltonian_dash):
-        comparison = float('-inf')
+        comparison = -np.inf
     else:
         comparison = hamiltonian_dash - hamiltonian
 
@@ -360,13 +355,12 @@ def find_reasonable_epsilon(theta, L, grad_L, inv_mass_matrix):
             yield from leapfrog(theta, L, grad_L, r, epsilon, inv_mass_matrix)
         hamiltonian_dash = L_dash - kinetic_energy(r_dash, inv_mass_matrix)
         if np.isnan(hamiltonian_dash):  # pragma: no cover
-            comparison = float('-inf')
+            comparison = -np.inf
         else:
             comparison = hamiltonian_dash - hamiltonian
     return epsilon
 
 
-@asyncio.coroutine
 def nuts_sampler(
         x0, adaptor, sigma0, hamiltonian_threshold, max_tree_depth):
     """
diff --git a/pints/_nested/__init__.py b/pints/_nested/__init__.py
index b23a05d0..a7a15259 100644
--- a/pints/_nested/__init__.py
+++ b/pints/_nested/__init__.py
@@ -35,7 +35,7 @@ class NestedSampler(pints.TunableMethod):
         self._log_prior = log_prior
 
         # Current value of the threshold log-likelihood value
-        self._running_log_likelihood = -float('inf')
+        self._running_log_likelihood = -np.inf
         self._proposed = None
 
         # Initialise active point containers
@@ -291,7 +291,7 @@ class NestedController(object):
         self._marginal_log_likelihood_threshold = 0.5
 
         # Initial marginal difference
-        self._diff = np.float('-Inf')
+        self._diff = np.inf
 
         # By default use ellipsoidal sampling
         if method is None:
diff --git a/pints/_optimisers/__init__.py b/pints/_optimisers/__init__.py
index 7d93b029..e95c31a6 100644
--- a/pints/_optimisers/__init__.py
+++ b/pints/_optimisers/__init__.py
@@ -581,13 +581,13 @@ class OptimisationController(object):
             evaluator = pints.SequentialEvaluator(f)
 
         # Keep track of current best and best-guess scores.
-        fb = fg = float('inf')
+        fb = fg = np.inf
 
         # Internally we always minimise! Keep a 2nd value to show the user.
         fb_user, fg_user = (fb, fg) if self._minimising else (-fb, -fg)
 
         # Keep track of the last significant change
-        f_sig = float('inf')
+        f_sig = np.inf
 
         # Set up progress reporting
         next_message = 0
diff --git a/pints/_optimisers/_cmaes.py b/pints/_optimisers/_cmaes.py
index d9e64ac7..b223a1c4 100644
--- a/pints/_optimisers/_cmaes.py
+++ b/pints/_optimisers/_cmaes.py
@@ -43,7 +43,7 @@ class CMAES(pints.PopulationBasedOptimiser):
         self._ready_for_tell = False
 
         # Estimated f(x_guessed)
-        self._f_guessed = float('inf')
+        self._f_guessed = np.inf
 
     def ask(self):
         """ See :meth:`Optimiser.ask()`. """
@@ -74,7 +74,7 @@ class CMAES(pints.PopulationBasedOptimiser):
     def f_best(self):
         """ See :meth:`Optimiser.f_best()`. """
         f = self._es.result.fbest if self._running else None
-        return float('inf') if f is None else f
+        return np.inf if f is None else f
 
     def f_guessed(self):
         """ See :meth:`Optimiser.f_guessed()`. """
diff --git a/pints/_optimisers/_cmaes_bare.py b/pints/_optimisers/_cmaes_bare.py
index 5a5ed57c..dc6ede94 100644
--- a/pints/_optimisers/_cmaes_bare.py
+++ b/pints/_optimisers/_cmaes_bare.py
@@ -50,7 +50,7 @@ class BareCMAES(pints.PopulationBasedOptimiser):
 
         # Best solution found
         self._x_best = pints.vector(x0)
-        self._f_best = float('inf')
+        self._f_best = np.inf
 
         # Number of iterations run
         self._iterations = 0
@@ -59,7 +59,7 @@ class BareCMAES(pints.PopulationBasedOptimiser):
         self._mu = np.copy(self._x0)
 
         # Approximate value at self._mu
-        self._f_guessed = float('inf')
+        self._f_guessed = np.inf
 
         # Step size
         self._eta = np.min(self._sigma0)
@@ -267,7 +267,7 @@ class BareCMAES(pints.PopulationBasedOptimiser):
         # Boundaries? Then reconstruct full fx vector
         if self._boundaries is not None and len(fx) < npo:
             user_fx = fx
-            fx = np.ones((npo, )) * float('inf')
+            fx = np.ones((npo, )) * np.inf
             fx[self._user_ids] = user_fx
 
         # Order the points from best to worst score
diff --git a/pints/_optimisers/_gradient_descent.py b/pints/_optimisers/_gradient_descent.py
index 38b100aa..ada45c26 100644
--- a/pints/_optimisers/_gradient_descent.py
+++ b/pints/_optimisers/_gradient_descent.py
@@ -6,6 +6,7 @@
 # copyright notice and full license details.
 #
 import pints
+import numpy as np
 
 
 class GradientDescent(pints.Optimiser):
@@ -27,7 +28,7 @@ class GradientDescent(pints.Optimiser):
 
         # Best solution found
         self._x_best = self._x0
-        self._f_best = float('inf')
+        self._f_best = np.inf
 
         # Learning rate
         self._eta = min(self._sigma0)
diff --git a/pints/_optimisers/_irpropmin.py b/pints/_optimisers/_irpropmin.py
index 0ece749a..53dea659 100644
--- a/pints/_optimisers/_irpropmin.py
+++ b/pints/_optimisers/_irpropmin.py
@@ -86,7 +86,7 @@ class IRPropMin(pints.Optimiser):
 
         # Best solution found
         self._x_best = self._x0
-        self._f_best = float('inf')
+        self._f_best = np.inf
 
         # Minimum and maximum step sizes
         self._step_min = 1e-3 * np.min(self._sigma0)
@@ -94,7 +94,7 @@ class IRPropMin(pints.Optimiser):
 
         # Current point, score, and gradient
         self._current = self._x0
-        self._current_f = float('inf')
+        self._current_f = np.inf
         self._current_df = None
 
         # Proposed next point (read-only, so can be passed to user)
diff --git a/pints/_optimisers/_nelder_mead.py b/pints/_optimisers/_nelder_mead.py
index c6d516cc..50631e07 100644
--- a/pints/_optimisers/_nelder_mead.py
+++ b/pints/_optimisers/_nelder_mead.py
@@ -216,7 +216,7 @@ class NelderMead(pints.Optimiser):
 
     def f_best(self):
         """ See: :meth:`pints.Optimiser.f_best()`. """
-        return self._fs[0] if self._running else float('inf')
+        return self._fs[0] if self._running else np.inf
 
     def name(self):
         """ See: :meth:`pints.Optimiser.name()`. """
diff --git a/pints/_optimisers/_pso.py b/pints/_optimisers/_pso.py
index e9d75fbc..33d75625 100644
--- a/pints/_optimisers/_pso.py
+++ b/pints/_optimisers/_pso.py
@@ -97,7 +97,7 @@ class PSO(pints.PopulationBasedOptimiser):
 
     def f_best(self):
         """ See :meth:`Optimiser.f_best()`. """
-        return self._fg if self._running else float('inf')
+        return self._fg if self._running else np.inf
 
     def _initialise(self):
         """
@@ -137,11 +137,11 @@ class PSO(pints.PopulationBasedOptimiser):
 
         # Set initial scores and local best
         for i in range(self._population_size):
-            self._fl.append(float('inf'))
+            self._fl.append(np.inf)
             self._pl.append(self._xs[i])
 
         # Set global best position and score
-        self._fg = float('inf')
+        self._fg = np.inf
         self._pg = self._xs[0]
 
         # Boundaries? Then filter out out-of-bounds points from xs
@@ -226,7 +226,7 @@ class PSO(pints.PopulationBasedOptimiser):
         # Boundaries? Then reconstruct full fx vector
         if self._boundaries is not None and len(fx) < self._population_size:
             user_fx = fx
-            fx = np.ones((self._population_size, )) * float('inf')
+            fx = np.ones((self._population_size, )) * np.inf
             fx[self._user_ids] = user_fx
 
         # Update particles
diff --git a/pints/_optimisers/_snes.py b/pints/_optimisers/_snes.py
index a2a22718..7f5ac180 100644
--- a/pints/_optimisers/_snes.py
+++ b/pints/_optimisers/_snes.py
@@ -47,11 +47,11 @@ class SNES(pints.PopulationBasedOptimiser):
 
         # Best solution found
         self._x_best = pints.vector(x0)
-        self._f_best = float('inf')
+        self._f_best = np.inf
 
         # Best guess of the solution is mu
         # We don't have f(mu), so we approximate it by max f(sample)
-        self._f_guessed = float('inf')
+        self._f_guessed = np.inf
 
     def ask(self):
         """ See :meth:`Optimiser.ask()`. """
@@ -141,7 +141,7 @@ class SNES(pints.PopulationBasedOptimiser):
         # Boundaries? Then reconstruct full fx vector
         if self._boundaries is not None and len(fx) < self._population_size:
             user_fx = fx
-            fx = np.ones((self._population_size, )) * float('inf')
+            fx = np.ones((self._population_size, )) * np.inf
             fx[self._user_ids] = user_fx
 
         # Order the normalized samples according to the scores
diff --git a/pints/_optimisers/_xnes.py b/pints/_optimisers/_xnes.py
index f0844a45..a8dfbab3 100644
--- a/pints/_optimisers/_xnes.py
+++ b/pints/_optimisers/_xnes.py
@@ -52,11 +52,11 @@ class XNES(pints.PopulationBasedOptimiser):
 
         # Best solution seen
         self._x_best = pints.vector(x0)
-        self._f_best = float('inf')
+        self._f_best = np.inf
 
         # Best guess of the solution is mu
         # We don't have f(mu), so we approximate it by min f(sample)
-        self._f_guessed = float('inf')
+        self._f_guessed = np.inf
 
     def ask(self):
         """ See :meth:`Optimiser.ask()`. """
@@ -150,7 +150,7 @@ class XNES(pints.PopulationBasedOptimiser):
         # Boundaries? Then reconstruct full fx vector
         if self._boundaries is not None and len(fx) < self._population_size:
             bounded_fx = fx
-            fx = np.ones((self._population_size, )) * float('inf')
+            fx = np.ones((self._population_size, )) * np.inf
             fx[self._bounded_ids] = bounded_fx
 
         # Order the normalized samples according to the scores
diff --git a/pints/plot/_histogram.py b/pints/plot/_histogram.py
index 39ef81e5..6b88afe1 100644
--- a/pints/plot/_histogram.py
+++ b/pints/plot/_histogram.py
@@ -56,7 +56,7 @@ def histogram(
     bins = 40
     alpha = 0.5
 
-    samples = np.asarray(samples)
+    samples = np.array(samples)
     n_list = len(samples)
     _, n_param = samples[0].shape
 
@@ -68,13 +68,6 @@ def histogram(
             'Length of `parameter_names` must be same as number of'
             ' parameters.')
 
-    # Check number of parameters
-    for samples_j in samples:
-        if n_param != samples_j.shape[1]:
-            raise ValueError(
-                'All samples must have the same number of parameters.'
-            )
-
     # Check reference parameters
     if ref_parameters is not None:
         if len(ref_parameters) != n_param:
diff --git a/pints/tests/test_abc_smc.py b/pints/tests/test_abc_smc.py
index 1cf64fb7..6c822995 100644
--- a/pints/tests/test_abc_smc.py
+++ b/pints/tests/test_abc_smc.py
@@ -101,9 +101,7 @@ class TestABCSMC(unittest.TestCase):
                 fxs = [self.error_measure(x) for x in xs]
                 sample = abc.tell(fxs)
             samples.append(sample)
-
-        samples = np.array(samples)
-        self.assertEqual(samples.shape[0], 3 * niter)
+        self.assertEqual(len(samples), 3 * niter)
 
     def test_errors(self):
         # test errors in abc rejection
diff --git a/pints/tests/test_error_measures.py b/pints/tests/test_error_measures.py
index c1da8050..473c86f2 100755
--- a/pints/tests/test_error_measures.py
+++ b/pints/tests/test_error_measures.py
@@ -63,7 +63,7 @@ class BigMiniProblem(MiniProblem):
 
 
 class BadMiniProblem(MiniProblem):
-    def __init__(self, bad_value=float('inf')):
+    def __init__(self, bad_value=np.inf):
         super(BadMiniProblem, self).__init__()
         self._v = pints.vector([bad_value, 2, -3])
 
@@ -72,7 +72,7 @@ class BadMiniProblem(MiniProblem):
 
 
 class BadErrorMeasure(pints.ErrorMeasure):
-    def __init__(self, bad_value=float('-inf')):
+    def __init__(self, bad_value=-np.inf):
         super(BadErrorMeasure, self).__init__()
         self._v = bad_value
 
@@ -628,24 +628,24 @@ class TestSumOfErrors(unittest.TestCase):
             e = pints.SumOfErrors(
                 [e4, e1, e1, e1, e1, e1], [10, 1, 1, 1, 1, 1])
             self.assertEqual(e.n_parameters(), 3)
-            self.assertEqual(e(x), float('inf'))
+            self.assertEqual(e(x), np.inf)
             e = pints.SumOfErrors(
                 [e4, e1, e1, e1, e1, e1], [0, 2, 0, 2, 0, 2])
             self.assertEqual(e.n_parameters(), 3)
             self.assertTrue(e(x), 6 * e1(x))
-            e5 = pints.SumOfSquaresError(BadMiniProblem(float('-inf')))
+            e5 = pints.SumOfSquaresError(BadMiniProblem(-np.inf))
             e = pints.SumOfErrors([e1, e5, e1], [2.1, 3.4, 6.5])
             self.assertTrue(np.isinf(e(x)))
             e = pints.SumOfErrors([e4, e5, e1], [2.1, 3.4, 6.5])
             self.assertTrue(np.isinf(e(x)))
             e5 = pints.SumOfSquaresError(BadMiniProblem(float('nan')))
             e = pints.SumOfErrors(
-                [BadErrorMeasure(float('inf')), BadErrorMeasure(float('inf'))],
+                [BadErrorMeasure(np.inf), BadErrorMeasure(np.inf)],
                 [1, 1])
-            self.assertEqual(e(x), float('inf'))
+            self.assertEqual(e(x), np.inf)
             e = pints.SumOfErrors(
-                [BadErrorMeasure(float('inf')),
-                 BadErrorMeasure(float('-inf'))],
+                [BadErrorMeasure(np.inf),
+                 BadErrorMeasure(-np.inf)],
                 [1, 1])
             self.assertTrue(np.isnan(e(x)))
             e = pints.SumOfErrors(
diff --git a/pints/tests/test_log_pdfs.py b/pints/tests/test_log_pdfs.py
index 876a2fb8..a8b5e5da 100755
--- a/pints/tests/test_log_pdfs.py
+++ b/pints/tests/test_log_pdfs.py
@@ -33,8 +33,8 @@ class TestLogPosterior(unittest.TestCase):
         p = pints.LogPosterior(log_likelihood, log_prior)
         self.assertEqual(p(x), log_likelihood(x) + log_prior(x))
         y = [-1, 500]
-        self.assertEqual(log_prior(y), -float('inf'))
-        self.assertEqual(p(y), -float('inf'))
+        self.assertEqual(log_prior(y), -np.inf)
+        self.assertEqual(p(y), -np.inf)
         self.assertEqual(p(y), log_prior(y))
 
         # Test derivatives
diff --git a/pints/tests/test_log_priors.py b/pints/tests/test_log_priors.py
index 4d41bb12..a77c9fca 100755
--- a/pints/tests/test_log_priors.py
+++ b/pints/tests/test_log_priors.py
@@ -202,7 +202,10 @@ class TestPrior(unittest.TestCase):
         p2 = pints.UniformLogPrior(m2, c2)
 
         p = pints.ComposedLogPrior(p1, p2)
-        self.assertTrue(np.array_equal(p.mean(), [10, 0]))
+        mean = p.mean()
+        self.assertEqual(len(mean), 2)
+        self.assertEqual(mean[0], 10)
+        self.assertEqual(mean[1][0], 0)
 
     def test_composed_prior_cdf_icdf(self):
         p1 = pints.GaussianLogPrior(-3, 7)
@@ -472,7 +475,7 @@ class TestPrior(unittest.TestCase):
     def test_half_cauchy_prior(self):
         # Test two specific function values
         p1 = pints.HalfCauchyLogPrior(0, 10)
-        self.assertEqual(p1([0]), -float('Inf'))
+        self.assertEqual(p1([0]), -np.inf)
         self.assertAlmostEqual(p1([10]), -3.447314978843445)
         p2 = pints.HalfCauchyLogPrior(10, 5)
         self.assertAlmostEqual(p2([10]), -2.594487638427916)
@@ -1064,7 +1067,7 @@ class TestPrior(unittest.TestCase):
 
         # Test normal construction
         p = pints.UniformLogPrior(lower, upper)
-        m = float('-inf')
+        m = -np.inf
         self.assertEqual(p([0, 0]), m)
         self.assertEqual(p([0, 5]), m)
         self.assertEqual(p([0, 19]), m)
@@ -1093,7 +1096,7 @@ class TestPrior(unittest.TestCase):
         # Test from rectangular boundaries object
         b = pints.RectangularBoundaries(lower, upper)
         p = pints.UniformLogPrior(b)
-        m = float('-inf')
+        m = -np.inf
         self.assertEqual(p([0, 0]), m)
         self.assertEqual(p([0, 5]), m)
         self.assertEqual(p([0, 19]), m)
@@ -1133,7 +1136,7 @@ class TestPrior(unittest.TestCase):
 
         b = CircleBoundaries(5, 5, 2)
         p = pints.UniformLogPrior(b)
-        minf = -float('inf')
+        minf = -np.inf
         self.assertTrue(p([0, 0]) == minf)
         self.assertTrue(p([4, 4]) > minf)
 
diff --git a/pints/tests/test_mcmc_adaptive.py b/pints/tests/test_mcmc_adaptive.py
index 5a17a552..77de5597 100755
--- a/pints/tests/test_mcmc_adaptive.py
+++ b/pints/tests/test_mcmc_adaptive.py
@@ -82,7 +82,7 @@ class TestAdaptiveCovarianceMC(unittest.TestCase):
         # Bad starting point
         mcmc = pints.HaarioACMC(x0)
         mcmc.ask()
-        self.assertRaises(ValueError, mcmc.tell, float('-inf'))
+        self.assertRaises(ValueError, mcmc.tell, -np.inf)
 
         # Tell without ask
         mcmc = pints.HaarioACMC(x0)
@@ -91,7 +91,7 @@ class TestAdaptiveCovarianceMC(unittest.TestCase):
         # Bad starting point
         mcmc = pints.HaarioACMC(x0)
         mcmc.ask()
-        self.assertRaises(ValueError, mcmc.tell, float('-inf'))
+        self.assertRaises(ValueError, mcmc.tell, -np.inf)
 
     def test_eta(self):
         # Test eta getting and setting
diff --git a/pints/tests/test_mcmc_differential_evolution.py b/pints/tests/test_mcmc_differential_evolution.py
index cf00ffb2..05042893 100755
--- a/pints/tests/test_mcmc_differential_evolution.py
+++ b/pints/tests/test_mcmc_differential_evolution.py
@@ -120,7 +120,7 @@ class TestDifferentialEvolutionMCMC(unittest.TestCase):
         # Bad starting point
         mcmc = pints.DifferentialEvolutionMCMC(n, x0)
         mcmc.ask()
-        self.assertRaises(ValueError, mcmc.tell, float('-inf'))
+        self.assertRaises(ValueError, mcmc.tell, -np.inf)
 
         # Use uniform error
         mcmc = pints.DifferentialEvolutionMCMC(n, x0)
diff --git a/pints/tests/test_mcmc_dram_ac.py b/pints/tests/test_mcmc_dram_ac.py
index 3eff7dc0..aa88f62a 100755
--- a/pints/tests/test_mcmc_dram_ac.py
+++ b/pints/tests/test_mcmc_dram_ac.py
@@ -132,7 +132,7 @@ class TestDramACMC(unittest.TestCase):
         x0 = self.real_parameters
         mcmc = pints.DramACMC(x0)
         mcmc.ask()
-        self.assertRaises(ValueError, mcmc.tell, -float('inf'))
+        self.assertRaises(ValueError, mcmc.tell, -np.inf)
 
         self.assertNotEqual(mcmc.target_acceptance_rate(), 0.5)
         mcmc.set_target_acceptance_rate(0.5)
diff --git a/pints/tests/test_mcmc_dream.py b/pints/tests/test_mcmc_dream.py
index db305271..d8ca3080 100755
--- a/pints/tests/test_mcmc_dream.py
+++ b/pints/tests/test_mcmc_dream.py
@@ -150,7 +150,7 @@ class TestDreamMCMC(unittest.TestCase):
         # Bad starting point
         mcmc = pints.DreamMCMC(n, x0)
         mcmc.ask()
-        self.assertRaises(ValueError, mcmc.tell, float('-inf'))
+        self.assertRaises(ValueError, mcmc.tell, -np.inf)
 
     def test_set_hyper_parameters(self):
         # Tests the hyper-parameter interface for this optimiser.
diff --git a/pints/tests/test_mcmc_emcee_hammer.py b/pints/tests/test_mcmc_emcee_hammer.py
index 55ead9af..192a3d31 100755
--- a/pints/tests/test_mcmc_emcee_hammer.py
+++ b/pints/tests/test_mcmc_emcee_hammer.py
@@ -118,7 +118,7 @@ class TestEmceeHammerMCMC(unittest.TestCase):
         # Bad starting point
         mcmc = pints.EmceeHammerMCMC(n, x0)
         mcmc.ask()
-        self.assertRaises(ValueError, mcmc.tell, float('-inf'))
+        self.assertRaises(ValueError, mcmc.tell, -np.inf)
 
     def test_set_hyper_parameters(self):
         # Tests the parameter and hyper-parameter interfaces for this sampler.
diff --git a/pints/tests/test_mcmc_hamiltonian.py b/pints/tests/test_mcmc_hamiltonian.py
index 0cf0f8e0..f088ca93 100755
--- a/pints/tests/test_mcmc_hamiltonian.py
+++ b/pints/tests/test_mcmc_hamiltonian.py
@@ -98,7 +98,7 @@ class TestHamiltonianMCMC(unittest.TestCase):
         mcmc = pints.HamiltonianMCMC(x0)
         mcmc.ask()
         self.assertRaises(
-            ValueError, mcmc.tell, (float('-inf'), np.array([1, 1])))
+            ValueError, mcmc.tell, (-np.inf, np.array([1, 1])))
 
     def test_set_hyper_parameters(self):
         # Tests the parameter interface for this sampler.
diff --git a/pints/tests/test_mcmc_mala.py b/pints/tests/test_mcmc_mala.py
index 697333ee..b03289f9 100755
--- a/pints/tests/test_mcmc_mala.py
+++ b/pints/tests/test_mcmc_mala.py
@@ -99,7 +99,7 @@ class TestMALAMCMC(unittest.TestCase):
         mcmc = pints.MALAMCMC(x0)
         mcmc.ask()
         self.assertRaises(
-            ValueError, mcmc.tell, (float('-inf'), np.array([1, 1])))
+            ValueError, mcmc.tell, (-np.inf, np.array([1, 1])))
 
         # Test initialisation twice
         mcmc = pints.MALAMCMC(x0)
diff --git a/pints/tests/test_mcmc_metropolis.py b/pints/tests/test_mcmc_metropolis.py
index 9b85a938..d2704962 100755
--- a/pints/tests/test_mcmc_metropolis.py
+++ b/pints/tests/test_mcmc_metropolis.py
@@ -147,7 +147,7 @@ class TestMetropolisRandomWalkMCMC(unittest.TestCase):
         # Bad starting point
         mcmc = pints.MetropolisRandomWalkMCMC(x0)
         mcmc.ask()
-        self.assertRaises(ValueError, mcmc.tell, float('-inf'))
+        self.assertRaises(ValueError, mcmc.tell, -np.inf)
 
     def test_set_hyper_parameters(self):
         # Tests the hyper-parameter interface for this optimiser.
diff --git a/pints/tests/test_mcmc_monomial_gamma_hmc.py b/pints/tests/test_mcmc_monomial_gamma_hmc.py
index 256f114c..f5f1570e 100755
--- a/pints/tests/test_mcmc_monomial_gamma_hmc.py
+++ b/pints/tests/test_mcmc_monomial_gamma_hmc.py
@@ -98,7 +98,7 @@ class TestMonomialGammaHamiltonianMCMC(unittest.TestCase):
         mcmc = pints.MonomialGammaHamiltonianMCMC(x0)
         mcmc.ask()
         self.assertRaises(
-            ValueError, mcmc.tell, (float('-inf'), np.array([1, 1])))
+            ValueError, mcmc.tell, (-np.inf, np.array([1, 1])))
 
     def test_kinetic_energy(self):
         # Tests kinetic energy values and derivatives
diff --git a/pints/tests/test_mcmc_nuts.py b/pints/tests/test_mcmc_nuts.py
index 789139be..cc82029a 100755
--- a/pints/tests/test_mcmc_nuts.py
+++ b/pints/tests/test_mcmc_nuts.py
@@ -191,7 +191,7 @@ class TestNutsMCMC(unittest.TestCase):
         mcmc = pints.NoUTurnMCMC(x0)
         mcmc.ask()
         self.assertRaises(
-            ValueError, mcmc.tell, (float('-inf'), np.array([1, 1])))
+            ValueError, mcmc.tell, (-np.inf, np.array([1, 1])))
 
     def test_pickle(self):
         # Test I: make sure pickling state does not alter behaviour of sampler
diff --git a/pints/tests/test_mcmc_relativistic.py b/pints/tests/test_mcmc_relativistic.py
index a6f8cb94..d5893a8c 100755
--- a/pints/tests/test_mcmc_relativistic.py
+++ b/pints/tests/test_mcmc_relativistic.py
@@ -99,7 +99,7 @@ class TestRelativisticMCMC(unittest.TestCase):
         mcmc = pints.RelativisticMCMC(x0)
         mcmc.ask()
         self.assertRaises(
-            ValueError, mcmc.tell, (float('-inf'), np.array([1, 1])))
+            ValueError, mcmc.tell, (-np.inf, np.array([1, 1])))
 
     def test_kinetic_energy(self):
         # Tests kinetic energy values
diff --git a/pints/tests/test_opt_adam.py b/pints/tests/test_opt_adam.py
index 29884c54..19b05098 100755
--- a/pints/tests/test_opt_adam.py
+++ b/pints/tests/test_opt_adam.py
@@ -59,8 +59,8 @@ class TestAdam(unittest.TestCase):
         # Best position and score called before run
         self.assertEqual(list(opt.x_best()), list(x))
         self.assertEqual(list(opt.x_guessed()), list(x))
-        self.assertEqual(opt.f_best(), float('inf'))
-        self.assertEqual(opt.f_guessed(), float('inf'))
+        self.assertEqual(opt.f_best(), np.inf)
+        self.assertEqual(opt.f_guessed(), np.inf)
 
         # Tell before ask
         self.assertRaisesRegex(
diff --git a/pints/tests/test_opt_cmaes.py b/pints/tests/test_opt_cmaes.py
index d979d1e0..7536149d 100755
--- a/pints/tests/test_opt_cmaes.py
+++ b/pints/tests/test_opt_cmaes.py
@@ -120,12 +120,12 @@ class TestCMAES(unittest.TestCase):
         # Best position and score called before run
         self.assertEqual(list(opt.x_best()), list(x))
         self.assertEqual(list(opt.x_guessed()), list(x))
-        self.assertEqual(opt.f_best(), float('inf'))
-        self.assertEqual(opt.f_guessed(), float('inf'))
+        self.assertEqual(opt.f_best(), np.inf)
+        self.assertEqual(opt.f_guessed(), np.inf)
 
         # Test deprecated xbest and fbest
         self.assertEqual(list(opt.xbest()), list(x))
-        self.assertEqual(opt.fbest(), float('inf'))
+        self.assertEqual(opt.fbest(), np.inf)
 
         # Tell before ask
         self.assertRaisesRegex(
diff --git a/pints/tests/test_opt_cmaes_bare.py b/pints/tests/test_opt_cmaes_bare.py
index e977f50a..8f37056b 100755
--- a/pints/tests/test_opt_cmaes_bare.py
+++ b/pints/tests/test_opt_cmaes_bare.py
@@ -82,8 +82,8 @@ class TestBareCMAES(unittest.TestCase):
         # Best position and score called before run
         self.assertEqual(list(opt.x_best()), list(x))
         self.assertEqual(list(opt.x_guessed()), list(x))
-        self.assertEqual(opt.f_best(), float('inf'))
-        self.assertEqual(opt.f_guessed(), float('inf'))
+        self.assertEqual(opt.f_best(), np.inf)
+        self.assertEqual(opt.f_guessed(), np.inf)
 
         # Tell before ask
         self.assertRaisesRegex(
@@ -93,8 +93,8 @@ class TestBareCMAES(unittest.TestCase):
         opt.tell([r(p) for p in opt.ask()])
         self.assertNotEqual(list(opt.x_best()), list(x))
         self.assertNotEqual(list(opt.x_guessed()), list(x))
-        self.assertNotEqual(opt.f_best(), float('inf'))
-        self.assertNotEqual(opt.f_guessed(), float('inf'))
+        self.assertNotEqual(opt.f_best(), np.inf)
+        self.assertNotEqual(opt.f_guessed(), np.inf)
 
     def test_hyper_parameter_interface(self):
         # Tests the hyper parameter interface for this optimiser.
diff --git a/pints/tests/test_opt_gradient_descent.py b/pints/tests/test_opt_gradient_descent.py
index bbe32a6a..bef20622 100755
--- a/pints/tests/test_opt_gradient_descent.py
+++ b/pints/tests/test_opt_gradient_descent.py
@@ -64,8 +64,8 @@ class TestGradientDescent(unittest.TestCase):
         # Best position and score called before run
         self.assertEqual(list(opt.x_best()), list(x))
         self.assertEqual(list(opt.x_guessed()), list(x))
-        self.assertEqual(opt.f_best(), float('inf'))
-        self.assertEqual(opt.f_guessed(), float('inf'))
+        self.assertEqual(opt.f_best(), np.inf)
+        self.assertEqual(opt.f_guessed(), np.inf)
 
         # Tell before ask
         self.assertRaisesRegex(
diff --git a/pints/tests/test_opt_irpropmin.py b/pints/tests/test_opt_irpropmin.py
index 49e01dc4..7f6c79af 100755
--- a/pints/tests/test_opt_irpropmin.py
+++ b/pints/tests/test_opt_irpropmin.py
@@ -77,8 +77,8 @@ class TestIRPropMin(unittest.TestCase):
         # Best position and score called before run
         self.assertEqual(list(opt.x_best()), list(x))
         self.assertEqual(list(opt.x_guessed()), list(x))
-        self.assertEqual(opt.f_best(), float('inf'))
-        self.assertEqual(opt.f_guessed(), float('inf'))
+        self.assertEqual(opt.f_best(), np.inf)
+        self.assertEqual(opt.f_guessed(), np.inf)
 
         # Tell before ask
         self.assertRaisesRegex(
diff --git a/pints/tests/test_opt_nelder_mead.py b/pints/tests/test_opt_nelder_mead.py
index 32b48d9b..8ea16949 100755
--- a/pints/tests/test_opt_nelder_mead.py
+++ b/pints/tests/test_opt_nelder_mead.py
@@ -68,8 +68,8 @@ class TestNelderMead(unittest.TestCase):
         # Best position and score called before run
         self.assertEqual(list(opt.x_best()), list(x))
         self.assertEqual(list(opt.x_guessed()), list(x))
-        self.assertEqual(opt.f_best(), float('inf'))
-        self.assertEqual(opt.f_guessed(), float('inf'))
+        self.assertEqual(opt.f_best(), np.inf)
+        self.assertEqual(opt.f_guessed(), np.inf)
 
         # Not running
         self.assertFalse(opt.running())
diff --git a/pints/tests/test_opt_pso.py b/pints/tests/test_opt_pso.py
index bd898b63..9b9795a2 100755
--- a/pints/tests/test_opt_pso.py
+++ b/pints/tests/test_opt_pso.py
@@ -84,8 +84,8 @@ class TestPSO(unittest.TestCase):
         # Best position and score called before run
         self.assertEqual(list(opt.x_best()), list(x))
         self.assertEqual(list(opt.x_guessed()), list(x))
-        self.assertEqual(opt.f_best(), float('inf'))
-        self.assertEqual(opt.f_guessed(), float('inf'))
+        self.assertEqual(opt.f_best(), np.inf)
+        self.assertEqual(opt.f_guessed(), np.inf)
 
         # Tell before ask
         self.assertRaisesRegex(
diff --git a/pints/tests/test_opt_snes.py b/pints/tests/test_opt_snes.py
index 0874ac48..e164c985 100755
--- a/pints/tests/test_opt_snes.py
+++ b/pints/tests/test_opt_snes.py
@@ -94,8 +94,8 @@ class TestSNES(unittest.TestCase):
         # Best position and score called before run
         self.assertEqual(list(opt.x_best()), list(x))
         self.assertEqual(list(opt.x_guessed()), list(x))
-        self.assertEqual(opt.f_best(), float('inf'))
-        self.assertEqual(opt.f_guessed(), float('inf'))
+        self.assertEqual(opt.f_best(), np.inf)
+        self.assertEqual(opt.f_guessed(), np.inf)
 
         # Tell before ask
         self.assertRaisesRegex(
@@ -105,8 +105,8 @@ class TestSNES(unittest.TestCase):
         opt.tell([r(p) for p in opt.ask()])
         self.assertNotEqual(list(opt.x_best()), list(x))
         self.assertNotEqual(list(opt.x_guessed()), list(x))
-        self.assertNotEqual(opt.f_best(), float('inf'))
-        self.assertNotEqual(opt.f_guessed(), float('inf'))
+        self.assertNotEqual(opt.f_best(), np.inf)
+        self.assertNotEqual(opt.f_guessed(), np.inf)
 
     def test_name(self):
         # Test the name() method.
diff --git a/pints/tests/test_opt_xnes.py b/pints/tests/test_opt_xnes.py
index f2c72409..a441900f 100755
--- a/pints/tests/test_opt_xnes.py
+++ b/pints/tests/test_opt_xnes.py
@@ -95,8 +95,8 @@ class TestXNES(unittest.TestCase):
         # Best position and score called before run
         self.assertEqual(list(opt.x_best()), list(x))
         self.assertEqual(list(opt.x_guessed()), list(x))
-        self.assertEqual(opt.f_best(), float('inf'))
-        self.assertEqual(opt.f_guessed(), float('inf'))
+        self.assertEqual(opt.f_best(), np.inf)
+        self.assertEqual(opt.f_guessed(), np.inf)
 
         # Tell before ask
         self.assertRaisesRegex(
@@ -106,8 +106,8 @@ class TestXNES(unittest.TestCase):
         opt.tell([r(p) for p in opt.ask()])
         self.assertNotEqual(list(opt.x_best()), list(x))
         self.assertNotEqual(list(opt.x_guessed()), list(x))
-        self.assertNotEqual(opt.f_best(), float('inf'))
-        self.assertNotEqual(opt.f_guessed(), float('inf'))
+        self.assertNotEqual(opt.f_best(), np.inf)
+        self.assertNotEqual(opt.f_guessed(), np.inf)
 
     def test_name(self):
         # Test the name() method.
diff --git a/pints/tests/test_plot.py b/pints/tests/test_plot.py
index 88ab379d..b52c572a 100755
--- a/pints/tests/test_plot.py
+++ b/pints/tests/test_plot.py
@@ -279,14 +279,6 @@ class TestPlot(unittest.TestCase):
         names = ['some_name'] * len(self.real_parameters)
         pints.plot.histogram(few_samples, parameter_names=names)
 
-        # Check invalid samples input
-        self.assertRaisesRegex(
-            ValueError,
-            r'All samples must have the same number of parameters\.',
-            pints.plot.histogram,
-            [self.samples[0, :, :], self.samples[1:, :, :-1]]
-        )
-
         # Check invalid parameter_names input
         self.assertRaisesRegex(
             ValueError,
diff --git a/pints/tests/test_toy_multimodal_gaussian_logpdf.py b/pints/tests/test_toy_multimodal_gaussian_logpdf.py
index 9cb3f3cd..0abd8ff8 100755
--- a/pints/tests/test_toy_multimodal_gaussian_logpdf.py
+++ b/pints/tests/test_toy_multimodal_gaussian_logpdf.py
@@ -32,7 +32,7 @@ class TestMultimodalGaussianLogPDF(unittest.TestCase):
         self.assertTrue(f3 < f1)
         f4 = f([0, -0.1])
         self.assertTrue(f4 < f1)
-        self.assertEqual(f([1e6, 1e6]), -float('inf'))
+        self.assertEqual(f([1e6, 1e6]), -np.inf)
         # Note: This is very basic testing, real tests are done in scipy!
 
         # Single mode, 3d, standard covariance
@@ -89,6 +89,16 @@ class TestMultimodalGaussianLogPDF(unittest.TestCase):
             ValueError, pints.toy.MultimodalGaussianLogPDF,
             [[1, 0], [1, 0]], [[[1, 0], [0, 1]], [[1, 1.1], [1.1, 1]]])
 
+        with self.assertRaisesRegex(ValueError, 'Covariance matrices must'):
+            pints.toy.MultimodalGaussianLogPDF(
+                modes=[[10, 1], [10, 1], [10, 1]],
+                covariances=[
+                    [1, 1, 1, 1],
+                    [1, 1, 1, 1],
+                    [1, 1, 1, 1]
+                ]
+            )
+
     def test_sensitivities(self):
         # Tests sensitivities.
 
diff --git a/pints/toy/_multimodal_gaussian.py b/pints/toy/_multimodal_gaussian.py
index 4d91f367..9b9a9013 100644
--- a/pints/toy/_multimodal_gaussian.py
+++ b/pints/toy/_multimodal_gaussian.py
@@ -99,7 +99,7 @@ class MultimodalGaussianLogPDF(ToyLogPDF):
 
     def __call__(self, x):
         f = np.sum([var.pdf(x) for var in self._vars])
-        return -float('inf') if f == 0 else np.log(f)
+        return -np.inf if f == 0 else np.log(f)
 
     def distance(self, samples):
         """
@@ -146,7 +146,7 @@ class MultimodalGaussianLogPDF(ToyLogPDF):
         best_mode = np.zeros(samples.shape[0])
         for i in range(samples.shape[0]):
             a_sample = samples[i, :]
-            a_log_pdf = -float('Inf')
+            a_log_pdf = -np.inf
             a_max_index = -1
             for j, var in enumerate(self._vars):
                 a_test_log_pdf = var.logpdf(a_sample)
diff --git a/pints/toy/_simple_egg_box.py b/pints/toy/_simple_egg_box.py
index 12a3425c..8a70c797 100644
--- a/pints/toy/_simple_egg_box.py
+++ b/pints/toy/_simple_egg_box.py
@@ -62,7 +62,7 @@ class SimpleEggBoxLogPDF(ToyLogPDF):
 
     def __call__(self, x):
         f = np.sum([var.pdf(x) for var in self._vars])
-        return -float('inf') if f == 0 else np.log(f)
+        return -np.inf if f == 0 else np.log(f)
 
     def distance(self, samples):
         """
['pints/tests/test_opt_cmaes.py', 'pints/tests/test_mcmc_monomial_gamma_hmc.py', 'pints/tests/test_mcmc_relativistic.py', 'pints/_optimisers/_nelder_mead.py', 'pints/tests/test_mcmc_dram_ac.py', 'pints/tests/test_mcmc_metropolis.py', 'pints/tests/test_opt_nelder_mead.py', 'pints/tests/test_mcmc_differential_evolution.py', 'pints/tests/test_opt_gradient_descent.py', 'pints/_optimisers/_cmaes.py', 'pints/tests/test_mcmc_hamiltonian.py', 'pints/tests/test_opt_pso.py', 'pints/tests/test_toy_multimodal_gaussian_logpdf.py', 'pints/tests/test_mcmc_adaptive.py', 'pints/tests/test_opt_xnes.py', 'pints/tests/test_log_pdfs.py', 'pints/_mcmc/_nuts.py', 'pints/tests/test_opt_adam.py', 'pints/tests/test_mcmc_dream.py', 'pints/_nested/__init__.py', 'pints/tests/test_plot.py', 'pints/tests/test_abc_smc.py', 'examples/stats/custom-prior.ipynb', 'pints/tests/test_error_measures.py', 'pints/toy/_simple_egg_box.py', 'pints/plot/_histogram.py', 'pints/_optimisers/_irpropmin.py', 'pints/_optimisers/_cmaes_bare.py', 'pints/tests/test_mcmc_emcee_hammer.py', 'pints/tests/test_mcmc_nuts.py', 'pints/_optimisers/_snes.py', 'pints/toy/_multimodal_gaussian.py', 'CHANGELOG.md', 'pints/tests/test_opt_cmaes_bare.py', 'pints/tests/test_mcmc_mala.py', 'pints/tests/test_log_priors.py', 'pints/_optimisers/__init__.py', 'pints/_boundaries.py', 'pints/_optimisers/_xnes.py', 'pints/tests/test_opt_snes.py', 'pints/_mcmc/_monomial_gamma_hamiltonian.py', 'pints/_optimisers/_pso.py', 'pints/_optimisers/_gradient_descent.py', 'LICENSE.md', 'pints/_log_pdfs.py', 'pints/tests/test_opt_irpropmin.py', '.github/workflows/unit-test-python-coverage.yml']