def test_transform(self): # Test optimisation with parameter transformation. # Test with LogPDF r = pints.toy.TwistedGaussianLogPDF(2, 0.01) x0 = np.array([0, 1.01]) b = pints.RectangularBoundaries([-0.01, 0.95], [0.01, 1.05]) s = 0.01 t = pints.RectangularBoundariesTransformation(b) opt = pints.OptimisationController(r, x0, s, b, t, method) opt.set_log_to_screen(False) opt.set_max_unchanged_iterations(None) opt.set_max_iterations(10) opt.run() # Test with ErrorMeasure r = pints.toy.ParabolicError() x0 = [0.1, 0.1] b = pints.RectangularBoundaries([-1, -1], [1, 1]) s = 0.1 t = pints.RectangularBoundariesTransformation(b) pints.OptimisationController(r, x0, boundaries=b, transform=t, method=method) opt = pints.OptimisationController(r, x0, s, b, t, method) opt.set_log_to_screen(False) opt.set_max_unchanged_iterations(None) opt.set_max_iterations(10) x, _ = opt.run() # Test output are detransformed self.assertEqual(x.shape, (2, )) self.assertTrue(b.check(x))
def optimise(self, data, sigma_fac=0.001, method="minimisation"): cmaes_problem = pints.MultiOutputProblem(self, self.frequency_range, data) if method == "likelihood": score = pints.GaussianLogLikelihood(cmaes_problem) sigma = sigma_fac * np.sum(data) / 2 * len(data) lower_bound = [self.param_bounds[x][0] for x in self.params] + [0.1 * sigma] * 2 upper_bound = [self.param_bounds[x][1] for x in self.params] + [10 * sigma] * 2 CMAES_boundaries = pints.RectangularBoundaries( lower_bound, upper_bound) random_init = abs(np.random.rand(self.n_parameters())) x0 = self.change_norm_group(random_init, "un_norm", "list") + [sigma] * 2 cmaes_fitting = pints.OptimisationController( score, x0, sigma0=None, boundaries=CMAES_boundaries, method=pints.CMAES) elif method == "minimisation": score = pints.SumOfSquaresError(cmaes_problem) lower_bound = [self.param_bounds[x][0] for x in self.params] upper_bound = [self.param_bounds[x][1] for x in self.params] CMAES_boundaries = pints.RectangularBoundaries( lower_bound, upper_bound) random_init = abs(np.random.rand(self.n_parameters())) x0 = self.change_norm_group(random_init, "un_norm", "list") cmaes_fitting = pints.OptimisationController( score, x0, sigma0=None, boundaries=CMAES_boundaries, method=pints.CMAES) cmaes_fitting.set_max_unchanged_iterations(iterations=200, threshold=1e-7) #cmaes_fitting.set_log_to_screen(False) cmaes_fitting.set_parallel(True) found_parameters, found_value = cmaes_fitting.run() if method == "likelihood": sim_params = found_parameters[:-2] sim_data = self.simulate(sim_params, self.frequency_range) else: found_value = -found_value sim_params = found_parameters sim_data = self.simulate(sim_params, self.frequency_range) """ log_score = pints.GaussianLogLikelihood(cmaes_problem) stds=self.get_std(data, sim_data) sigma=sigma_fac*np.sum(data)/2*len(data) score_params=list(found_parameters)+[sigma]*2 found_value=log_score(score_params) print(stds, found_value, "stds")""" #DOITDIMENSIONALLY#NORMALISE DEFAULT TO BOUND return found_parameters, found_value, cmaes_fitting._optimiser._es.sm.C, sim_data
def test_creation(self): # Tests creation and input checking # Create boundaries pints.RectangularBoundaries([1, 2], [3, 4]) pints.RectangularBoundaries([1], [2]) pints.RectangularBoundaries(np.array([1, 2, 3]), [4, 5, 6]) pints.RectangularBoundaries(1, 2) # Create invalid boundaries self.assertRaises(ValueError, pints.RectangularBoundaries, [1, 2], [1]) self.assertRaises(ValueError, pints.RectangularBoundaries, [], []) self.assertRaises(ValueError, pints.RectangularBoundaries, [2], [1]) self.assertRaises(ValueError, pints.RectangularBoundaries, [1, 1], [10, 1])
def setUpClass(cls): # Create Transformation class lower1 = np.array([1]) upper1 = np.array([10]) lower2 = np.array([1, 2]) upper2 = np.array([10, 20]) # Test normal construction with lower and upper cls.t1 = pints.RectangularBoundariesTransformation(lower1, upper1) cls.t2 = pints.RectangularBoundariesTransformation(lower2, upper2) # Test construction with rectangular boundaries object b2 = pints.RectangularBoundaries(lower2, upper2) cls.t2b = pints.RectangularBoundariesTransformation(b2) cls.p = [1.5, 15.] cls.x = [-2.8332133440562162, 0.9555114450274365] cls.j = np.diag([0.4722222222222225, 3.6111111111111098]) cls.j_s1_diag = [0.4197530864197533, -1.6049382716049378] cls.j_s1 = np.zeros((2, 2, 2)) for i in range(2): cls.j_s1[i, i, i] = cls.j_s1_diag[i] cls.log_j_det = 0.5337099175995788 cls.log_j_det_s1 = [0.8888888888888888, -0.4444444444444445]
def test_boundary_checking(self): # Check methods lower = [1, -2] upper = [3, 4] b = pints.RectangularBoundaries(lower, upper) self.assertEqual(b.n_parameters(), len(lower)) self.assertTrue(np.all(b.lower() == np.array(lower))) self.assertTrue(np.all(b.upper() == np.array(upper))) self.assertTrue(np.all(b.range() == np.array(upper) - np.array(lower))) # Check checking # Within bounds self.assertTrue(b.check([2, 3])) # On a lower bound self.assertTrue(b.check([1, 3])) # Below a lower bound self.assertFalse(b.check([1 - 1e16, 4])) # On an upper bound self.assertFalse(b.check([3, 0])) # Above an upper bound self.assertFalse(b.check([2, 14])) # Wrong in every way self.assertFalse(b.check([-20, 20])) self.assertFalse(b.check([20, -20])) # Negative number self.assertFalse(b.check([2, -3]))
def setUpClass(cls): """ Prepare problem for tests. """ # Load a forward model model = pints.toy.LogisticModel() # Create some toy data real_parameters = [0.015, 500] times = np.linspace(0, 1000, 1000) org_values = model.simulate(real_parameters, times) # Add noise noise = 10 values = org_values + np.random.normal(0, noise, org_values.shape) real_parameters = np.array(real_parameters + [noise]) # Create an object with links to the model and time series problem = pints.SingleOutputProblem(model, times, values) # Create an error measure cls.score = pints.SumOfSquaresError(problem) cls.boundaries = pints.RectangularBoundaries([0, 400], [0.05, 600]) # Create a log-likelihood function (adds an extra parameter!) log_likelihood = pints.GaussianLogLikelihood(problem) # Create a uniform prior over both the parameters and the new noise cls.log_prior = pints.UniformLogPrior([0.01, 400, noise * 0.1], [0.02, 600, noise * 100]) # Create a posterior log-likelihood (log(likelihood * prior)) cls.log_posterior = pints.LogPosterior(log_likelihood, cls.log_prior)
def test_logging(self): r = pints.toy.TwistedGaussianLogPDF(2, 0.01) x = np.array([0, 1.01]) b = pints.RectangularBoundaries([-0.01, 0.95], [0.01, 1.05]) s = 0.01 opt = pints.OptimisationController(r, x, s, b, method) opt.set_log_to_screen(True) opt.set_max_unchanged_iterations(None) opt.set_log_interval(3) opt.set_max_iterations(10) self.assertEqual(opt.max_iterations(), 10) with StreamCapture() as c: opt.run() log_should_be = ( 'Maximising LogPDF\n' 'using Exponential Natural Evolution Strategy (xNES)\n' 'Running in sequential mode.\n' 'Population size: 6\n' 'Iter. Eval. Best Time m:s\n' '0 6 -4.140462 0:00.0\n' '1 12 -4.140462 0:00.0\n' '2 18 -4.140462 0:00.0\n' '3 24 -4.140462 0:00.0\n' '6 42 -4.140462 0:00.0\n' '9 60 -4.140462 0:00.0\n' '10 60 -4.140462 0:00.0\n' 'Halting: Maximum number of iterations (10) reached.\n' ) self.assertEqual(log_should_be, c.text()) # Invalid log interval self.assertRaises(ValueError, opt.set_log_interval, 0)
def test_parallel(self): # Test parallelised running. r = pints.toy.RosenbrockError() x = np.array([1.1, 1.1]) b = pints.RectangularBoundaries([0.5, 0.5], [1.5, 1.5]) # Run with guessed number of cores opt = pints.OptimisationController(r, x, boundaries=b, method=method) opt.set_max_iterations(10) opt.set_log_to_screen(debug) opt.set_parallel(False) self.assertIs(opt.parallel(), False) opt.set_parallel(True) self.assertTrue(type(opt.parallel()) == int) self.assertTrue(opt.parallel() >= 1) opt.run() # Run with explicit number of cores opt = pints.OptimisationController(r, x, boundaries=b, method=method) opt.set_max_iterations(10) opt.set_log_to_screen(debug) opt.set_parallel(4) self.assertTrue(type(opt.parallel()) == int) self.assertEqual(opt.parallel(), 4) opt.run()
def test_post_run_statistics(self): # Test the methods to return statistics, post-run. r = pints.toy.TwistedGaussianLogPDF(2, 0.01) x = np.array([0, 1.01]) b = pints.RectangularBoundaries([-0.01, 0.95], [0.01, 1.05]) s = 0.01 opt = pints.OptimisationController(r, x, s, b, method=method) opt.set_log_to_screen(False) opt.set_max_unchanged_iterations(50, 1e-11) np.random.seed(123) # Before run methods return None self.assertIsNone(opt.iterations()) self.assertIsNone(opt.evaluations()) self.assertIsNone(opt.time()) t = pints.Timer() opt.run() t_upper = t.time() self.assertEqual(opt.iterations(), 75) self.assertEqual(opt.evaluations(), 450) # Time after run is greater than zero self.assertIsInstance(opt.time(), float) self.assertGreater(opt.time(), 0) self.assertGreater(t_upper, opt.time())
def test_deprecated_alias(self): # Tests Optimisation() r = pints.toy.RosenbrockError() x = np.array([1.1, 1.1]) b = pints.RectangularBoundaries([0.5, 0.5], [1.5, 1.5]) opt = pints.Optimisation(r, x, boundaries=b, method=method) self.assertIsInstance(opt, pints.OptimisationController)
def _problem(self): import numpy as np import pints import pints.toy # Load a forward model model = pints.toy.LogisticModel() # Create some toy data xtrue = [0.015, 500] times = np.linspace(0, 1000, 1000) values = model.simulate(xtrue, times) # Add noise values += np.random.normal(0, 10, values.shape) # Create problem problem = pints.SingleOutputProblem(model, times, values) score = pints.SumOfSquaresError(problem) # Select some boundaries boundaries = pints.RectangularBoundaries([0, 400], [0.03, 600]) # Select a random starting point x0 = boundaries.sample(1)[0] # Select an initial sigma sigma0 = (1 / 6) * boundaries.range() return score, xtrue, x0, sigma0, boundaries
def _problem(self): import numpy as np import pints import pints.toy # Load a forward model model = pints.toy.ActionPotentialModel() # Create some toy data xtrue = model.suggested_parameters() times = model.suggested_times() values = model.simulate(xtrue, times) # Add noise values[:, 0] += np.random.normal(0, 1, values[:, 0].shape) values[:, 1] += np.random.normal(0, 5e-7, values[:, 1].shape) # Create problem and a weighted score function problem = pints.MultiOutputProblem(model, times, values) weights = [1 / 70, 1 / 0.000006] score = pints.SumOfSquaresError(problem, weights=weights) # Select some boundaries lower = xtrue - 2 upper = xtrue + 2 boundaries = pints.RectangularBoundaries(lower, upper) # Select a random starting point x0 = boundaries.sample(1)[0] # Select an initial sigma sigma0 = (1 / 6) * boundaries.range() return score, xtrue, x0, sigma0, boundaries
def _problem(self): import numpy as np import pints import pints.toy # Create a model model = pints.toy.FitzhughNagumoModel() # Run a simulation xtrue = [0.1, 0.5, 3] times = np.linspace(0, 20, 200) values = model.simulate(xtrue, times) # Add some noise sigma = 0.5 noisy = values + np.random.normal(0, sigma, values.shape) # Create problem problem = pints.MultiOutputProblem(model, times, noisy) score = pints.SumOfSquaresError(problem) # Select boundaries boundaries = pints.RectangularBoundaries([0, 0, 0], [10, 10, 10]) # Select a random starting point x0 = boundaries.sample(1)[0] # Select an initial sigma sigma0 = (1 / 6) * boundaries.range() return score, xtrue, x0, sigma0, boundaries
def test_set_parameter_boundaries(self): """Tests whether setting boundaries for inference works as expected. """ problem = inf.SingleOutputInverseProblem( models=[self.linear_model], times=[self.times], values=[self.linear_model_data]) # Test Case I: no boundaries provided # define boundaries boundaries = None # set boundaries problem.set_parameter_boundaries(boundaries=boundaries) # assert that boundaries are set properly assert problem.parameter_boundaries is None # Test Case II: boundaries are provided # define boundaries min_values = [0, 0] max_values = [3, 3] boundaries = pints.RectangularBoundaries(min_values, max_values) # set boundaries problem.set_parameter_boundaries(boundaries=[min_values, max_values]) # assert that boundaries are set properly assert isinstance(problem.parameter_boundaries, type(boundaries))
def problem(self): """ Returns a test problem, starting point, sigma, and boundaries. """ r = pints.toy.ParabolicError() x = [0.1, 0.1] s = 0.1 b = pints.RectangularBoundaries([-1, -1], [1, 1]) return r, x, s, b
def set_parameter_boundaries(self, boundaries:List): """Sets the parameter boundaries for inference. Arguments: boundaries {List} -- List of two lists. [min values, max values] """ min_values, max_values = boundaries[0], boundaries[1] self.parameter_boundaries = pints.RectangularBoundaries(min_values, max_values)
def test_optimise(self): """ Tests :meth: `pints.optimise()`. """ r = pints.toy.TwistedGaussianLogPDF(2, 0.01) x = np.array([0, 1.01]) s = 0.01 b = pints.RectangularBoundaries([-0.01, 0.95], [0.01, 1.05]) with StreamCapture(): x, f = pints.optimise(r, x, s, b, method=pints.XNES) self.assertEqual(x.shape, (2, )) self.assertTrue(f < 1e-6)
def test_stopping_no_criterion(self): """ Tries to run an optimisation with the no stopping criterion. """ r = pints.toy.TwistedGaussianLogPDF(2, 0.01) x = np.array([0, 1.01]) b = pints.RectangularBoundaries([-0.01, 0.95], [0.01, 1.05]) s = 0.01 opt = pints.OptimisationController(r, x, s, b, method) opt.set_log_to_screen(debug) opt.set_max_iterations(None) opt.set_max_unchanged_iterations(None) self.assertRaises(ValueError, opt.run)
def test_deprecated_alias(self): # Tests Optimisation() r = pints.toy.RosenbrockError() x = np.array([1.1, 1.1]) b = pints.RectangularBoundaries([0.5, 0.5], [1.5, 1.5]) with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') opt = pints.Optimisation(r, x, boundaries=b, method=method) self.assertEqual(len(w), 1) self.assertIn('deprecated', str(w[-1].message)) self.assertIsInstance(opt, pints.OptimisationController)
def set_parameter_boundaries(self, boundaries:List): """Sets the parameter boundaries for inference. Arguments: boundaries {List} -- List of two lists. [min values, max values] """ print('boundaries are ' + str(boundaries)) if boundaries is None: self.parameter_boundaries = None else: min_values, max_values = boundaries[0], boundaries[1] self.parameter_boundaries = pints.RectangularBoundaries(min_values, max_values)
def test_rectangular_boundaries(self): # Create boundaries pints.RectangularBoundaries([1, 2], [3, 4]) pints.RectangularBoundaries([1], [2]) pints.RectangularBoundaries(np.array([1, 2, 3]), [4, 5, 6]) pints.RectangularBoundaries(1, 2) # Create invalid boundaries self.assertRaises(ValueError, pints.RectangularBoundaries, [1, 2], [1]) self.assertRaises(ValueError, pints.RectangularBoundaries, [], []) self.assertRaises(ValueError, pints.RectangularBoundaries, [2], [1]) self.assertRaises( ValueError, pints.RectangularBoundaries, [1, 1], [10, 1]) # Check methods lower = [1, -2] upper = [3, 4] b = pints.RectangularBoundaries(lower, upper) self.assertEqual(b.n_parameters(), len(lower)) self.assertTrue(np.all(b.lower() == np.array(lower))) self.assertTrue(np.all(b.upper() == np.array(upper))) self.assertTrue(np.all(b.range() == np.array(upper) - np.array(lower))) # Check checking # Within bounds self.assertTrue(b.check([2, 3])) # On a lower bound self.assertTrue(b.check([1, 3])) # Below a lower bound self.assertFalse(b.check([1 - 1e16, 4])) # On an upper bound self.assertFalse(b.check([3, 0])) # Above an upper bound self.assertFalse(b.check([2, 14])) # Wrong in every way self.assertFalse(b.check([-20, 20])) self.assertFalse(b.check([20, -20])) # Negative number self.assertFalse(b.check([2, -3]))
def optimise(self, x, parallel=False): """ Runs the optimisation, this method: (1) generates simulated data and adds noise (2) sets up the optimiser with the method given, trying to optimise the function f(x) = sum of squared error (3) runs the optimisation (4) returns: - the found parameters x, - the ratio of f(x) / f(x_0), where x_0 are the real parameters - time total time taken divided by the time taken to evaluate a single evaluation of f(x) """ the_model = self.model() print('model = ', the_model) values = the_model.simulate(self.real_parameters, self.times) value_range = np.max(values) - np.min(values) values += np.random.normal(0, self.noise * value_range, values.shape) problem = pints.MultiOutputProblem(the_model, self.times, values) score = pints.SumOfSquaresError(problem) middle = [0.5 * (u + l) for l, u in zip(self.lower, self.upper)] sigma = [(1.0/6.0)*(u - l) for l, u in zip(self.lower, self.upper)] print('sigma = ', sigma) boundaries = pints.RectangularBoundaries(self.lower, self.upper) optimisation = pints.Optimisation( score, middle, sigma0=sigma, boundaries=boundaries, method=self.method ) optimisation.optimiser().set_hyper_parameters(x) if parallel: optimisation.set_parallel(int(os.environ['OMP_NUM_THREADS'])) else: optimisation.set_parallel(False) start = timer() found_parameters, found_value = optimisation.run() end = timer() N = 10 start_score = timer() for i in range(N): minimum_value = score(self.real_parameters) end_score = timer() score_duration = (end_score - start_score) / N return found_parameters, \ found_value / minimum_value, \ (end - start) / score_duration
def test_surface(self): # Choose some points np.random.seed(1) points = np.random.normal(-2, 10, [100, 2]) values = np.random.uniform(0, 10, len(points)) # Check that duplicate points are handled points[:-10] = points[10:] # Create a plot pints.plot.surface(points, values) # Create a plot with boundaries b = pints.RectangularBoundaries([3, 5], [8, 7]) pints.plot.surface(points, values, b) # Points must be 2-dimensional bad_points = np.random.uniform(-2, 10, [20, 3]) self.assertRaisesRegex( ValueError, r'two-dimensional parameters', pints.plot.surface, bad_points, values) # Number of values must match number of points bad_values = values[:-1] self.assertRaisesRegex( ValueError, r'number of values must match', pints.plot.surface, points, bad_values) # Three-dimensional boundaries bad_b = pints.RectangularBoundaries([0, 5, 1], [1, 9, 3]) self.assertRaisesRegex( ValueError, r'boundaries must be two-dimensional', pints.plot.surface, points, values, bad_b) # Close figure objects import matplotlib.pyplot as plt plt.close('all')
def setUpClass(cls): # Define objective function model = pints.toy.ConstantModel(1) times = np.linspace(1, 10) cls.true_params = [2.5] values = model.simulate(cls.true_params, times) problem = pints.SingleOutputProblem(model, times, values) cls.error = pints.SumOfSquaresError(problem) # Define initial parameters cls.params = [[3]] # Define boundaries cls.boundaries = pints.RectangularBoundaries(1, 5)
def test_exception_on_multi_use(self): # Controller should raise an exception if use multiple times r = pints.toy.TwistedGaussianLogPDF(2, 0.01) x = np.array([0, 1.01]) b = pints.RectangularBoundaries([-0.01, 0.95], [0.01, 1.05]) s = 0.01 opt = pints.OptimisationController(r, x, s, b, method=method) opt.set_log_to_screen(False) opt.set_max_unchanged_iterations(None) opt.set_max_iterations(10) opt.run() self.assertRaisesRegex( RuntimeError, 'Controller is valid for single use only', opt.run)
def test_stopping_max_iterations(self): """ Runs an optimisation with the max_iter stopping criterion. """ r = pints.toy.TwistedGaussianLogPDF(2, 0.01) x = np.array([0, 1.01]) b = pints.RectangularBoundaries([-0.01, 0.95], [0.01, 1.05]) s = 0.01 opt = pints.OptimisationController(r, x, s, b, method) opt.set_log_to_screen(True) opt.set_max_unchanged_iterations(None) opt.set_max_iterations(10) self.assertEqual(opt.max_iterations(), 10) self.assertRaises(ValueError, opt.set_max_iterations, -1) with StreamCapture() as c: opt.run() self.assertIn('Halting: Maximum number of iterations', c.text())
def test_stopping_threshold(self): """ Runs an optimisation with the threshold stopping criterion. """ r = pints.toy.TwistedGaussianLogPDF(2, 0.01) x = np.array([0.008, 1.01]) b = pints.RectangularBoundaries([-0.01, 0.95], [0.01, 1.05]) s = 0.01 opt = pints.OptimisationController(r, x, s, b, method) opt.set_log_to_screen(True) opt.set_max_iterations(None) opt.set_max_unchanged_iterations(None) opt.set_threshold(5) self.assertEqual(opt.threshold(), 5) with StreamCapture() as c: opt.run() self.assertIn( 'Halting: Objective function crossed threshold', c.text())
def test_sampling(self): lower = np.array([1, -1]) upper = np.array([2, 1]) d = 2 b = pints.RectangularBoundaries(lower, upper) self.assertTrue(b.check(b.sample())) n = 1 x = b.sample() self.assertEqual(x.shape, (n, d)) n = 10 x = b.sample(n) self.assertEqual(x.shape, (n, d)) for p in b.sample(50): self.assertTrue(b.check(p))
def test_post_run_statistics(self): # Test the methods to return statistics, post-run. r = pints.toy.TwistedGaussianLogPDF(2, 0.01) x = np.array([0, 1.01]) b = pints.RectangularBoundaries([-0.01, 0.95], [0.01, 1.05]) s = 0.01 opt = pints.OptimisationController(r, x, s, b, method) opt.set_log_to_screen(False) opt.set_max_unchanged_iterations(50, 1e-11) np.random.seed(123) opt.run() self.assertEqual(opt.iterations(), 75) self.assertEqual(opt.evaluations(), 450) t = opt.time() self.assertTrue(0 < t < 5)
def test_bounded(self): # Runs an optimisation with boundaries. r, x, s, b = self.problem() # Rectangular boundaries b = pints.RectangularBoundaries([-1, -1], [1, 1]) opt = pints.OptimisationController(r, x, boundaries=b, method=method) opt.set_log_to_screen(debug) found_parameters, found_solution = opt.run() self.assertTrue(found_solution < 1e-3) # Circular boundaries # Start near edge, to increase chance of out-of-bounds occurring. b = CircularBoundaries([0, 0], 1) x = [0.99, 0] opt = pints.OptimisationController(r, x, boundaries=b, method=method) opt.set_log_to_screen(debug) found_parameters, found_solution = opt.run() self.assertTrue(found_solution < 1e-3)