def test_maxiter_stops_solve(self): # test that if the maximum number of iterations is exceeded # the solver stops. solver = DifferentialEvolutionSolver(rosen, self.bounds, maxiter=1) result = solver.solve() assert_equal(result.success, False) assert_equal(result.message, 'Maximum number of iterations has been exceeded.')
def test_exp_runs(self): # test whether exponential mutation loop runs solver = DifferentialEvolutionSolver(rosen, self.bounds, strategy='best1exp', maxiter=1) solver.solve()
def setUp(self): self.old_seterr = np.seterr(invalid='raise') self.limits = np.array([[0., 0.], [2., 2.]]) self.bounds = [(0., 2.), (0., 2.)] self.dummy_solver = DifferentialEvolutionSolver( self.quadratic, [(0, 100)]) # dummy_solver2 will be used to test mutation strategies self.dummy_solver2 = DifferentialEvolutionSolver(self.quadratic, [(0, 1)], popsize=7, mutation=0.5) # create a population that's only 7 members long # [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7] population = np.atleast_2d(np.arange(0.1, 0.8, 0.1)).T self.dummy_solver2.population = population
def test_maxiter_none_GH5731(self): # Pre 0.17 the previous default for maxiter and maxfun was None. # the numerical defaults are now 1000 and np.inf. However, some scripts # will still supply None for both of those, this will raise a TypeError # in the solve method. solver = DifferentialEvolutionSolver(rosen, self.bounds, maxiter=None, maxfun=None) solver.solve()
def test_maxfun_stops_solve(self): # test that if the maximum number of function evaluations is exceeded # during initialisation the solver stops solver = DifferentialEvolutionSolver(rosen, self.bounds, maxfun=1, polish=False) result = solver.solve() assert_equal(result.nfev, 2) assert_equal(result.success, False) assert_equal(result.message, 'Maximum number of function evaluations has ' 'been exceeded.') # test that if the maximum number of function evaluations is exceeded # during the actual minimisation, then the solver stops. # Have to turn polishing off, as this will still occur even if maxfun # is reached. For popsize=5 and len(bounds)=2, then there are only 10 # function evaluations during initialisation. solver = DifferentialEvolutionSolver(rosen, self.bounds, popsize=5, polish=False, maxfun=40) result = solver.solve() assert_equal(result.nfev, 41) assert_equal(result.success, False) assert_equal(result.message, 'Maximum number of function evaluations has ' 'been exceeded.') # now repeat for updating='deferred version solver = DifferentialEvolutionSolver(rosen, self.bounds, popsize=5, polish=False, maxfun=40, updating='deferred') result = solver.solve() assert_equal(result.nfev, 40) assert_equal(result.success, False) assert_equal(result.message, 'Maximum number of function evaluations has ' 'been reached.')
def test_deferred_updating(self): # check setting of deferred updating, with default workers bounds = [(0., 2.), (0., 2.)] solver = DifferentialEvolutionSolver(rosen, bounds, updating='deferred') assert_(solver._updating == 'deferred') assert_(solver._mapwrapper._mapfunc is map) solver.solve()
def test_calculate_population_energies(self): # if popsize is 3 then the overall generation has size (6,) solver = DifferentialEvolutionSolver(rosen, self.bounds, popsize=3) solver._calculate_population_energies(solver.population) solver._promote_lowest_energy() assert_equal(np.argmin(solver.population_energies), 0) # initial calculation of the energies should require 6 nfev. assert_equal(solver._nfev, 6)
def test_select_samples(self): # select_samples should return 5 separate random numbers. limits = np.arange(12., dtype='float64').reshape(2, 6) bounds = list(zip(limits[0, :], limits[1, :])) solver = DifferentialEvolutionSolver(None, bounds, popsize=1) candidate = 0 r1, r2, r3, r4, r5 = solver._select_samples(candidate, 5) assert_equal(len(np.unique(np.array([candidate, r1, r2, r3, r4, r5]))), 6)
def test_parallel(self): # smoke test for parallelisation with deferred updating bounds = [(0., 2.), (0., 2.)] with multiprocessing.Pool(2) as p, DifferentialEvolutionSolver( rosen, bounds, updating='deferred', workers=p.map) as solver: assert_(solver._mapwrapper.pool is not None) assert_(solver._updating == 'deferred') solver.solve() with DifferentialEvolutionSolver(rosen, bounds, updating='deferred', workers=2) as solver: assert_(solver._mapwrapper.pool is not None) assert_(solver._updating == 'deferred') solver.solve() del solver gc.collect() # ensure MapWrapper cleans up properly
def test_parallel(self): # smoke test for parallelisation with deferred updating bounds = [(0., 2.), (0., 2.)] with DifferentialEvolutionSolver(rosen, bounds, updating='deferred', workers=2) as solver: assert_(solver._mapwrapper.pool is not None) assert_(solver._updating == 'deferred') solver.solve()
def test_parallel(self): # smoke test for parallelisation with deferred updating bounds = [(0., 2.), (0., 2.)] try: p = multiprocessing.Pool(2) with DifferentialEvolutionSolver(rosen, bounds, updating='deferred', workers=p.map) as solver: assert_(solver._mapwrapper.pool is not None) assert_(solver._updating == 'deferred') solver.solve() finally: p.close() with DifferentialEvolutionSolver(rosen, bounds, updating='deferred', workers=2) as solver: assert_(solver._mapwrapper.pool is not None) assert_(solver._updating == 'deferred') solver.solve()
def _maximize( self, runhistory: RunHistory, stats: Stats, num_points: int, _sorted: bool=False, **kwargs ) -> List[Tuple[float, Configuration]]: """DifferentialEvolutionSolver Parameters ---------- runhistory: ~smac.runhistory.runhistory.RunHistory runhistory object stats: ~smac.stats.stats.Stats current stats object num_points: int number of points to be sampled _sorted: bool whether random configurations are sorted according to acquisition function **kwargs not used Returns ------- iterable An iterable consistng of tuple(acqusition_value, :class:`smac.configspace.Configuration`). """ from scipy.optimize._differentialevolution import DifferentialEvolutionSolver configs = [] def func(x): return -self.acquisition_function([Configuration(self.config_space, vector=x)]) ds = DifferentialEvolutionSolver(func, bounds=[[0, 1], [0, 1]], args=(), strategy='best1bin', maxiter=1000, popsize=50, tol=0.01, mutation=(0.5, 1), recombination=0.7, seed=self.rng.randint(1000), polish=True, callback=None, disp=False, init='latinhypercube', atol=0) rval = ds.solve() for pop, val in zip(ds.population, ds.population_energies): rc = Configuration(self.config_space, vector=pop) rc.origin = 'DifferentialEvolution' configs.append((-val, rc)) configs.sort(key=lambda t: t[0]) configs.reverse() return configs
def test_constraint_population_feasibilities(self): def constr_f(x): return [x[0] + x[1]] def constr_f2(x): return [x[0]**2 + x[1], x[0] - x[1]] nlc = NonlinearConstraint(constr_f, -np.inf, 1.9) solver = DifferentialEvolutionSolver(rosen, [(0, 2), (0, 2)], constraints=(nlc)) # are population feasibilities correct # [0.5, 0.5] corresponds to scaled values of [1., 1.] feas, cv = solver._calculate_population_feasibilities( np.array([[0.5, 0.5], [1., 1.]])) assert_equal(feas, [False, False]) assert_almost_equal(cv, np.array([[0.1], [2.1]])) assert cv.shape == (2, 1) nlc2 = NonlinearConstraint(constr_f2, -np.inf, 1.8) solver = DifferentialEvolutionSolver(rosen, [(0, 2), (0, 2)], constraints=(nlc, nlc2)) feas, cv = solver._calculate_population_feasibilities( np.array([[0.5, 0.5], [0.6, 0.5]])) assert_equal(feas, [False, False]) assert_almost_equal(cv, np.array([[0.1, 0.2, 0], [0.3, 0.64, 0]])) feas, cv = solver._calculate_population_feasibilities( np.array([[0.5, 0.5], [1., 1.]])) assert_equal(feas, [False, False]) assert_almost_equal(cv, np.array([[0.1, 0.2, 0], [2.1, 4.2, 0]])) assert cv.shape == (2, 3) feas, cv = solver._calculate_population_feasibilities( np.array([[0.25, 0.25], [1., 1.]])) assert_equal(feas, [True, False]) assert_almost_equal(cv, np.array([[0.0, 0.0, 0.], [2.1, 4.2, 0]])) assert cv.shape == (2, 3)
def test_impossible_constraint(self): def constr_f(x): return np.array([x[0] + x[1]]) nlc = NonlinearConstraint(constr_f, -np.inf, -1) solver = DifferentialEvolutionSolver(rosen, [(0, 2), (0, 2)], constraints=(nlc), popsize=3, seed=1) # a UserWarning is issued because the 'trust-constr' polishing is # attempted on the least infeasible solution found. with warns(UserWarning): res = solver.solve() assert res.maxcv > 0 assert not res.success # test _promote_lowest_energy works when none of the population is # feasible. In this case the solution with the lowest constraint # violation should be promoted. solver = DifferentialEvolutionSolver(rosen, [(0, 2), (0, 2)], constraints=(nlc), polish=False) next(solver) assert not solver.feasible.all() assert not np.isfinite(solver.population_energies).all() # now swap two of the entries in the population l = 20 cv = solver.constraint_violation[0] solver.population_energies[[0, l]] = solver.population_energies[[l, 0]] solver.population[[0, l], :] = solver.population[[l, 0], :] solver.constraint_violation[[0, l], :] = ( solver.constraint_violation[[l, 0], :]) solver._promote_lowest_energy() assert_equal(solver.constraint_violation[0], cv)
def test_iteration(self): # test that DifferentialEvolutionSolver is iterable # if popsize is 3 then the overall generation has size (6,) solver = DifferentialEvolutionSolver(rosen, self.bounds, popsize=3, maxfun=12) x, fun = next(solver) assert_equal(np.size(x, 0), 2) # 6 nfev are required for initial calculation of energies, 6 nfev are # required for the evolution of the 6 population members. assert_equal(solver._nfev, 12) # the next generation should halt because it exceeds maxfun assert_raises(StopIteration, next, solver) # check a proper minimisation can be done by an iterable solver solver = DifferentialEvolutionSolver(rosen, self.bounds) for i, soln in enumerate(solver): x_current, fun_current = soln # need to have this otherwise the solver would never stop. if i == 1000: break assert_almost_equal(fun_current, 0)
def test_constraint_solve(self): def constr_f(x): return np.array([x[0] + x[1]]) nlc = NonlinearConstraint(constr_f, -np.inf, 1.9) solver = DifferentialEvolutionSolver(rosen, [(0, 2), (0, 2)], constraints=(nlc)) # trust-constr warns if the constraint function is linear with warns(UserWarning): res = solver.solve() assert constr_f(res.x) <= 1.9 assert res.success
def test_population_initiation(self): # test the different modes of population initiation # init must be either 'latinhypercube' or 'random' # raising ValueError is something else is passed in assert_raises(ValueError, DifferentialEvolutionSolver, *(rosen, self.bounds), **{'init': 'rubbish'}) solver = DifferentialEvolutionSolver(rosen, self.bounds) # check that population initiation: # 1) resets _nfev to 0 # 2) all population energies are np.inf solver.init_population_random() assert_equal(solver._nfev, 0) assert_(np.all(np.isinf(solver.population_energies))) solver.init_population_lhs() assert_equal(solver._nfev, 0) assert_(np.all(np.isinf(solver.population_energies)))
def test_best_solution_retrieval(self): # test that the getter property method for the best solution works. solver = DifferentialEvolutionSolver(self.quadratic, [(-2, 2)]) result = solver.solve() assert_almost_equal(result.x, solver.x)
def test_quadratic(self): # test the quadratic function from object solver = DifferentialEvolutionSolver(self.quadratic, [(-100, 100)], tol=0.02) solver.solve()
def test_population_initiation(self): # test the different modes of population initiation # init must be either 'latinhypercube' or 'random' # raising ValueError is something else is passed in assert_raises(ValueError, DifferentialEvolutionSolver, *(rosen, self.bounds), **{'init': 'rubbish'}) solver = DifferentialEvolutionSolver(rosen, self.bounds) # check that population initiation: # 1) resets _nfev to 0 # 2) all population energies are np.inf solver.init_population_random() assert_equal(solver._nfev, 0) assert_(np.all(np.isinf(solver.population_energies))) solver.init_population_lhs() assert_equal(solver._nfev, 0) assert_(np.all(np.isinf(solver.population_energies))) solver.init_population_qmc(qmc_engine='halton') assert_equal(solver._nfev, 0) assert_(np.all(np.isinf(solver.population_energies))) solver = DifferentialEvolutionSolver(rosen, self.bounds, init='sobol') solver.init_population_qmc(qmc_engine='sobol') assert_equal(solver._nfev, 0) assert_(np.all(np.isinf(solver.population_energies))) # we should be able to initialize with our own array population = np.linspace(-1, 3, 10).reshape(5, 2) solver = DifferentialEvolutionSolver(rosen, self.bounds, init=population, strategy='best2bin', atol=0.01, seed=1, popsize=5) assert_equal(solver._nfev, 0) assert_(np.all(np.isinf(solver.population_energies))) assert_(solver.num_population_members == 5) assert_(solver.population_shape == (5, 2)) # check that the population was initialized correctly unscaled_population = np.clip(solver._unscale_parameters(population), 0, 1) assert_almost_equal(solver.population[:5], unscaled_population) # population values need to be clipped to bounds assert_almost_equal(np.min(solver.population[:5]), 0) assert_almost_equal(np.max(solver.population[:5]), 1) # shouldn't be able to initialize with an array if it's the wrong shape # this would have too many parameters population = np.linspace(-1, 3, 15).reshape(5, 3) assert_raises(ValueError, DifferentialEvolutionSolver, *(rosen, self.bounds), **{'init': population}) # provide an initial solution # bounds are [(0, 2), (0, 2)] x0 = np.random.uniform(low=0.0, high=2.0, size=2) solver = DifferentialEvolutionSolver( rosen, self.bounds, x0=x0 ) # parameters are scaled to unit interval assert_allclose(solver.population[0], x0 / 2.0)
def _create_DE_solver(self): return DifferentialEvolutionSolver( self._fom_func, list(self.master_controller.bounds(only_fitted=True)), callback=self.fit_callback, **self.algo_kwargs)
def test_converged(self): solver = DifferentialEvolutionSolver(rosen, [(0, 2), (0, 2)]) solver.solve() assert_(solver.converged())
def test_convergence(self): solver = DifferentialEvolutionSolver(rosen, self.bounds, tol=0.2, polish=False) solver.solve() assert_(solver.convergence < 0.2)
def test__strategy_resolves(self): # test that the correct mutation function is resolved by # different requested strategy arguments solver = DifferentialEvolutionSolver(rosen, self.bounds, strategy='best1exp') assert_equal(solver.strategy, 'best1exp') assert_equal(solver.mutation_func.__name__, '_best1') solver = DifferentialEvolutionSolver(rosen, self.bounds, strategy='best1bin') assert_equal(solver.strategy, 'best1bin') assert_equal(solver.mutation_func.__name__, '_best1') solver = DifferentialEvolutionSolver(rosen, self.bounds, strategy='rand1bin') assert_equal(solver.strategy, 'rand1bin') assert_equal(solver.mutation_func.__name__, '_rand1') solver = DifferentialEvolutionSolver(rosen, self.bounds, strategy='rand1exp') assert_equal(solver.strategy, 'rand1exp') assert_equal(solver.mutation_func.__name__, '_rand1') solver = DifferentialEvolutionSolver(rosen, self.bounds, strategy='rand2exp') assert_equal(solver.strategy, 'rand2exp') assert_equal(solver.mutation_func.__name__, '_rand2') solver = DifferentialEvolutionSolver(rosen, self.bounds, strategy='best2bin') assert_equal(solver.strategy, 'best2bin') assert_equal(solver.mutation_func.__name__, '_best2') solver = DifferentialEvolutionSolver(rosen, self.bounds, strategy='rand2bin') assert_equal(solver.strategy, 'rand2bin') assert_equal(solver.mutation_func.__name__, '_rand2') solver = DifferentialEvolutionSolver(rosen, self.bounds, strategy='rand2exp') assert_equal(solver.strategy, 'rand2exp') assert_equal(solver.mutation_func.__name__, '_rand2') solver = DifferentialEvolutionSolver(rosen, self.bounds, strategy='randtobest1bin') assert_equal(solver.strategy, 'randtobest1bin') assert_equal(solver.mutation_func.__name__, '_randtobest1') solver = DifferentialEvolutionSolver(rosen, self.bounds, strategy='randtobest1exp') assert_equal(solver.strategy, 'randtobest1exp') assert_equal(solver.mutation_func.__name__, '_randtobest1') solver = DifferentialEvolutionSolver(rosen, self.bounds, strategy='currenttobest1bin') assert_equal(solver.strategy, 'currenttobest1bin') assert_equal(solver.mutation_func.__name__, '_currenttobest1') solver = DifferentialEvolutionSolver(rosen, self.bounds, strategy='currenttobest1exp') assert_equal(solver.strategy, 'currenttobest1exp') assert_equal(solver.mutation_func.__name__, '_currenttobest1')
def test_differential_evolution(self): # test that the Jmin of DifferentialEvolutionSolver # is the same as the function evaluation solver = DifferentialEvolutionSolver(self.quadratic, [(-2, 2)]) result = solver.solve() assert_almost_equal(result.fun, self.quadratic(result.x))
def test_quadratic(self): # test the quadratic function from object solver = DifferentialEvolutionSolver(self.quadratic, [(-100, 100)], tol=0.02) solver.solve() assert_equal(np.argmin(solver.population_energies), 0)
def mcmc_sample_model(model, y, beta=1., nwalkers=100, nburnin=200, nprod=800, nthreads=1, optimized=False, bounds=None, return_logpost=False, show_progress=False, progress_mod=10): """Markov Chain Monte Carlo sampling interface MCMC sampling interface to sample posterior probabilities using the :class:`emcee.EnsembleSampler` [#]_. .. [#] https://emcee.readthedocs.io Arguments --------- model : celerite.GP, george.GP, or sciapy.regress.RegressionModel instance The model to draw posterior samples from. It should provide either `log_likelihood()` and `log_prior()` functions or be directly callable via `__call__()`. y : (N,) array_like The data to condition the probabilities on. beta : float, optional Tempering factor for the probability, default: 1. nwalkers : int, optional The number of MCMC walkers (default: 100). If this number is smaller than 4 times the number of parameters, it is multiplied by the number of parameters. Otherwise it specifies the number of parameters directly. nburnin : int, optional The number of burn-in samples to draw, default: 200. nprod : int, optional The number of production samples to draw, default: 800. nthreads : int, optional The number of threads to use with a `multiprocessing.Pool`, used as `pool` for `emcee.EnsembleSampler`. Default: 1. optimized : bool, optional Indicate whether the actual (starting) position was determined with an optimization algorithm beforehand. If `False` (the default), a pre-burn-in run optimizes the starting position. Sampling continues from there with the normal burn-in and production runs. In that case, latin hypercube sampling is used to distribute the walker starting positions equally in parameter space. bounds : iterable, optional The parameter bounds as a list of (min, max) entries. Default: None return_logpost : bool, optional Indicate whether or not to return the sampled log probabilities as well. Default: False show_progress : bool, optional Print the percentage of samples every `progress_mod` samples. Default: False progress_mod : int, optional Interval in samples to print the percentage of samples. Default: 10 Returns ------- samples or (samples, logpost) : array_like or tuple (nwalkers * nprod, ndim) array of the sampled parameters from the production run if return_logpost is `False`. A tuple of an (nwalkers * nprod, ndim) array (the same as above) and an (nwalkers,) array with the second entry containing the log posterior probabilities if return_logpost is `True`. """ v = model.get_parameter_vector() ndim = len(v) if nwalkers < 4 * ndim: nwalkers *= ndim logging.info("MCMC parameters: %s walkers, %s burn-in samples, " "%s production samples using %s threads.", nwalkers, nburnin, nprod, nthreads) if isinstance(model, celerite.GP) or isinstance(model, george.GP): mod_func = _lpost mod_args = (model, y, beta) else: mod_func = model mod_args = (beta,) # Initialize the walkers. if not optimized: # scipy.optimize's DifferentialEvolutionSolver uses # latin hypercube sampling as starting positions. # We just use their initialization to avoid duplicating code. if bounds is None: bounds = model.get_parameter_bounds() de_solver = DifferentialEvolutionSolver(_lpost, bounds=bounds, popsize=nwalkers // ndim) # The initial population should reflect latin hypercube sampling p0 = de_solver.population # fill up to full size in case the number of walkers is not a # multiple of the number of parameters missing = nwalkers - p0.shape[0] p0 = np.vstack([p0] + [v + 1e-2 * np.random.randn(ndim) for _ in range(missing)]) else: p0 = np.array([v + 1e-2 * np.random.randn(ndim) for _ in range(nwalkers)]) # set up the sampling pool if nthreads > 1: pool = Pool(processes=nthreads) else: pool = None sampler = emcee.EnsembleSampler(nwalkers, ndim, mod_func, args=mod_args, pool=pool) rst0 = np.random.get_state() if not optimized: logging.info("Running MCMC fit (%s samples)", nburnin) p0, lnp0, rst0, _ = _sample_mcmc(sampler, nburnin, p0, rst0, show_progress, progress_mod, debug=True) logging.info("MCMC fit finished.") p = p0[np.argmax(lnp0)] logging.info("Fit max logpost: %s, params: %s, exp(params): %s", np.max(lnp0), p, np.exp(p)) model.set_parameter_vector(p) logging.debug("params: %s", model.get_parameter_dict()) logging.debug("log_likelihood: %s", model.log_likelihood(y)) p0 = [p + 1e-4 * np.random.randn(ndim) for _ in range(nwalkers)] sampler.reset() logging.info("Running burn-in (%s samples)", nburnin) p0, lnp0, rst0, _ = _sample_mcmc(sampler, nburnin, p0, rst0, show_progress, progress_mod) logging.info("Burn-in finished.") p = p0[np.argmax(lnp0)] logging.info("burn-in max logpost: %s, params: %s, exp(params): %s", np.max(lnp0), p, np.exp(p)) model.set_parameter_vector(p) logging.debug("params: %s", model.get_parameter_dict()) logging.debug("log_likelihood: %s", model.log_likelihood(y)) sampler.reset() logging.info("Running production chain (%s samples)", nprod) _sample_mcmc(sampler, nprod, p0, rst0, show_progress, progress_mod) logging.info("Production run finished.") samples = sampler.flatchain lnp = sampler.flatlnprobability # first column in the blobs are the log likelihoods lnlh = np.array(sampler.blobs)[..., 0].ravel().astype(float) post_expect_loglh = np.nanmean(np.array(lnlh)) logging.info("total samples: %s", samples.shape) samplmean = np.mean(samples, axis=0) logging.info("mean: %s, exp(mean): %s, sqrt(exp(mean)): %s", samplmean, np.exp(samplmean), np.sqrt(np.exp(samplmean))) samplmedian = np.median(samples, axis=0) logging.info("median: %s, exp(median): %s, sqrt(exp(median)): %s", samplmedian, np.exp(samplmedian), np.sqrt(np.exp(samplmedian))) logging.info("max logpost: %s, params: %s, exp(params): %s", np.max(lnp), samples[np.argmax(lnp)], np.exp(samples[np.argmax(lnp)])) logging.info("AIC: %s", 2 * ndim - 2 * np.max(lnp)) logging.info("BIC: %s", np.log(len(y)) * ndim - 2 * np.max(lnp)) logging.info("poor man's evidence 1 sum: %s, mean: %s", np.sum(np.exp(lnp)), np.mean(np.exp(lnp))) logging.info("poor man's evidence 2 max: %s, std: %s", np.max(np.exp(lnp)), np.std(np.exp(lnp))) logging.info("poor man's evidence 3: %s", np.max(np.exp(lnp)) / np.std(np.exp(lnp))) logging.info("poor man's evidence 4 sum: %s", logsumexp(lnp, b=1. / lnp.shape[0], axis=0)) # mode model.set_parameter_vector(samples[np.argmax(lnp)]) log_lh = model.log_likelihood(y) # Use the likelihood instead of the posterior # https://doi.org/10.3847/1538-3881/aa9332 logging.info("BIC lh: %s", np.log(len(y)) * ndim - 2 * log_lh) # DIC sample_deviance = -2 * np.max(lnp) deviance_at_sample = -2 * (model.log_prior() + log_lh) pd = sample_deviance - deviance_at_sample dic = 2 * sample_deviance - deviance_at_sample logging.info("max logpost log_lh: %s, AIC: %s, DIC: %s, pd: %s", model.log_likelihood(y), 2 * ndim - 2 * log_lh, dic, pd) # mean model.set_parameter_vector(samplmean) log_lh = model.log_likelihood(y) log_lh_mean = log_lh # DIC sample_deviance = -2 * np.nanmean(lnp) deviance_at_sample = -2 * (model.log_prior() + log_lh) pd = sample_deviance - deviance_at_sample dic = 2 * sample_deviance - deviance_at_sample logging.info("mean log_lh: %s, AIC: %s, DIC: %s, pd: %s", model.log_likelihood(y), 2 * ndim - 2 * log_lh, dic, pd) # median model.set_parameter_vector(samplmedian) log_lh = model.log_likelihood(y) # DIC sample_deviance = -2 * np.nanmedian(lnp) deviance_at_sample = -2 * (model.log_prior() + log_lh) dic = 2 * sample_deviance - deviance_at_sample pd = sample_deviance - deviance_at_sample logging.info("median log_lh: %s, AIC: %s, DIC: %s, pd: %s", model.log_likelihood(y), 2 * ndim - 2 * log_lh, dic, pd) # (4)--(6) in Ando2011 doi:10.1080/01966324.2011.10737798 pd_ando = 2 * (log_lh_mean - post_expect_loglh) ic5 = - 2 * post_expect_loglh + 2 * pd_ando ic6 = - 2 * post_expect_loglh + 2 * ndim logging.info("Ando2011: pd: %s, IC(5): %s, IC(6): %s", pd_ando, ic5, ic6) if return_logpost: return samples, lnp return samples