class TestCurveFitter(object): def setup_method(self): # Reproducible results! np.random.seed(123) self.m_true = -0.9594 self.b_true = 4.294 self.f_true = 0.534 self.m_ls = -1.1040757010910947 self.b_ls = 5.4405552502319505 # Generate some synthetic data from the model. N = 50 x = np.sort(10 * np.random.rand(N)) y_err = 0.1 + 0.5 * np.random.rand(N) y = self.m_true * x + self.b_true y += np.abs(self.f_true * y) * np.random.randn(N) y += y_err * np.random.randn(N) self.data = Data1D(data=(x, y, y_err)) self.p = Parameter(self.b_ls, "b", vary=True, bounds=(-100, 100)) self.p |= Parameter(self.m_ls, "m", vary=True, bounds=(-100, 100)) self.model = Model(self.p, fitfunc=line) self.objective = Objective(self.model, self.data) assert_(len(self.objective.varying_parameters()) == 2) mod = np.array([ 4.78166609, 4.42364699, 4.16404064, 3.50343504, 3.4257084, 2.93594347, 2.92035638, 2.67533842, 2.28136038, 2.19772983, 1.99295496, 1.93748334, 1.87484436, 1.65161016, 1.44613461, 1.11128101, 1.04584535, 0.86055984, 0.76913963, 0.73906649, 0.73331407, 0.68350418, 0.65216599, 0.59838566, 0.13070299, 0.10749131, -0.01010195, -0.10010155, -0.29495372, -0.42817431, -0.43122391, -0.64637715, -1.30560686, -1.32626428, -1.44835768, -1.52589881, -1.56371158, -2.12048349, -2.24899179, -2.50292682, -2.53576659, -2.55797996, -2.60870542, -2.7074727, -3.93781479, -4.12415366, -4.42313742, -4.98368609, -5.38782395, -5.44077086, ]) self.mod = mod self.mcfitter = CurveFitter(self.objective) def test_bounds_list(self): bnds = bounds_list(self.p) assert_allclose(bnds, [(-100, 100), (-100, 100)]) # try making a Parameter bound a normal distribution, then get an # approximation to box bounds self.p[0].bounds = PDF(norm(0, 1)) assert_allclose(bounds_list(self.p), [norm(0, 1).ppf([0.005, 0.995]), (-100, 100)]) def test_constraints(self): # constraints should work during fitting self.p[0].value = 5.4 self.p[1].constraint = -0.203 * self.p[0] assert_equal(self.p[1].value, self.p[0].value * -0.203) res = self.mcfitter.fit() assert_(res.success) assert_equal(len(self.objective.varying_parameters()), 1) # lnsigma is parameters[0] assert_(self.p[0] is self.objective.parameters.flattened()[0]) assert_(self.p[1] is self.objective.parameters.flattened()[1]) assert_almost_equal(self.p[0].value, res.x[0]) assert_almost_equal(self.p[1].value, self.p[0].value * -0.203) # check that constraints work during sampling # the CurveFitter has to be set up again if you change how the # parameters are being fitted. mcfitter = CurveFitter(self.objective) assert_(mcfitter.nvary == 1) mcfitter.sample(5) assert_equal(self.p[1].value, self.p[0].value * -0.203) # the constrained parameters should have a chain assert_(self.p[0].chain is not None) assert_(self.p[1].chain is not None) assert_allclose(self.p[1].chain, self.p[0].chain * -0.203) def test_mcmc(self): self.mcfitter.sample(steps=50, nthin=1, verbose=False) assert_equal(self.mcfitter.nvary, 2) # smoke test for corner plot self.mcfitter.objective.corner() # we're not doing Parallel Tempering here. assert_(self.mcfitter._ntemps == -1) assert_(isinstance(self.mcfitter.sampler, emcee.EnsembleSampler)) # should be able to multithread mcfitter = CurveFitter(self.objective, nwalkers=50) res = mcfitter.sample(steps=33, nthin=2, verbose=False, pool=2) # check that the autocorrelation function at least runs acfs = mcfitter.acf(nburn=10) assert_equal(acfs.shape[-1], mcfitter.nvary) # check the standalone autocorrelation calculator acfs2 = autocorrelation_chain(mcfitter.chain, nburn=10) assert_equal(acfs, acfs2) # check integrated_time integrated_time(acfs2, tol=5) # check chain shape assert_equal(mcfitter.chain.shape, (33, 50, 2)) # assert_equal(mcfitter._lastpos, mcfitter.chain[:, -1, :]) assert_equal(res[0].chain.shape, (33, 50)) # if the number of parameters changes there should be an Exception # raised from pytest import raises with raises(RuntimeError): self.p[0].vary = False self.mcfitter.sample(1) # can fix by making the sampler again self.mcfitter.make_sampler() self.mcfitter.sample(1) def test_random_seed(self): # check that MCMC sampling is reproducible self.mcfitter.sample(steps=2, random_state=1) # get a starting pos starting_pos = self.mcfitter._state.coords # is sampling reproducible self.mcfitter.reset() self.mcfitter.initialise(pos=starting_pos) self.mcfitter.sample(3, random_state=1, pool=1) chain1 = np.copy(self.mcfitter.chain) self.mcfitter.reset() self.mcfitter.initialise(pos=starting_pos) self.mcfitter.sample(3, random_state=1, pool=1) chain2 = np.copy(self.mcfitter.chain) assert_equal(chain1, chain2) def test_mcmc_pt(self): # smoke test for parallel tempering x = np.array(self.objective.parameters) mcfitter = CurveFitter(self.objective, ntemps=10, nwalkers=50) assert_equal(mcfitter.sampler.ntemps, 10) # check that the parallel sampling works # and that chain shape is correct res = mcfitter.sample(steps=5, nthin=2, verbose=False, pool=-1) assert_equal(mcfitter.chain.shape, (5, 10, 50, 2)) assert_equal(res[0].chain.shape, (5, 50)) assert_equal(mcfitter.chain[:, 0, :, 0], res[0].chain) assert_equal(mcfitter.chain[:, 0, :, 1], res[1].chain) chain = np.copy(mcfitter.chain) # the sampler should store the probability assert_equal(mcfitter.logpost.shape, (5, 10, 50)) assert_allclose(mcfitter.logpost, mcfitter.sampler._ptchain.logP) logprobs = mcfitter.logpost highest_prob_loc = np.argmax(logprobs[:, 0]) idx = np.unravel_index(highest_prob_loc, logprobs[:, 0].shape) idx = list(idx) idx.insert(1, 0) idx = tuple(idx) assert_equal(idx, mcfitter.index_max_prob) pvals = mcfitter.chain[idx] assert_allclose(logprobs[idx], self.objective.logpost(pvals)) # try resetting the chain mcfitter.reset() # test for reproducible operation self.objective.setp(x) mcfitter = CurveFitter(self.objective, ntemps=10, nwalkers=50) mcfitter.initialise("jitter", random_state=1) mcfitter.sample(steps=5, nthin=2, verbose=False, random_state=2) chain = np.copy(mcfitter.chain) self.objective.setp(x) mcfitter = CurveFitter(self.objective, ntemps=10, nwalkers=50) mcfitter.initialise("jitter", random_state=1) mcfitter.sample(steps=5, nthin=2, verbose=False, random_state=2) chain2 = np.copy(mcfitter.chain) assert_allclose(chain2, chain) def test_mcmc_init(self): # smoke test for sampler initialisation # TODO check that the initialisation worked. # reproducible initialisation with random_state dependents self.mcfitter.initialise("prior", random_state=1) starting_pos = np.copy(self.mcfitter._state.coords) self.mcfitter.initialise("prior", random_state=1) starting_pos2 = self.mcfitter._state.coords assert_equal(starting_pos, starting_pos2) self.mcfitter.initialise("jitter", random_state=1) starting_pos = np.copy(self.mcfitter._state.coords) self.mcfitter.initialise("jitter", random_state=1) starting_pos2 = self.mcfitter._state.coords assert_equal(starting_pos, starting_pos2) mcfitter = CurveFitter(self.objective, nwalkers=100) mcfitter.initialise("covar") assert_equal(mcfitter._state.coords.shape, (100, 2)) mcfitter.initialise("prior") assert_equal(mcfitter._state.coords.shape, (100, 2)) mcfitter.initialise("jitter") assert_equal(mcfitter._state.coords.shape, (100, 2)) # initialise with last position mcfitter.sample(steps=1) chain = mcfitter.chain mcfitter.initialise(pos=chain[-1]) assert_equal(mcfitter._state.coords.shape, (100, 2)) # initialise with chain mcfitter.sample(steps=2) chain = mcfitter.chain mcfitter.initialise(pos=chain) assert_equal(mcfitter._state.coords, chain[-1]) # initialise with chain if it's never been run before mcfitter = CurveFitter(self.objective, nwalkers=100) mcfitter.initialise(chain) # initialise for Parallel tempering mcfitter = CurveFitter(self.objective, ntemps=20, nwalkers=100) mcfitter.initialise("covar") assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) mcfitter.initialise("prior") assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) mcfitter.initialise("jitter") assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) # initialise with last position mcfitter.sample(steps=1) chain = mcfitter.chain mcfitter.initialise(pos=chain[-1]) assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) # initialise with chain mcfitter.sample(steps=2) chain = mcfitter.chain mcfitter.initialise(pos=np.copy(chain)) assert_equal(mcfitter._state.coords, chain[-1]) # initialise with chain if it's never been run before mcfitter = CurveFitter(self.objective, nwalkers=100, ntemps=20) mcfitter.initialise(chain) def test_fit_smoke(self): # smoke tests to check that fit runs def callback(xk): return def callback2(xk, **kws): return # L-BFGS-B res0 = self.mcfitter.fit(callback=callback) assert_almost_equal(res0.x, [self.b_ls, self.m_ls], 6) res0 = self.mcfitter.fit() res0 = self.mcfitter.fit(verbose=False) res0 = self.mcfitter.fit(verbose=False, callback=callback) # least_squares res1 = self.mcfitter.fit(method="least_squares") assert_almost_equal(res1.x, [self.b_ls, self.m_ls], 6) # least_squares doesn't accept a callback. As well as testing that # least_squares works, it checks that providing a callback doesn't # trip the fitter up. res1 = self.mcfitter.fit(method="least_squares", callback=callback) assert_almost_equal(res1.x, [self.b_ls, self.m_ls], 6) # need full bounds for differential_evolution self.p[0].range(3, 7) self.p[1].range(-2, 0) res2 = self.mcfitter.fit( method="differential_evolution", seed=1, popsize=10, maxiter=100, callback=callback2, ) assert_almost_equal(res2.x, [self.b_ls, self.m_ls], 6) # check that the res object has covar and stderr assert_("covar" in res0) assert_("stderr" in res0) def test_NIST(self): # Run all the NIST standard tests with leastsq for model in NIST_Models: try: NIST_runner(model) except Exception: print(model) raise
class TestCurveFitter(object): def setup_method(self): # Reproducible results! np.random.seed(123) self.m_true = -0.9594 self.b_true = 4.294 self.f_true = 0.534 self.m_ls = -1.1040757010910947 self.b_ls = 5.4405552502319505 # Generate some synthetic data from the model. N = 50 x = np.sort(10 * np.random.rand(N)) y_err = 0.1 + 0.5 * np.random.rand(N) y = self.m_true * x + self.b_true y += np.abs(self.f_true * y) * np.random.randn(N) y += y_err * np.random.randn(N) self.data = Data1D(data=(x, y, y_err)) self.p = Parameter(self.b_ls, 'b', vary=True, bounds=(-100, 100)) self.p |= Parameter(self.m_ls, 'm', vary=True, bounds=(-100, 100)) self.model = Model(self.p, fitfunc=line) self.objective = Objective(self.model, self.data) assert_(len(self.objective.varying_parameters()) == 2) mod = np.array([4.78166609, 4.42364699, 4.16404064, 3.50343504, 3.4257084, 2.93594347, 2.92035638, 2.67533842, 2.28136038, 2.19772983, 1.99295496, 1.93748334, 1.87484436, 1.65161016, 1.44613461, 1.11128101, 1.04584535, 0.86055984, 0.76913963, 0.73906649, 0.73331407, 0.68350418, 0.65216599, 0.59838566, 0.13070299, 0.10749131, -0.01010195, -0.10010155, -0.29495372, -0.42817431, -0.43122391, -0.64637715, -1.30560686, -1.32626428, -1.44835768, -1.52589881, -1.56371158, -2.12048349, -2.24899179, -2.50292682, -2.53576659, -2.55797996, -2.60870542, -2.7074727, -3.93781479, -4.12415366, -4.42313742, -4.98368609, -5.38782395, -5.44077086]) self.mod = mod self.mcfitter = CurveFitter(self.objective) def test_constraints(self): # constraints should work during fitting self.p[0].value = 5.4 self.p[1].constraint = -0.203 * self.p[0] assert_equal(self.p[1].value, self.p[0].value * -0.203) res = self.mcfitter.fit() assert_(res.success) assert_equal(len(self.objective.varying_parameters()), 1) # lnsigma is parameters[0] assert_(self.p[0] is self.objective.parameters.flattened()[0]) assert_(self.p[1] is self.objective.parameters.flattened()[1]) assert_almost_equal(self.p[0].value, res.x[0]) assert_almost_equal(self.p[1].value, self.p[0].value * -0.203) # check that constraints work during sampling # the CurveFitter has to be set up again if you change how the # parameters are being fitted. mcfitter = CurveFitter(self.objective) assert_(mcfitter.nvary == 1) mcfitter.sample(5) assert_equal(self.p[1].value, self.p[0].value * -0.203) # the constrained parameters should have a chain assert_(self.p[0].chain is not None) assert_(self.p[1].chain is not None) assert_allclose(self.p[1].chain, self.p[0].chain * -0.203) def test_mcmc(self): self.mcfitter.sample(steps=50, nthin=1, verbose=False) assert_equal(self.mcfitter.nvary, 2) # smoke test for corner plot self.mcfitter.objective.corner() # we're not doing Parallel Tempering here. assert_(self.mcfitter._ntemps == -1) assert_(isinstance(self.mcfitter.sampler, emcee.EnsembleSampler)) # should be able to multithread mcfitter = CurveFitter(self.objective, nwalkers=50) res = mcfitter.sample(steps=33, nthin=2, verbose=False, pool=2) # check that the autocorrelation function at least runs acfs = mcfitter.acf(nburn=10) assert_equal(acfs.shape[-1], mcfitter.nvary) # check chain shape assert_equal(mcfitter.chain.shape, (33, 50, 2)) # assert_equal(mcfitter._lastpos, mcfitter.chain[:, -1, :]) assert_equal(res[0].chain.shape, (33, 50)) # if the number of parameters changes there should be an Exception # raised from pytest import raises with raises(RuntimeError): self.p[0].vary = False self.mcfitter.sample(1) # can fix by making the sampler again self.mcfitter.make_sampler() self.mcfitter.sample(1) def test_mcmc_pt(self): if not _HAVE_PTSAMPLER: return # smoke test for parallel tempering mcfitter = CurveFitter(self.objective, ntemps=10, nwalkers=50) assert_equal(mcfitter.sampler.ntemps, 10) res = mcfitter.sample(steps=30, nthin=2, verbose=False, pool=0) assert_equal(mcfitter.chain.shape, (30, 10, 50, 2)) assert_equal(res[0].chain.shape, (30, 50)) assert_equal(mcfitter.chain[:, 0, :, 0], res[0].chain) assert_equal(mcfitter.chain[:, 0, :, 1], res[1].chain) def test_mcmc_init(self): # smoke test for sampler initialisation # TODO check that the initialisation worked. mcfitter = CurveFitter(self.objective, nwalkers=100) mcfitter.initialise('covar') assert_equal(mcfitter._state.coords.shape, (100, 2)) mcfitter.initialise('prior') assert_equal(mcfitter._state.coords.shape, (100, 2)) mcfitter.initialise('jitter') assert_equal(mcfitter._state.coords.shape, (100, 2)) # initialise with last position mcfitter.sample(steps=1) chain = mcfitter.chain mcfitter.initialise(pos=chain[-1]) assert_equal(mcfitter._state.coords.shape, (100, 2)) # initialise with chain mcfitter.sample(steps=2) chain = mcfitter.chain mcfitter.initialise(pos=chain) assert_equal(mcfitter._state.coords, chain[-1]) if not _HAVE_PTSAMPLER: return # initialise for Parallel tempering mcfitter = CurveFitter(self.objective, ntemps=20, nwalkers=100) mcfitter.initialise('covar') assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) mcfitter.initialise('prior') assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) mcfitter.initialise('jitter') assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) # initialise with last position mcfitter.sample(steps=1) chain = mcfitter.chain mcfitter.initialise(pos=chain[-1]) assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) # initialise with chain mcfitter.sample(steps=2) chain = mcfitter.chain mcfitter.initialise(pos=np.copy(chain)) assert_equal(mcfitter._state.coords, chain[-1]) def test_fit_smoke(self): # smoke tests to check that fit runs # L-BFGS-B res0 = self.mcfitter.fit() assert_almost_equal(res0.x, [self.b_ls, self.m_ls], 6) # least_squares res1 = self.mcfitter.fit(method='least_squares') assert_almost_equal(res1.x, [self.b_ls, self.m_ls], 6) # need full bounds for differential_evolution self.p[0].range(3, 7) self.p[1].range(-2, 0) res2 = self.mcfitter.fit(method='differential_evolution', seed=1, popsize=10, maxiter=100) assert_almost_equal(res2.x, [self.b_ls, self.m_ls], 6) # check that the res object has covar and stderr assert_('covar' in res0) assert_('stderr' in res0) def test_NIST(self): # Run all the NIST standard tests with leastsq for model in NIST_Models: try: NIST_runner(model) except Exception: print(model) raise