diff --git a/.coveragerc b/.coveragerc index 4f333f056..2b1b16ec1 100644 --- a/.coveragerc +++ b/.coveragerc @@ -2,6 +2,7 @@ source = pints omit = pints/tests/* + pints/functionaltests/* [report] exclude_lines = diff --git a/.github/workflows/change-point-tests.yml b/.github/workflows/change-point-tests.yml new file mode 100644 index 000000000..cc5c99f9b --- /dev/null +++ b/.github/workflows/change-point-tests.yml @@ -0,0 +1,58 @@ +name: Change-point testing + +on: + push: + branches: + - issue-1294-functional-testing-module + +jobs: + + run-functional-testing: + name: Change-point testing + runs-on: ubuntu-latest + + steps: + - name: Check out PINTS repository + uses: actions/checkout@v2 + with: + path: 'pints' + + - name: Check out functional-testing-2 repository + uses: actions/checkout@v2 + with: + repository: 'pints-team/functional-testing-2' + ref: 'new-infra' + path: 'functional-testing-2' + token: ${{ secrets.FUNCTIONAL_TESTING_TOKEN }} + + - name: Set up Python 3.8 + uses: actions/setup-python@v1 + with: + python-version: 3.8 + architecture: x64 + + - name: install pints + run: | + python --version + python -m pip install --upgrade pip setuptools wheel + python -m pip install . + working-directory: 'pints' + + - name: install functional-testing-2 + run: | + python -m pip install . + working-directory: 'functional-testing-2' + + - name: run change-point testing + run: | + python run_all_the_things.py + working-directory: 'functional-testing-2' + + - name: commit changes + run: | + git config user.name "github-workflow" + git config user.email "github-workflow" + git add --all + git commit -m "Run of change-point testing" || echo "No changes to commit" + git push + working-directory: 'functional-testing-2' diff --git a/pints/cptests/__init__.py b/pints/cptests/__init__.py new file mode 100644 index 000000000..660173f71 --- /dev/null +++ b/pints/cptests/__init__.py @@ -0,0 +1,52 @@ +# +# Change point tests for PINTS. +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# + +# Import all problem classes straight into this module, so that they can be +# addressed as e.g. pints.cptests.RunMcmcMethodOnAnnulus. +from ._problems import ( # noqa + RunMcmcMethodOnAnnulus, + RunMcmcMethodOnBanana, + RunMcmcMethodOnCone, + RunMcmcMethodOnCorrelatedGaussian, + RunMcmcMethodOnHighDimensionalGaussian, + RunMcmcMethodOnMultimodalGaussian, + RunMcmcMethodOnProblem, + RunMcmcMethodOnTwoDimGaussian, + RunOptimiserOnBoundedFitzhughNagumo, + RunOptimiserOnBoundedUntransformedLogistic, + RunOptimiserOnProblem, + RunOptimiserOnRosenbrockError, + RunOptimiserOnTwoDimParabola, +) + +# Import all test modules (not methods!) directly into this method, so that +# they can be addressed as e.g. +# pints.cptests.dram_acmc.two_dim_gaussian(). +from . import ( # noqa + cmaes, + cmaes_bare, + differential_evolution_mcmc, + dram_acmc, + dream_mcmc, + emcee_hammer_mcmc, + haario_acmc, + haario_bardenet_acmc, + hamiltonian_mcmc, + mala_mcmc, + metropolis_random_walk_mcmc, + monomial_gamma_hamiltonian_mcmc, + no_u_turn_mcmc, + population_mcmc, + relativistic_mcmc, + slice_stepout_mcmc, + slice_doubling_mcmc, +) + + +# Test discovery methods +from ._discovery import tests # noqa diff --git a/pints/cptests/_discovery.py b/pints/cptests/_discovery.py new file mode 100644 index 000000000..92be3d29e --- /dev/null +++ b/pints/cptests/_discovery.py @@ -0,0 +1,40 @@ +# +# Change point test discovery methods for PINTS. +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import inspect + +import pints.cptests as cpt + + +def tests(method=None): + """ + Returns a list of all change point tests, each represented as a tuple + ``(method, test)`` where ``method`` is the PINTS class being tested and + ``test`` is a callable that returns the test results. + + If the optional argument ``method`` is given, only tests for this method + are returned. + """ + # Get all modules imported into this module + modules = [getattr(cpt, x) for x in dir(cpt) if not x.startswith('_')] + modules = [x for x in modules if inspect.ismodule(x)] + + # Look for (explicitly defined) tests + tests = [] + for module in modules: + try: + m_method = module._method + m_tests = module._change_point_tests + except AttributeError: + continue + + if method is None or method == m_method: + for test in m_tests: + tests.append((m_method, test)) + + return tests + diff --git a/pints/cptests/_problems.py b/pints/cptests/_problems.py new file mode 100644 index 000000000..57ad1619d --- /dev/null +++ b/pints/cptests/_problems.py @@ -0,0 +1,435 @@ +# +# Shared problems used in change point testing. +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import numpy as np + +import pints +import pints.toy + + +class RunMcmcMethodOnProblem(object): + """ + Base class for tests that run an MCMC method on a log-PDF. + + Parameters + ---------- + log_pdf : pints.LogPDF + The PDF to sample. Will be passed to a :class:`pints.MCMCController`. + x0 + One or more starting points to be passed to the + :class:`pints.MCMCController`. + sigma0 + One or more ``sigma0`` parameters to be passed to the + :class:`pints.MCMCController`. + method : pints.MCMCSampler + The method to test. Will be passed to the + :class:`pints.MCMCController`. + n_chains : int + The number of chains to run. Will be passed to the + :class:`pints.MCMCController`. + n_iterations : int + The number of iterations to run + n_warmup : int + The number of iterations to discard + method_hyper_parameters : list + A list of hyperparameter values. + + """ + + def __init__(self, log_pdf, x0, sigma0, method, n_chains, n_iterations, + n_warmup, method_hyper_parameters): + self.log_pdf = log_pdf + + controller = pints.MCMCController( + log_pdf, n_chains, x0, sigma0=sigma0, method=method) + controller.set_max_iterations(n_iterations) + controller.set_log_to_screen(False) + set_hyperparameters_for_any_mcmc_class(controller, method, + method_hyper_parameters) + self.chains = run_and_throw_away_warmup(controller, n_warmup) + + def estimate_kld(self): + """ + Estimates the Kullback-Leibler divergence. + + Raises an ``AttributeError`` if the underlying LogPDF does not have a + method ``kl_divergence()``. + """ + chains = np.vstack(self.chains) + return np.mean(self.log_pdf.kl_divergence(chains)) + + def estimate_mean_ess(self): + """ + Estimates the effective sample size (ESS) for each chain and each + parameter and returns the mean ESS for across all chains and + parameters. + """ + # Estimate mean ESS for each chain + n_chains, _, n_parameters = self.chains.shape + ess = np.empty(shape=(n_chains, n_parameters)) + for chain_id, chain in enumerate(self.chains): + ess[chain_id] = pints.effective_sample_size(chain) + + return np.mean(ess) + + def estimate_distance(self): + """ + Estimates a measure of distance between the sampled chains and the true + distribution. + + Raises an ``AttributeError`` if the underlying LogPDF does not have a + method ``distance()``. + """ + return self.log_pdf.distance(np.vstack(self.chains)) + + +class RunMcmcMethodOnTwoDimGaussian(RunMcmcMethodOnProblem): + """ + Tests a given MCMC method on a two-dimensional Gaussian distribution with + means ``[0, 0]`` and sigma ``[1, 1]``. + + For constructor arguments, see :class:`RunMcmcMethodOnProblem`. + """ + + def __init__(self, method, n_chains, n_iterations, n_warmup, + method_hyper_parameters=None): + log_pdf = pints.toy.GaussianLogPDF(mean=[0, 0], sigma=[1, 1]) + + # Get initial parameters + log_prior = pints.ComposedLogPrior( + pints.GaussianLogPrior(mean=0, sd=10), + pints.GaussianLogPrior(mean=0, sd=10)) + x0 = log_prior.sample(n=n_chains) + sigma0 = None + + super().__init__(log_pdf, x0, sigma0, method, n_chains, n_iterations, + n_warmup, method_hyper_parameters) + + +class RunMcmcMethodOnBanana(RunMcmcMethodOnProblem): + """ + Tests a given MCMC method on a two-dimensional + :class:`pints.toy.TwistedGaussianLogPDF` distribution with means + ``[0, 0]``. + + For constructor arguments, see :class:`RunMcmcMethodOnProblem`. + """ + def __init__(self, method, n_chains, n_iterations, n_warmup, + method_hyper_parameters=None): + log_pdf = pints.toy.TwistedGaussianLogPDF(dimension=2, b=0.1) + + # Get initial parameters + log_prior = pints.MultivariateGaussianLogPrior([0, 0], + [[10, 0], [0, 10]]) + x0 = log_prior.sample(n_chains) + sigma0 = np.diag(np.array([1, 3])) + + super().__init__(log_pdf, x0, sigma0, method, n_chains, n_iterations, + n_warmup, method_hyper_parameters) + + +''' +class RunMcmcMethodOnSimpleEggBox(RunMcmcMethodOnProblem): + """ + Tests a given MCMC method on `pints.toy.SimpleEggBoxLogPDF`. + """ + def __init__(self, method, n_chains, n_iterations, n_warmup, + method_hyper_parameters=None): + sigma = 2 + r = 4 + log_pdf = pints.toy.SimpleEggBoxLogPDF(sigma, r) + x0 = np.random.uniform(-15, 15, size=(n_chains, 2)) + sigma0 = None + + super().__init__(log_pdf, x0, sigma0, method, n_chains, n_iterations, + n_warmup, method_hyper_parameters) +''' + + +class RunMcmcMethodOnHighDimensionalGaussian(RunMcmcMethodOnProblem): + """ + Tests a given MCMC method on a 20-dimensional + :class:`pints.toy.HighDimensionalGaussianLogPDF` centered at the origin. + + For constructor arguments, see :class:`RunMcmcMethodOnProblem`. + """ + def __init__(self, method, n_chains, n_iterations, n_warmup, + method_hyper_parameters=None): + log_pdf = pints.toy.HighDimensionalGaussianLogPDF() + x0 = np.random.uniform(-4, 4, size=(n_chains, 20)) + sigma0 = None + + super().__init__(log_pdf, x0, sigma0, method, n_chains, n_iterations, + n_warmup, method_hyper_parameters) + + +class RunMcmcMethodOnCorrelatedGaussian(RunMcmcMethodOnProblem): + """ + Tests a given MCMC method on a 6-dimensional, highly correlated + :class:`pints.toy.HighDimensionalGaussianLogPDF` centered at the origin. + + For constructor arguments, see :class:`RunMcmcMethodOnProblem`. + """ + def __init__(self, method, n_chains, n_iterations, n_warmup, + method_hyper_parameters=None): + log_pdf = pints.toy.HighDimensionalGaussianLogPDF(dimension=6, rho=0.8) + x0 = np.random.uniform(-4, 4, size=(n_chains, 6)) + sigma0 = None + + super().__init__(log_pdf, x0, sigma0, method, n_chains, n_iterations, + n_warmup, method_hyper_parameters) + + +class RunMcmcMethodOnAnnulus(RunMcmcMethodOnProblem): + """ + Tests a given MCMC method on a two-dimensional + :class:`pints.toy.AnnulusLogPDF` distribution, with its highest values at + any point ``x`` with ``np.linalg.norm(x) == 10``. + + For constructor arguments, see :class:`RunMcmcMethodOnProblem`. + """ + def __init__(self, method, n_chains, n_iterations, n_warmup, + method_hyper_parameters=None): + log_pdf = pints.toy.AnnulusLogPDF() + x0 = log_pdf.sample(n_chains) + sigma0 = None + + super().__init__(log_pdf, x0, sigma0, method, n_chains, n_iterations, + n_warmup, method_hyper_parameters) + + +class RunMcmcMethodOnMultimodalGaussian(RunMcmcMethodOnProblem): + """ + Tests a given MCMC method on a two-dimensional + :class:`pints.toy.MultimodalGaussianLogPDF` with modes at ``[0, 0]``, + ``[5, 10]``, and ``[10, 0]``. + + For constructor arguments, see :class:`RunMcmcMethodOnProblem`. + """ + def __init__(self, method, n_chains, n_iterations, n_warmup, + method_hyper_parameters=None): + modes = [[0, 0], + [5, 10], + [10, 0]] + covariances = [[[1, 0], [0, 1]], + [[2, 0.8], [0.8, 3]], + [[1, -0.5], [-0.5, 1]]] + log_pdf = pints.toy.MultimodalGaussianLogPDF(modes, covariances) + x0 = log_pdf.sample(n_chains) + sigma0 = None + + super().__init__(log_pdf, x0, sigma0, method, n_chains, n_iterations, + n_warmup, method_hyper_parameters) + + +class RunMcmcMethodOnCone(RunMcmcMethodOnProblem): + """ + Tests a given MCMC method on a two-dimensional + :class:`pints.toy,ConeLogPDF` centered at ``[0, 0]``. + + For constructor arguments, see :class:`RunMcmcMethodOnProblem`. + """ + def __init__(self, method, n_chains, n_iterations, n_warmup, + method_hyper_parameters=None): + log_pdf = pints.toy.ConeLogPDF(dimensions=2, beta=0.6) + x0 = log_pdf.sample(n_chains) + sigma0 = None + + super().__init__(log_pdf, x0, sigma0, method, n_chains, n_iterations, + n_warmup, method_hyper_parameters) + + +class RunOptimiserOnProblem(object): + """ + Base class for tests that run an optimiser on an error function or log-PDF. + + Parameters + ---------- + error : pints.Error or pints.LogPDF + The function to opimise. Will be passed to a + :class:`pints.OptimisationController`. + x0 + A starting point to be passed to the controller. + sigma0 + An optional ``sigma0`` argument to pass to the controller. + method : pints.Optimiser + The method to test. + n_iterations : int + The number of iterations to run. + use_guessed : bool + Set to true to use ``f_guessed_tracking`` (see + :meth:`Optimiser.set_f_guessed_tracking`). + method_hyper_parameters : list + A list of hyperparameter values. + + """ + + def __init__(self, error, x0, sigma0, boundaries, transformation, method, + xtrue, n_iterations, use_guessed=False, + method_hyper_parameters=None): + self._error = error + self._xtrue = pints.vector(xtrue) + + controller = pints.OptimisationController( + error, x0, sigma0, boundaries, transformation, method) + controller.set_max_iterations(n_iterations) + controller.set_max_unchanged_iterations(None) + controller.set_log_to_screen(False) + if use_guessed: + controller.set_f_guessed_tracking(True) + if method_hyper_parameters is not None: + controller.optimiser().set_hyperparameters(method_hyper_parameters) + self._x, self._f = controller.run() + + def distance(self): + """ + Calculates the distance between the obtained solution and the true + solution. + """ + return np.sqrt(np.sum((self._x - self._xtrue)**2)) + + def error(self): + """ + Returns the final error. + """ + return self._f + + +class RunOptimiserOnBoundedFitzhughNagumo(RunOptimiserOnProblem): + """ + Tests a given Optimiser on a fully observable (multi-output) + Fitzhugh-Nagumo model, using boundaries but no transformations (the scales + of the parameters are relatively similar). + """ + def __init__(self, method, n_iterations, use_guessed=False, + method_hyper_parameters=None): + + # Choose starting point. The loss surface does not suggest any sensible + # way to do this, so just sampling in a small sphere around a chosen x. + x0 = [0.75, 1.5, 3] # Center + r = np.random.uniform(0, 0.2) # Sphere radius + t = np.random.uniform(0, 2 * np.pi) + p = np.random.uniform(0, 2 * np.pi) + x0[0] += r * np.sin(t) * np.cos(p) + x0[1] += r * np.sin(t) * np.sin(p) + x0[2] += r * np.cos(t) + # Note that this is not a uniform sampling from the sphere! + sigma0 = 0.05 + + # Create a seeded generator to get consistent noise + r = np.random.default_rng(1) + + # Create problem + model = pints.toy.FitzhughNagumoModel() + xtrue = model.suggested_parameters() + times = model.suggested_times() + values = model.simulate(xtrue, times) + values += r.normal(0, 0.25, values.shape) + problem = pints.MultiOutputProblem(model, times, values) + error = pints.SumOfSquaresError(problem) + + # Add boundaries + boundaries = pints.RectangularBoundaries( + [1e-3, 1e-3, 1e-3], [2, 2, 10]) + + super().__init__(error, x0, sigma0, boundaries, None, method, xtrue, + n_iterations, use_guessed, method_hyper_parameters) + + +class RunOptimiserOnBoundedUntransformedLogistic(RunOptimiserOnProblem): + """ + Tests a given Optimiser on a logistic model inference problem with + boundaries and very different scalings for the parameters (no sigma0 + information is given). + """ + def __init__(self, method, n_iterations, use_guessed=False, + method_hyper_parameters=None): + # Choose starting point + # For the default parameters, the contours of the score function with + # x[1] = 15 are almost horizontal after x[0] = 0.1, so we can fix Y and + # vary X to get starting points with similar errors. + x0 = np.array([np.random.uniform(0.15, 9), 15]) + + # Create random generator to add consistent noise + r = np.random.default_rng(1) + + # Create problem + model = pints.toy.LogisticModel() + xtrue = model.suggested_parameters() + times = model.suggested_times() + values = model.simulate(xtrue, times) + values += r.normal(0, 5, values.shape) + problem = pints.SingleOutputProblem(model, times, values) + error = pints.SumOfSquaresError(problem) + + # Add boundaries + boundaries = pints.RectangularBoundaries([0, 0.5], [10, 100]) + + super().__init__(error, x0, None, boundaries, None, method, xtrue, + n_iterations, use_guessed, method_hyper_parameters) + + +class RunOptimiserOnRosenbrockError(RunOptimiserOnProblem): + """ + Tests a given Optimiser on a Rosenbrock error, starting from a randomly + sampled point with error 10. + + For constructor arguments, see :class:`RunOptimiserOnProblem`. + """ + + def __init__(self, method, n_iterations, use_guessed=False, + method_hyper_parameters=None): + + # Choose starting point + c = 10 + x = np.random.uniform(-1, 3) + y = np.sqrt((c - (1 - x)**2) / 100) + x**2 + x0 = np.array([x, y]) + sigma0 = 0.1 + + # Create error + e = pints.toy.RosenbrockError() + x = e.optimum() + super().__init__(e, x0, sigma0, None, None, method, x, n_iterations, + use_guessed, method_hyper_parameters) + + +class RunOptimiserOnTwoDimParabola(RunOptimiserOnProblem): + """ + Tests a given Optimiser on a two-dimensional parabola with mean ``[0, 0]``, + starting at a randomly chosen point 10 distance units away. + + For constructor arguments, see :class:`RunOptimiserOnProblem`. + """ + + def __init__(self, method, n_iterations, use_guessed=False, + method_hyper_parameters=None): + x = np.array([0, 0]) + e = pints.toy.ParabolicError(x) + t = np.random.uniform(0, 2 * np.pi) + x0 = 10 * np.array([np.cos(t), np.sin(t)]) + sigma0 = 1 + super().__init__(e, x0, sigma0, None, None, method, x, n_iterations, + use_guessed, method_hyper_parameters) + + +def run_and_throw_away_warmup(controller, n_warmup): + """ Runs sampling then throws away warmup. """ + chains = controller.run() + return chains[:, n_warmup:] + + +def set_hyperparameters_for_any_mcmc_class(controller, method, + method_hyper_parameters): + """ Sets hyperparameters for any MCMC class. """ + if method_hyper_parameters is not None: + if issubclass(method, pints.MultiChainMCMC): + controller.sampler().set_hyper_parameters( + method_hyper_parameters) + else: + for sampler in controller.samplers(): + sampler.set_hyper_parameters(method_hyper_parameters) diff --git a/pints/cptests/cmaes.py b/pints/cptests/cmaes.py new file mode 100644 index 000000000..f16f6bac5 --- /dev/null +++ b/pints/cptests/cmaes.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# +# Change point tests for CMAES. +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def bounded_fitzhugh_nagumo(n_iterations=100): + """ + Tests :class:`pints.CMAES` on a bounded Fitzhugh-Nagumo model, and returns + a dictionary with ``error`` and ``distance``. + + For details of the solved problem, see + :class:`pints.cptests.RunOptimiserOnBoundedUntransformedLogistic`. + """ + problem = cpt.RunOptimiserOnBoundedFitzhughNagumo( + _method, n_iterations, _fguess) + return { + 'error': problem.error(), + 'distance': problem.distance() + } + + +def bounded_untransformed_logistic(n_iterations=300): + """ + Tests :class:`pints.CMAES` on a bounded logistic model without + transformations, and returns a dictionary with ``error`` and ``distance``. + + For details of the solved problem, see + :class:`pints.cptests.RunOptimiserOnBoundedUntransformedLogistic`. + """ + problem = cpt.RunOptimiserOnBoundedUntransformedLogistic( + _method, n_iterations, _fguess) + return { + 'error': problem.error(), + 'distance': problem.distance() + } + + +def rosenbrock(n_iterations=100): + """ + Tests :class:`pints.CMAES` on a Rosenbrock error and returns a dictionary + with ``error`` and ``distance``. + + For details of the solved problem, see + :class:`pints.cptests.RunOptimiserOnRosenbrockError`. + """ + problem = cpt.RunOptimiserOnRosenbrockError(_method, n_iterations, _fguess) + return { + 'error': problem.error(), + 'distance': problem.distance() + } + + +def two_dim_parabola(n_iterations=50): + """ + Tests :class:`pints.CMAES` on a two-dimensional parabolic error and returns + a dictionary with entries ``error`` and ``distance``. + + For details of the solved problem, see + :class:`pints.cptests.RunOptimiserOnTwoDimParabola`. + """ + problem = cpt.RunOptimiserOnTwoDimParabola(_method, n_iterations, _fguess) + return { + 'error': problem.error(), + 'distance': problem.distance() + } + + +_method = pints.CMAES +_fguess = True +_change_point_tests = [ + bounded_fitzhugh_nagumo, + bounded_untransformed_logistic, + rosenbrock, + two_dim_parabola, +] diff --git a/pints/cptests/cmaes_bare.py b/pints/cptests/cmaes_bare.py new file mode 100644 index 000000000..aec1c6fa5 --- /dev/null +++ b/pints/cptests/cmaes_bare.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# +# Change point tests for bare-bones CMAES reimplementation. +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def bounded_fitzhugh_nagumo(n_iterations=100): + """ + Tests :class:`pints.BareCMAES` on a bounded Fitzhugh-Nagumo model, and + returns a dictionary with ``error`` and ``distance``. + + For details of the solved problem, see + :class:`pints.cptests.RunOptimiserOnBoundedUntransformedLogistic`. + """ + problem = cpt.RunOptimiserOnBoundedFitzhughNagumo( + _method, n_iterations, _fguess) + return { + 'error': problem.error(), + 'distance': problem.distance() + } + + +def bounded_untransformed_logistic(n_iterations=300): + """ + Tests :class:`pints.BareCMAES` on a bounded logistic model without + transformations, and returns a dictionary with ``error`` and ``distance``. + + For details of the solved problem, see + :class:`pints.cptests.RunOptimiserOnBoundedUntransformedLogistic`. + """ + problem = cpt.RunOptimiserOnBoundedUntransformedLogistic( + _method, n_iterations, _fguess) + return { + 'error': problem.error(), + 'distance': problem.distance() + } + + +def rosenbrock(n_iterations=100): + """ + Tests :class:`pints.BareCMAES` on a Rosenbrock error and returns a + dictionary with ``error`` and ``distance``. + + For details of the solved problem, see + :class:`pints.cptests.RunOptimiserOnRosenbrockError`. + """ + problem = cpt.RunOptimiserOnRosenbrockError(_method, n_iterations, _fguess) + return { + 'error': problem.error(), + 'distance': problem.distance() + } + + +def two_dim_parabola(n_iterations=50): + """ + Tests :class:`pints.BareCMAES` on a two-dimensional parabolic error and + returns a dictionary with entries ``error`` and ``distance``. + + For details of the solved problem, see + :class:`pints.cptests.RunOptimiserOnTwoDimParabola`. + """ + problem = cpt.RunOptimiserOnTwoDimParabola(_method, n_iterations, _fguess) + return { + 'error': problem.error(), + 'distance': problem.distance() + } + + +_method = pints.BareCMAES +_fguess = True +_change_point_tests = [ + bounded_fitzhugh_nagumo, + bounded_untransformed_logistic, + rosenbrock, + two_dim_parabola, +] diff --git a/pints/cptests/differential_evolution_mcmc.py b/pints/cptests/differential_evolution_mcmc.py new file mode 100644 index 000000000..8ce44b374 --- /dev/null +++ b/pints/cptests/differential_evolution_mcmc.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# +# Change point tests for DifferentialEvolutionMCMC +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def two_dim_gaussian(n_iterations=10000, n_warmup=1000): + """ + Tests :class:`pints.DifferentialEvolutionMCMC` + on a two-dimensional Gaussian distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnTwoDimGaussian`. + """ + problem = cpt.RunMcmcMethodOnTwoDimGaussian( + _method, 10, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def banana(n_iterations=5000, n_warmup=1000): + """ + Tests :class:`pints.DifferentialEvolutionMCMC` + on a two-dimensional "twisted Gaussian" distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnBanana`. + """ + problem = cpt.RunMcmcMethodOnBanana( + _method, 20, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def correlated_gaussian(n_iterations=10000, n_warmup=1000): + """ + Tests :class:`pints.DifferentialEvolutionMCMC` + on a six-dimensional highly correlated Gaussian distribution with true + solution ``[0, 0, 0, 0, 0, 0]`` and returns a dictionary with entries + ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCorrelatedGaussian`. + """ + problem = cpt.RunMcmcMethodOnCorrelatedGaussian( + _method, 20, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def annulus(n_iterations=10000, n_warmup=1000): + """ + Tests :class:`pints.DifferentialEvolutionMCMC` + on a two-dimensional annulus distribution with radius 10, and returns a + dictionary with entries ``distance`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnAnnulus`. + """ + problem = cpt.RunMcmcMethodOnAnnulus( + _method, 10, n_iterations, n_warmup) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +_method = pints.DifferentialEvolutionMCMC +_change_point_tests = [ + annulus, + banana, + correlated_gaussian, + two_dim_gaussian, +] diff --git a/pints/cptests/dram_acmc.py b/pints/cptests/dram_acmc.py new file mode 100644 index 000000000..137c78ddc --- /dev/null +++ b/pints/cptests/dram_acmc.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# +# Change point tests for DramACMC +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def two_dim_gaussian(n_iterations=8000, n_warmup=2000): + """ + Tests :class:`pints.DramACMC` + on a two-dimensional Gaussian distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnTwoDimGaussian`. + """ + problem = cpt.RunMcmcMethodOnTwoDimGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def banana(n_iterations=4000, n_warmup=1000): + """ + Tests :class:`pints.DramACMC` + on a two-dimensional "twisted Gaussian" distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnBanana`. + """ + problem = cpt.RunMcmcMethodOnBanana( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def correlated_gaussian(n_iterations=8000, n_warmup=4000): + """ + Tests :class:`pints.DramACMC` + on a six-dimensional highly correlated Gaussian distribution with true + solution ``[0, 0, 0, 0, 0, 0]`` and returns a dictionary with entries + ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCorrelatedGaussian`. + """ + problem = cpt.RunMcmcMethodOnCorrelatedGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +_method = pints.DramACMC +_change_point_tests = [ + banana, + correlated_gaussian, + two_dim_gaussian, +] diff --git a/pints/cptests/dream_mcmc.py b/pints/cptests/dream_mcmc.py new file mode 100644 index 000000000..0d480a9ef --- /dev/null +++ b/pints/cptests/dream_mcmc.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +# +# Change point tests for DreamMCMC +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def two_dim_gaussian(n_iterations=10000, n_warmup=1000): + """ + Tests :class:`pints.DreamMCMC` + on a two-dimensional Gaussian distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnTwoDimGaussian`. + """ + problem = cpt.RunMcmcMethodOnTwoDimGaussian( + _method, 10, n_iterations, n_warmup) + + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def banana(n_iterations=5000, n_warmup=1000): + """ + Tests :class:`pints.DreamMCMC` + on a two-dimensional "twisted Gaussian" distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnBanana`. + """ + problem = cpt.RunMcmcMethodOnBanana( + _method, 20, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def correlated_gaussian(n_iterations=10000, n_warmup=1000): + """ + Tests :class:`pints.DreamMCMC` + on a six-dimensional highly correlated Gaussian distribution with true + solution ``[0, 0, 0, 0, 0, 0]`` and returns a dictionary with entries + ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCorrelatedGaussian`. + """ + problem = cpt.RunMcmcMethodOnCorrelatedGaussian( + _method, 20, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def annulus(n_iterations=10000, n_warmup=1000): + """ + Tests :class:`pints.DreamMCMC` + on a two-dimensional annulus distribution with radius 10, and returns a + dictionary with entries ``distance`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnAnnulus`. + """ + problem = cpt.RunMcmcMethodOnAnnulus( + _method, 10, n_iterations, n_warmup) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +_method = pints.DreamMCMC +_change_point_tests = [ + annulus, + banana, + correlated_gaussian, + two_dim_gaussian, +] diff --git a/pints/cptests/emcee_hammer_mcmc.py b/pints/cptests/emcee_hammer_mcmc.py new file mode 100644 index 000000000..bd562432e --- /dev/null +++ b/pints/cptests/emcee_hammer_mcmc.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 +# +# Change point tests for EmceeHammerMCMC +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def two_dim_gaussian(n_iterations=10000, n_warmup=1000): + """ + Tests :class:`pints.EmceeHammerMCMC` + on a two-dimensional Gaussian distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnTwoDimGaussian`. + """ + problem = cpt.RunMcmcMethodOnTwoDimGaussian( + _method, 10, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def banana(n_iterations=10000, n_warmup=2000): + """ + Tests :class:`pints.EmceeHammerMCMC` + on a two-dimensional "twisted Gaussian" distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnBanana`. + """ + problem = cpt.RunMcmcMethodOnBanana( + _method, 10, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def correlated_gaussian(n_iterations=8000, n_warmup=4000): + """ + Tests :class:`pints.EmceeHammerMCMC` + on a six-dimensional highly correlated Gaussian distribution with true + solution ``[0, 0, 0, 0, 0, 0]`` and returns a dictionary with entries + ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCorrelatedGaussian`. + """ + problem = cpt.RunMcmcMethodOnCorrelatedGaussian( + _method, 10, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def annulus(n_iterations=4000, n_warmup=2000): + """ + Tests :class:`pints.EmceeHammerMCMC` + on a two-dimensional annulus distribution with radius 10, and returns a + dictionary with entries ``distance`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnAnnulus`. + """ + problem = cpt.RunMcmcMethodOnAnnulus( + _method, 10, n_iterations, n_warmup) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def multimodal_gaussian(n_iterations=10000, n_warmup=1000): + """ + Tests :class:`pints.EmceeHammerMCMC` + on a two-dimensional multi-modal Gaussian distribution with modes at + ``[0, 0]``, ``[5, 10]``, and ``[10, 0]``, and returns a dict with entries + "kld" and "mean-ess". + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnMultimodalGaussian`. + """ + problem = cpt.RunMcmcMethodOnMultimodalGaussian( + _method, 10, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def cone(n_iterations=10000, n_warmup=1000): + """ + Tests :class:`pints.EmceeHammerMCMC` + on a two-dimensional cone distribution centered at ``[0, 0]``, and returns + a dict with entries "distance" and "mean-ess". + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCone`. + """ + problem = cpt.RunMcmcMethodOnCone( + _method, 10, n_iterations, n_warmup) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +_method = pints.EmceeHammerMCMC +_change_point_tests = [ + annulus, + banana, + cone, + correlated_gaussian, + multimodal_gaussian, + two_dim_gaussian, +] diff --git a/pints/cptests/haario_acmc.py b/pints/cptests/haario_acmc.py new file mode 100644 index 000000000..f0b3feb88 --- /dev/null +++ b/pints/cptests/haario_acmc.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# +# Change point tests for HaarioACMC +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def two_dim_gaussian(n_iterations=4000, n_warmup=1000): + """ + Tests :class:`pints.HaarioACMC` + on a two-dimensional Gaussian distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnTwoDimGaussian`. + """ + problem = cpt.RunMcmcMethodOnTwoDimGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def banana(n_iterations=4000, n_warmup=1000): + """ + Tests :class:`pints.HaarioACMC` + on a two-dimensional "twisted Gaussian" distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnBanana`. + """ + problem = cpt.RunMcmcMethodOnBanana( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def correlated_gaussian(n_iterations=8000, n_warmup=4000): + """ + Tests :class:`pints.HaarioACMC` + on a six-dimensional highly correlated Gaussian distribution with true + solution ``[0, 0, 0, 0, 0, 0]`` and returns a dictionary with entries + ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCorrelatedGaussian`. + """ + problem = cpt.RunMcmcMethodOnCorrelatedGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +_method = pints.HaarioACMC +_change_point_tests = [ + banana, + correlated_gaussian, + two_dim_gaussian, +] + diff --git a/pints/cptests/haario_bardenet_acmc.py b/pints/cptests/haario_bardenet_acmc.py new file mode 100644 index 000000000..e9b6a9256 --- /dev/null +++ b/pints/cptests/haario_bardenet_acmc.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# +# Change point tests for HaarioBardenetACMC +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def two_dim_gaussian(n_iterations=4000, n_warmup=1000): + """ + Tests :class:`pints.HaarioBardenetACMC` + on a two-dimensional Gaussian distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnTwoDimGaussian`. + """ + problem = cpt.RunMcmcMethodOnTwoDimGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def banana(n_iterations=4000, n_warmup=1000): + """ + Tests :class:`pints.HaarioBardenetACMC` + on a two-dimensional "twisted Gaussian" distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnBanana`. + """ + problem = cpt.RunMcmcMethodOnBanana( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def correlated_gaussian(n_iterations=8000, n_warmup=4000): + """ + Tests :class:`pints.HaarioBardenetACMC` + on a six-dimensional highly correlated Gaussian distribution with true + solution ``[0, 0, 0, 0, 0, 0]`` and returns a dictionary with entries + ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCorrelatedGaussian`. + """ + problem = cpt.RunMcmcMethodOnCorrelatedGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def annulus(n_iterations=4000, n_warmup=2000): + """ + Tests :class:`pints.HaarioBardenetACMC` + on a two-dimensional annulus distribution with radius 10, and returns a + dictionary with entries ``distance`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnAnnulus`. + """ + problem = cpt.RunMcmcMethodOnAnnulus( + _method, 4, n_iterations, n_warmup) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +_method = pints.HaarioBardenetACMC +_change_point_tests = [ + annulus, + banana, + correlated_gaussian, + two_dim_gaussian, +] diff --git a/pints/cptests/hamiltonian_mcmc.py b/pints/cptests/hamiltonian_mcmc.py new file mode 100644 index 000000000..1cd7e3f63 --- /dev/null +++ b/pints/cptests/hamiltonian_mcmc.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 +# +# Change point tests for HamiltonianMCMC +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def two_dim_gaussian(n_iterations=1000, n_warmup=200): + """ + Tests :class:`pints.HamiltonianMCMC` + on a two-dimensional Gaussian distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnTwoDimGaussian`. + """ + problem = cpt.RunMcmcMethodOnTwoDimGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 0.5] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def correlated_gaussian(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.HamiltonianMCMC` + on a six-dimensional highly correlated Gaussian distribution with true + solution ``[0, 0, 0, 0, 0, 0]`` and returns a dictionary with entries + ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCorrelatedGaussian`. + """ + problem = cpt.RunMcmcMethodOnCorrelatedGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 0.5] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def banana(n_iterations=2000, n_warmup=1000): + """ + Tests :class:`pints.HamiltonianMCMC` + on a two-dimensional "twisted Gaussian" distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnBanana`. + """ + problem = cpt.RunMcmcMethodOnBanana( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 0.5] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def high_dim_gaussian(n_iterations=4000, n_warmup=1000): + """ + Tests :class:`pints.HamiltonianMCMC` + on a 20-dimensional Gaussian distribution centered at the origin, and + returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnHighDimensionalGaussian`. + """ + problem = cpt.RunMcmcMethodOnHighDimensionalGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 0.5] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def annulus(n_iterations=5000, n_warmup=1000): + """ + Tests :class:`pints.HamiltonianMCMC` + on a two-dimensional annulus distribution with radius 10, and returns a + dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnAnnulus`. + """ + problem = cpt.RunMcmcMethodOnAnnulus( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 0.5] + ) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def multimodal_gaussian(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.HamiltonianMCMC` + on a two-dimensional multi-modal Gaussian distribution with modes at + ``[0, 0]``, ``[5, 10]``, and ``[10, 0]``, and returns a dict with entries + "kld" and "mean-ess". + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnMultimodalGaussian`. + """ + problem = cpt.RunMcmcMethodOnMultimodalGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 0.5] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def cone(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.MonomialGammaHamiltonianMCMC` + on a two-dimensional cone distribution centered at ``[0, 0]``, and returns + a dict with entries "distance" and "mean-ess". + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCone`. + """ + problem = cpt.RunMcmcMethodOnCone( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 0.5] + ) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +_method = pints.HamiltonianMCMC +_change_point_tests = [ + annulus, + banana, + cone, + correlated_gaussian, + high_dim_gaussian, + multimodal_gaussian, + two_dim_gaussian, +] diff --git a/pints/cptests/mala_mcmc.py b/pints/cptests/mala_mcmc.py new file mode 100644 index 000000000..2c8910727 --- /dev/null +++ b/pints/cptests/mala_mcmc.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 +# +# Functional tests for MALA MCMC +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def two_dim_gaussian(n_iterations=1000, n_warmup=200): + """ + Tests :class:`pints.MALAMCMC` + on a two-dimensional Gaussian distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnTwoDimGaussian`. + """ + problem = cpt.RunMcmcMethodOnTwoDimGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[[1.0, 1.0]] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def banana(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.MALAMCMC` + on a two-dimensional "twisted Gaussian" distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnBanana`. + """ + problem = cpt.RunMcmcMethodOnBanana( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[[0.8] * 2] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def high_dim_gaussian(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.MALAMCMC` + on a 20-dimensional Gaussian distribution centered at the origin, and + returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnHighDimensionalGaussian`. + """ + problem = cpt.RunMcmcMethodOnHighDimensionalGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[[1.2] * 20] + ) + + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def correlated_gaussian(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.MALAMCMC` + on a six-dimensional highly correlated Gaussian distribution with true + solution ``[0, 0, 0, 0, 0, 0]`` and returns a dictionary with entries + ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCorrelatedGaussian`. + """ + problem = cpt.RunMcmcMethodOnCorrelatedGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[[1.0] * 6] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def annulus(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.MALAMCMC` + on a two-dimensional annulus distribution with radius 10, and returns a + dictionary with entries ``distance`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnAnnulus`. + """ + problem = cpt.RunMcmcMethodOnAnnulus( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[[1.2] * 2], + ) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def multimodal_gaussian(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.MALAMCMC` + on a two-dimensional multi-modal Gaussian distribution with modes at + ``[0, 0]``, ``[5, 10]``, and ``[10, 0]``, and returns a dict with entries + "kld" and "mean-ess". + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnMultimodalGaussian`. + """ + problem = cpt.RunMcmcMethodOnMultimodalGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[[2.0] * 2] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def cone(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.MALAMCMC` + on a two-dimensional cone distribution centered at ``[0, 0]``, and returns + a dict with entries "distance" and "mean-ess". + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCone`. + """ + problem = cpt.RunMcmcMethodOnCone( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[[1.0, 1.0]], + ) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +_method = pints.MALAMCMC +_change_point_tests = [ + annulus, + banana, + cone, + correlated_gaussian, + high_dim_gaussian, + multimodal_gaussian, + two_dim_gaussian, +] diff --git a/pints/cptests/metropolis_random_walk_mcmc.py b/pints/cptests/metropolis_random_walk_mcmc.py new file mode 100644 index 000000000..5bd17321b --- /dev/null +++ b/pints/cptests/metropolis_random_walk_mcmc.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# +# Change point tests for MetropolisRandomWalkMCMC +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def two_dim_gaussian(n_iterations=4000, n_warmup=1000): + """ + Tests :class:`pints.MetropolisRandomWalkMCMC` + on a two-dimensional Gaussian distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnTwoDimGaussian`. + """ + problem = cpt.RunMcmcMethodOnTwoDimGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def banana(n_iterations=4000, n_warmup=1000): + """ + Tests :class:`pints.MetropolisRandomWalkMCMC` + on a two-dimensional "twisted Gaussian" distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnBanana`. + """ + problem = cpt.RunMcmcMethodOnBanana( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def correlated_gaussian(n_iterations=8000, n_warmup=4000): + """ + Tests :class:`pints.MetropolisRandomWalkMCMC` + on a six-dimensional highly correlated Gaussian distribution with true + solution ``[0, 0, 0, 0, 0, 0]`` and returns a dictionary with entries + ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCorrelatedGaussian`. + """ + problem = cpt.RunMcmcMethodOnCorrelatedGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +_method = pints.MetropolisRandomWalkMCMC +_change_point_tests = [ + banana, + correlated_gaussian, + two_dim_gaussian, +] diff --git a/pints/cptests/monomial_gamma_hamiltonian_mcmc.py b/pints/cptests/monomial_gamma_hamiltonian_mcmc.py new file mode 100644 index 000000000..d55d929fb --- /dev/null +++ b/pints/cptests/monomial_gamma_hamiltonian_mcmc.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 +# +# Change point tests for MonomialGammaHamiltonianMCMC +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def two_dim_gaussian(n_iterations=1000, n_warmup=200): + """ + Tests :class:`pints.MonomialGammaHamiltonianMCMC` + on a two-dimensional Gaussian distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnTwoDimGaussian`. + """ + problem = cpt.RunMcmcMethodOnTwoDimGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 1, 0.5, 0.2, 1] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def banana(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.MonomialGammaHamiltonianMCMC` + on a two-dimensional "twisted Gaussian" distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnBanana`. + """ + problem = cpt.RunMcmcMethodOnBanana( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 1, 0.5, 0.2, 1] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def high_dim_gaussian(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.MonomialGammaHamiltonianMCMC` + on a 20-dimensional Gaussian distribution centered at the origin, and + returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnHighDimensionalGaussian`. + """ + problem = cpt.RunMcmcMethodOnHighDimensionalGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 1, 0.5, 0.2, 1] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def correlated_gaussian(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.MonomialGammaHamiltonianMCMC` + on a six-dimensional highly correlated Gaussian distribution with true + solution ``[0, 0, 0, 0, 0, 0]`` and returns a dictionary with entries + ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCorrelatedGaussian`. + """ + problem = cpt.RunMcmcMethodOnCorrelatedGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 1, 0.5, 0.2, 1] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def annulus(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.MonomialGammaHamiltonianMCMC` + on a two-dimensional annulus distribution with radius 10, and returns a + dictionary with entries ``distance`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnAnnulus`. + """ + problem = cpt.RunMcmcMethodOnAnnulus( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 1, 0.5, 0.2, 1] + ) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def multimodal_gaussian(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.MonomialGammaHamiltonianMCMC` + on a two-dimensional multi-modal Gaussian distribution with modes at + ``[0, 0]``, ``[5, 10]``, and ``[10, 0]``, and returns a dict with entries + "kld" and "mean-ess". + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnMultimodalGaussian`. + """ + problem = cpt.RunMcmcMethodOnMultimodalGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 1, 0.5, 0.2, 1] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def cone(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.MonomialGammaHamiltonianMCMC` + on a two-dimensional cone distribution centered at ``[0, 0]``, and returns + a dict with entries "distance" and "mean-ess". + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCone`. + """ + problem = cpt.RunMcmcMethodOnCone( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 1, 0.5, 0.2, 1] + ) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +_method = pints.MonomialGammaHamiltonianMCMC +_change_point_tests = [ + annulus, + banana, + cone, + correlated_gaussian, + high_dim_gaussian, + multimodal_gaussian, + two_dim_gaussian, +] diff --git a/pints/cptests/no_u_turn_mcmc.py b/pints/cptests/no_u_turn_mcmc.py new file mode 100644 index 000000000..6e778f552 --- /dev/null +++ b/pints/cptests/no_u_turn_mcmc.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# +# Change point tests for NoUTurnMCMC +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def two_dim_gaussian(n_iterations=1000, n_warmup=200): + """ + Tests :class:`pints.NoUTurnMCMC` + on a two-dimensional Gaussian distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnTwoDimGaussian`. + """ + problem = cpt.RunMcmcMethodOnTwoDimGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def banana(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.NoUTurnMCMC` + on a two-dimensional "twisted Gaussian" distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnBanana`. + """ + problem = cpt.RunMcmcMethodOnBanana( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def high_dim_gaussian(n_iterations=4000, n_warmup=1000): + """ + Tests :class:`pints.NoUTurnMCMC` + on a 20-dimensional Gaussian distribution centered at the origin, and + returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnHighDimensionalGaussian`. + """ + problem = cpt.RunMcmcMethodOnHighDimensionalGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +_method = pints.NoUTurnMCMC +_change_point_tests = [ + banana, + high_dim_gaussian, + two_dim_gaussian, +] diff --git a/pints/cptests/population_mcmc.py b/pints/cptests/population_mcmc.py new file mode 100644 index 000000000..bf445b928 --- /dev/null +++ b/pints/cptests/population_mcmc.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# +# Change point tests for Population MCMC. +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def two_dim_gaussian(n_iterations=20000, n_warmup=500): + """ + Tests :class:`pints.PopulationMCMC` + on a two-dimensional Gaussian distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnTwoDimGaussian`. + """ + problem = cpt.RunMcmcMethodOnTwoDimGaussian( + _method, 1, n_iterations, n_warmup) + + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def banana(n_iterations=20000, n_warmup=5000): + """ + Tests :class:`pints.PopulationMCMC` + on a two-dimensional "twisted Gaussian" distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnBanana`. + """ + problem = cpt.RunMcmcMethodOnBanana( + _method, 1, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def multimodal_gaussian( + n_iterations=20000, n_warmup=500, n_temperatures=None): + """ + Tests :class:`pints.PopulationMCMC` + on a two-dimensional multi-modal Gaussian distribution with modes at + ``[0, 0]``, ``[5, 10]``, and ``[10, 0]``, and returns a dict with entries + "kld" and "mean-ess". + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnMultimodalGaussian`. + """ + method_hyper_parameters = None + if n_temperatures is not None: + method_hyper_parameters = [n_temperatures] + + problem = cpt.RunMcmcMethodOnMultimodalGaussian( + method=_method, + n_chains=1, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=method_hyper_parameters, + ) + + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +_method = pints.PopulationMCMC +_change_point_tests = [ + banana, + multimodal_gaussian, + two_dim_gaussian, +] diff --git a/pints/cptests/relativistic_mcmc.py b/pints/cptests/relativistic_mcmc.py new file mode 100644 index 000000000..2cefeb65f --- /dev/null +++ b/pints/cptests/relativistic_mcmc.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python3 +# +# Change point tests for RelativisticMCMC +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def two_dim_gaussian(n_iterations=1000, n_warmup=200): + """ + Tests :class:`pints.RelativisticMCMC` + on a two-dimensional Gaussian distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnTwoDimGaussian`. + """ + problem = cpt.RunMcmcMethodOnTwoDimGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 1, 0.1, 10] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def banana(n_iterations=5000, n_warmup=500): + """ + Tests :class:`pints.RelativisticMCMC` + on a two-dimensional "twisted Gaussian" distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnBanana`. + """ + problem = cpt.RunMcmcMethodOnBanana( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 1, 0.1, 10] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def high_dim_gaussian(n_iterations=5000, n_warmup=500): + """ + Tests :class:`pints.RelativisticMCMC` + on a 20-dimensional Gaussian distribution centered at the origin, and + returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnHighDimensionalGaussian`. + """ + problem = cpt.RunMcmcMethodOnHighDimensionalGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 1, 0.1, 10] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def correlated_gaussian(n_iterations=5000, n_warmup=500): + """ + Tests :class:`pints.RelativisticMCMC` + on a six-dimensional highly correlated Gaussian distribution with true + solution ``[0, 0, 0, 0, 0, 0]`` and returns a dictionary with entries + ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCorrelatedGaussian`. + """ + problem = cpt.RunMcmcMethodOnCorrelatedGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 1, 0.1, 10] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def annulus(n_iterations=5000, n_warmup=500): + """ + Tests :class:`pints.RelativisticMCMC` + on a two-dimensional annulus distribution with radius 10, and returns a + dictionary with entries ``distance`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnAnnulus`. + """ + problem = cpt.RunMcmcMethodOnAnnulus( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 1, 0.1, 10] + ) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def multimodal_gaussian(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.RelativisticMCMC` + on a two-dimensional multi-modal Gaussian distribution with modes at + ``[0, 0]``, ``[5, 10]``, and ``[10, 0]``, and returns a dict with entries + "kld" and "mean-ess". + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnMultimodalGaussian`. + """ + problem = cpt.RunMcmcMethodOnMultimodalGaussian( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 1, 0.1, 10] + ) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def cone(n_iterations=2000, n_warmup=500): + """ + Tests :class:`pints.RelativisticMCMC` + on a two-dimensional cone distribution centered at ``[0, 0]``, and returns + a dict with entries "distance" and "mean-ess". + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCone`. + """ + problem = cpt.RunMcmcMethodOnCone( + method=_method, + n_chains=4, + n_iterations=n_iterations, + n_warmup=n_warmup, + method_hyper_parameters=[20, 1, 0.1, 10] + ) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +_method = pints.RelativisticMCMC +_change_point_tests = [ + annulus, + banana, + cone, + correlated_gaussian, + high_dim_gaussian, + multimodal_gaussian, + two_dim_gaussian, +] diff --git a/pints/cptests/slice_doubling_mcmc.py b/pints/cptests/slice_doubling_mcmc.py new file mode 100644 index 000000000..21db5c2e3 --- /dev/null +++ b/pints/cptests/slice_doubling_mcmc.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +# +# Change point tests for SliceDoublingMCMC +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def two_dim_gaussian(n_iterations=5000, n_warmup=500): + """ + Tests :class:`pints.SliceDoublingMCMC` + on a two-dimensional Gaussian distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnTwoDimGaussian`. + """ + problem = cpt.RunMcmcMethodOnTwoDimGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def correlated_gaussian(n_iterations=5000, n_warmup=500): + """ + Tests :class:`pints.SliceDoublingMCMC` + on a six-dimensional highly correlated Gaussian distribution with true + solution ``[0, 0, 0, 0, 0, 0]`` and returns a dictionary with entries + ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCorrelatedGaussian`. + """ + problem = cpt.RunMcmcMethodOnCorrelatedGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def high_dim_gaussian(n_iterations=5000, n_warmup=500): + """ + Tests :class:`pints.SliceDoublingMCMC` + on a 20-dimensional Gaussian distribution centered at the origin, and + returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnHighDimensionalGaussian`. + """ + problem = cpt.RunMcmcMethodOnHighDimensionalGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def annulus(n_iterations=10000, n_warmup=2000): + """ + Tests :class:`pints.SliceDoublingMCMC` + on a two-dimensional annulus distribution with radius 10, and returns a + dictionary with entries ``distance`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnAnnulus`. + """ + problem = cpt.RunMcmcMethodOnAnnulus( + _method, 4, n_iterations, n_warmup) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def cone(n_iterations=5000, n_warmup=500): + """ + Tests :class:`pints.SliceDoublingMCMC` + on a two-dimensional cone distribution centered at ``[0, 0]``, and returns + a dict with entries "distance" and "mean-ess". + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCone`. + """ + problem = cpt.RunMcmcMethodOnCone( + _method, 4, n_iterations, n_warmup) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +_method = pints.SliceStepoutMCMC +_change_point_tests = [ + annulus, + cone, + correlated_gaussian, + high_dim_gaussian, + two_dim_gaussian, +] diff --git a/pints/cptests/slice_stepout_mcmc.py b/pints/cptests/slice_stepout_mcmc.py new file mode 100644 index 000000000..b6355ce3e --- /dev/null +++ b/pints/cptests/slice_stepout_mcmc.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +# +# Change point tests for SliceStepoutMCMC +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def two_dim_gaussian(n_iterations=5000, n_warmup=500): + """ + Tests :class:`pints.SliceStepoutMCMC` + on a two-dimensional Gaussian distribution with true solution + ``[0, 0]`` and returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnTwoDimGaussian`. + """ + problem = cpt.RunMcmcMethodOnTwoDimGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def correlated_gaussian(n_iterations=5000, n_warmup=500): + """ + Tests :class:`pints.SliceStepoutMCMC` + on a six-dimensional highly correlated Gaussian distribution with true + solution ``[0, 0, 0, 0, 0, 0]`` and returns a dictionary with entries + ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCorrelatedGaussian`. + """ + problem = cpt.RunMcmcMethodOnCorrelatedGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def high_dim_gaussian(n_iterations=5000, n_warmup=500): + """ + Tests :class:`pints.SliceStepoutMCMC` + on a 20-dimensional Gaussian distribution centered at the origin, and + returns a dictionary with entries ``kld`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnHighDimensionalGaussian`. + """ + problem = cpt.RunMcmcMethodOnHighDimensionalGaussian( + _method, 4, n_iterations, n_warmup) + return { + 'kld': problem.estimate_kld(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def annulus(n_iterations=10000, n_warmup=2000): + """ + Tests :class:`pints.SliceStepoutMCMC` + on a two-dimensional annulus distribution with radius 10, and returns a + dictionary with entries ``distance`` and ``mean-ess``. + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnAnnulus`. + """ + problem = cpt.RunMcmcMethodOnAnnulus( + _method, 4, n_iterations, n_warmup) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +def cone(n_iterations=5000, n_warmup=500): + """ + Tests :class:`pints.SliceStepoutMCMC` + on a two-dimensional cone distribution centered at ``[0, 0]``, and returns + a dict with entries "distance" and "mean-ess". + + For details of the solved problem, see + :class:`pints.cptests.RunMcmcMethodOnCone`. + """ + problem = cpt.RunMcmcMethodOnCone( + _method, 4, n_iterations, n_warmup) + return { + 'distance': problem.estimate_distance(), + 'mean-ess': problem.estimate_mean_ess() + } + + +_method = pints.SliceStepoutMCMC +_change_point_tests = [ + annulus, + cone, + correlated_gaussian, + high_dim_gaussian, + two_dim_gaussian, +] diff --git a/pints/cptests/snes.py b/pints/cptests/snes.py new file mode 100644 index 000000000..2040a95d1 --- /dev/null +++ b/pints/cptests/snes.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +# +# Change point tests for SNES. +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def bounded_fitzhugh_nagumo(n_iterations=100): + """ + Tests :class:`pints.SNES` on a bounded Fitzhugh-Nagumo model, and returns + a dictionary with ``error`` and ``distance``. + + For details of the solved problem, see + :class:`pints.cptests.RunOptimiserOnBoundedUntransformedLogistic`. + """ + problem = cpt.RunOptimiserOnBoundedFitzhughNagumo( + _method, n_iterations, _fguess) + return { + 'error': problem.error(), + 'distance': problem.distance() + } + + +def bounded_untransformed_logistic(n_iterations=300): + """ + Tests :class:`pints.SNES` on a bounded logistic model without + transformations, and returns a dictionary with ``error`` and ``distance``. + + For details of the solved problem, see + :class:`pints.cptests.RunOptimiserOnBoundedUntransformedLogistic`. + """ + problem = cpt.RunOptimiserOnBoundedUntransformedLogistic( + _method, n_iterations, _fguess) + return { + 'error': problem.error(), + 'distance': problem.distance() + } + + +def two_dim_parabola(n_iterations=50): + """ + Tests :class:`pints.SNES` on a two-dimensional parabolic error and returns + a dictionary with entries ``error`` and ``distance``. + + For details of the solved problem, see + :class:`pints.cptests.RunOptimiserOnTwoDimParabola`. + """ + problem = cpt.RunOptimiserOnTwoDimParabola(_method, n_iterations, _fguess) + return { + 'error': problem.error(), + 'distance': problem.distance() + } + + +_method = pints.SNES +_fguess = True +_change_point_tests = [ + bounded_fitzhugh_nagumo, + bounded_untransformed_logistic, + two_dim_parabola, +] diff --git a/pints/cptests/xnes.py b/pints/cptests/xnes.py new file mode 100644 index 000000000..25f1029cf --- /dev/null +++ b/pints/cptests/xnes.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# +# Change point tests for XNES. +# +# This file is part of PINTS (https://github.com/pints-team/pints/) which is +# released under the BSD 3-clause license. See accompanying LICENSE.md for +# copyright notice and full license details. +# +import pints +import pints.cptests as cpt + + +def bounded_fitzhugh_nagumo(n_iterations=100): + """ + Tests :class:`pints.XNES` on a bounded Fitzhugh-Nagumo model, and returns + a dictionary with ``error`` and ``distance``. + + For details of the solved problem, see + :class:`pints.cptests.RunOptimiserOnBoundedUntransformedLogistic`. + """ + problem = cpt.RunOptimiserOnBoundedFitzhughNagumo( + _method, n_iterations, _fguess) + return { + 'error': problem.error(), + 'distance': problem.distance() + } + + +def bounded_untransformed_logistic(n_iterations=300): + """ + Tests :class:`pints.XNES` on a bounded logistic model without + transformations, and returns a dictionary with ``error`` and ``distance``. + + For details of the solved problem, see + :class:`pints.cptests.RunOptimiserOnBoundedUntransformedLogistic`. + """ + problem = cpt.RunOptimiserOnBoundedUntransformedLogistic( + _method, n_iterations, _fguess) + return { + 'error': problem.error(), + 'distance': problem.distance() + } + + +def rosenbrock(n_iterations=100): + """ + Tests :class:`pints.XNES` on a Rosenbrock error and returns a dictionary + with ``error`` and ``distance``. + + For details of the solved problem, see + :class:`pints.cptests.RunOptimiserOnRosenbrockError`. + """ + problem = cpt.RunOptimiserOnRosenbrockError(_method, n_iterations, _fguess) + return { + 'error': problem.error(), + 'distance': problem.distance() + } + + +def two_dim_parabola(n_iterations=50): + """ + Tests :class:`pints.XNES` on a two-dimensional parabolic error and returns + a dictionary with entries ``error`` and ``distance``. + + For details of the solved problem, see + :class:`pints.cptests.RunOptimiserOnTwoDimParabola`. + """ + problem = cpt.RunOptimiserOnTwoDimParabola(_method, n_iterations, _fguess) + return { + 'error': problem.error(), + 'distance': problem.distance() + } + + +_method = pints.XNES +_fguess = True +_change_point_tests = [ + bounded_fitzhugh_nagumo, + bounded_untransformed_logistic, + rosenbrock, + two_dim_parabola, +]