def build_evolution_pCN_sampler(observation_operator, u, data, noise, prior, posterior, rng): potential = EvolutionPotential(observation_operator, data, noise) proposer = pCNProposer(beta=0.25, prior=prior) accepter = CountedAccepter(pCNAccepter(potential=potential)) return MCMCSampler(proposer, accepter, rng)
def create_pCNSampler(density): mean = np.array([0]) covariance = np.array([1], ndmin=2) prior = GaussianDistribution(mean, covariance) potential = AnalyticPotential(posterior=density, prior=prior) # beta != delta of other proposers, but # it could easily be translated if someone took the 30s to do it proposer = pCNProposer(beta=0.25, prior=prior) accepter = pCNAccepter(potential=potential) return MCMCSampler(proposer, accepter, np.random.default_rng(1))
def create_StandardRWSampler(density): mean = np.array([0]) covariance = np.array([1], ndmin=2) sqrt_covariance = np.array([1], ndmin=2) prior = GaussianDistribution(mean, covariance) potential = AnalyticPotential(posterior=density, prior=prior) proposer = StandardRWProposer(delta=0.25, dims=1, sqrt_covariance=sqrt_covariance) accepter = StandardRWAccepter(potential=potential, prior=prior) return MCMCSampler(proposer, accepter, np.random.default_rng(1))
def autocorrelation(samples, tau_max): avg_over = int(len(samples[0, :]) / tau_max) assert avg_over > 0, ("Not enough samples to compute autocorrelation" "with specified length") n_vars = len(samples[:, 0]) ac = np.zeros((n_vars, tau_max)) for i in range(avg_over): for var in range(n_vars): vals = samples[var, i * tau_max:(i + 1) * tau_max] ac[var, :] += MCMCSampler.autocorr(vals) ac /= avg_over return ac
def create_mcmc_sampler(): rng = np.random.default_rng(2) # Proposer prior = Settings.Prior.get_distribution() proposer = pCNProposer(Settings.Sampling.beta, prior) # Accepter integrator = create_integrator() measurer = create_measurer() IC_true = PerturbedRiemannIC(Settings.Simulation.IC.ground_truth) observation_operator = FVMObservationOperator(PerturbedRiemannIC, Settings.Prior.mean, integrator, measurer) ground_truth = measurer(integrator(IC_true)) noise = Settings.Noise.get_distribution() potential = EvolutionPotential(observation_operator, ground_truth, noise) accepter = CountedAccepter(pCNAccepter(potential)) return MCMCSampler(proposer, accepter, rng)
def create_mcmc_sampler(): # Proposer prior = Settings.Prior.get_distribution() # proposer = ConstSteppCNProposer(Settings.Sampling.step, prior) # proposer = ConstStepStandardRWProposer(Settings.Sampling.step, prior) proposer = VarStepStandardRWProposer(Settings.Sampling.step, prior) # Accepter integrator = create_integrator() measurer = create_measurer() IC_true = PerturbedRiemannIC(Settings.Simulation.IC.ground_truth) observation_operator = FVMObservationOperator(PerturbedRiemannIC, Settings.Prior.mean, integrator, measurer) ground_truth = measurer(integrator(IC_true)) noise = Settings.Noise.get_distribution() potential = EvolutionPotential(observation_operator, ground_truth, noise) # accepter = CountedAccepter(pCNAccepter(potential)) accepter = CountedAccepter(StandardRWAccepter(potential, prior)) return MCMCSampler(proposer, accepter, Settings.Sampling.rng)
def create_AnalyticSampler(density): proposer = StandardRWProposer(0.25, 1) accepter = AnalyticAccepter(density) return MCMCSampler(proposer, accepter, np.random.default_rng(1))
def main(): rng = np.random.default_rng(1) data_dir = "/home/david/fs20/thesis/code/report/data/" # Parameters of simulation K, J = 6, 4 sim_length = 20 # True Theta theta = np.array([10, 10, 1, 10]) # F, h, c, b r = 0.5 # noise level # Characteristics of system T = 500 try: Y = np.load(data_dir + f"Y_{K=}_{J=}_{T=}.npy") print("Loaded existing simulation results") except FileNotFoundError: print("Running simulation to generate fake measurements") Y = run_lorenz96(K, J, theta, T) np.save(data_dir + f"Y_{K=}_{J=}_{T=}", Y) print(f"{Y.shape=}") moment_function_values = moment_function(Y, K, J) moment_function_means = np.mean(moment_function_values, axis=1) moment_function_variances = np.var(moment_function_values, axis=1) print(f"{moment_function_variances.shape=}") noise = GaussianDistribution(mean=np.zeros_like(moment_function_variances), covariance=r**2 * np.diag(moment_function_variances)) prior_means = np.array([12, 8, 9]) # F, h, b prior_covariance = np.diag([10, 1, 10]) # From theory: prior is always assumed to be centered, # so I do MCMC over pertubations from given prior means prior = GaussianDistribution(np.zeros_like(prior_means), prior_covariance) observation_operator = LorenzObservationOperator(K, J, sim_length, theta[2], prior_means, Y[:, -1]) # don't need huge array anymore del Y potential = EvolutionPotential(observation_operator, moment_function_means, noise) proposer = pCNProposer(beta=0.5, prior=prior) accepter = CountedAccepter(pCNAccepter(potential=potential)) sampler = MCMCSampler(proposer, accepter, rng) u_0 = np.array([-1.9, 1.9, 0.9]) # start close to true theta n_samples = 2000 try: samples = np.load(data_dir + f"S_{K=}_{J=}_T={sim_length}_{r=}_{n_samples=}.npy") print("Loaded existing sampling results") except FileNotFoundError: print("Generating samples") samples = sampler.run(u_0=u_0, n_samples=n_samples, burn_in=100, sample_interval=1) np.save(data_dir + f"S_{K=}_{J=}_T={sim_length}_{r=}_{n_samples=}", samples) print(f"{samples.shape=}") # to conform with the output-shape of # solve_ivp. Might be worthwile to change it in the sampler, # but then I break older scripts samples = samples.T # Add pertubations to means for i in range(len(samples[0, :])): samples[:, i] += prior_means # Plot densities priors = [ GaussianDistribution(mu, np.sqrt(sigma_sq)) for mu, sigma_sq in zip(prior_means, np.diag(prior_covariance)) ] intervals = [(-5, 25)] * 3 names = ["F", "h", "b"] fig, plts = plt.subplots(1, 3, figsize=(20, 10)) plot_info = zip(priors, intervals, [theta[0], theta[1], theta[3]], names, plts) for i, (prior, interval, true_val, name, ax) in enumerate(plot_info): ax.hist(samples[i, :], density=True) x_range = np.linspace(*interval) ax.plot(x_range, [prior(x) for x in x_range]) ax.axvline(true_val, c='r') ax.set_title(f"Prior and posterior for {name}") ax.set(xlabel=name, ylabel="Probability") fig.suptitle("Posteriors and priors") store_figure(f"combined_{K=}_{J=}_T={sim_length}_{r=}") # Average the autocorrelation ac = np.zeros((3, 100)) n = 10 for i in range(1, 1 + n): for var in range(3): ac[var, :] += MCMCSampler.autocorr(samples[var, i * 100:(i + 1) * 100]) ac /= n plt.plot(ac[0, :], label="F") plt.plot(ac[1, :], label="h") plt.plot(ac[2, :], label="b") plt.title("Autocorrelation") plt.xlabel("Lag") plt.legend() store_figure(f"lorenz_ac_avg_{K=}_{J=}_T={sim_length}_{r=}")