def test_scalar_ode_2_param(self): """Test running model for a scalar ODE with 2 parameters""" def system(y, t, p): return p[0] * np.exp(-p[0] * t) - p[1] * y[0] times = np.array( [0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5] ) yobs = np.array( [0.31, 0.57, 0.51, 0.55, 0.47, 0.42, 0.38, 0.3, 0.26, 0.22, 0.22, 0.14, 0.14, 0.09, 0.1] )[:, np.newaxis] ode_model = DifferentialEquation(func=system, t0=0, times=times, n_states=1, n_theta=2) with pm.Model() as model: alpha = pm.HalfCauchy("alpha", 1) beta = pm.HalfCauchy("beta", 1) y0 = pm.LogNormal("y0", 0, 1) sigma = pm.HalfCauchy("sigma", 1) forward = ode_model(theta=[alpha, beta], y0=[y0]) y = pm.LogNormal("y", mu=pm.math.log(forward), sd=sigma, observed=yobs) idata = pm.sample(100, tune=0, chains=1) assert idata.posterior["alpha"].shape == (1, 100) assert idata.posterior["beta"].shape == (1, 100) assert idata.posterior["y0"].shape == (1, 100) assert idata.posterior["sigma"].shape == (1, 100)
def test_scalar_ode_1_param(self): """Test running model for a scalar ODE with 1 parameter""" def system(y, t, p): return np.exp(-t) - p[0] * y[0] times = np.array( [0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5] ) yobs = np.array( [0.31, 0.57, 0.51, 0.55, 0.47, 0.42, 0.38, 0.3, 0.26, 0.22, 0.22, 0.14, 0.14, 0.09, 0.1] )[:, np.newaxis] ode_model = DifferentialEquation(func=system, t0=0, times=times, n_states=1, n_theta=1) with pm.Model() as model: alpha = pm.HalfCauchy("alpha", 1) y0 = pm.LogNormal("y0", 0, 1) sigma = pm.HalfCauchy("sigma", 1) forward = ode_model(theta=[alpha], y0=[y0]) y = pm.LogNormal("y", mu=pm.math.log(forward), sigma=sigma, observed=yobs) with aesara.config.change_flags(mode=fast_unstable_sampling_mode): idata = pm.sample(50, tune=0, chains=1) assert idata.posterior["alpha"].shape == (1, 50) assert idata.posterior["y0"].shape == (1, 50) assert idata.posterior["sigma"].shape == (1, 50)
def test_nested_initvals(self): # See issue #5168 with pm.Model() as pmodel: one = pm.LogNormal("one", mu=np.log(1), sigma=1e-5, initval="prior") two = pm.Lognormal("two", mu=np.log(one * 2), sigma=1e-5, initval="prior") three = pm.LogNormal("three", mu=np.log(two * 2), sigma=1e-5, initval="prior") four = pm.LogNormal("four", mu=np.log(three * 2), sigma=1e-5, initval="prior") five = pm.LogNormal("five", mu=np.log(four * 2), sigma=1e-5, initval="prior") six = pm.LogNormal("six", mu=np.log(five * 2), sigma=1e-5, initval="prior") ip_vals = list( make_initial_point_fn(model=pmodel, return_transformed=True)(0).values()) assert np.allclose(np.exp(ip_vals), [1, 2, 4, 8, 16, 32], rtol=1e-3) ip_vals = list( make_initial_point_fn(model=pmodel, return_transformed=False)(0).values()) assert np.allclose(ip_vals, [1, 2, 4, 8, 16, 32], rtol=1e-3) pmodel.initial_values[four] = 1 ip_vals = list( make_initial_point_fn(model=pmodel, return_transformed=True)(0).values()) assert np.allclose(np.exp(ip_vals), [1, 2, 4, 1, 2, 4], rtol=1e-3) ip_vals = list( make_initial_point_fn(model=pmodel, return_transformed=False)(0).values()) assert np.allclose(ip_vals, [1, 2, 4, 1, 2, 4], rtol=1e-3)
def test_model_logp(jacobian): with pm.Model() as m: x = pm.Normal("x", 0, 1, size=2) y = pm.LogNormal("y", 0, 1, size=2) test_vals = np.array([0.0, 1.0]) expected_x_logp = st.norm().logpdf(test_vals) expected_y_logp = expected_x_logp.copy() if not jacobian: expected_y_logp -= np.array([0.0, 1.0]) x_logp, y_logp = m.compile_logp(sum=False, jacobian=jacobian)( {"x": test_vals, "y_log__": test_vals} ) assert np.all(np.isclose(x_logp, expected_x_logp)) assert np.all(np.isclose(y_logp, expected_y_logp)) x_logp2 = m.compile_logp(vars=[x], sum=False, jacobian=jacobian)({"x": test_vals}) assert np.all(np.isclose(x_logp2, expected_x_logp)) y_logp2 = m.compile_logp(vars=[y], sum=False, jacobian=jacobian)({"y_log__": test_vals}) assert np.all(np.isclose(y_logp2, expected_y_logp)) logp_sum = m.compile_logp(sum=True, jacobian=jacobian)({"x": test_vals, "y_log__": test_vals}) assert np.isclose(logp_sum, expected_x_logp.sum() + expected_y_logp.sum())
def test_model_logpt_deprecation_warning(): with pm.Model() as m: x = pm.Normal("x", 0, 1, size=2) y = pm.LogNormal("y", 0, 1, size=2) with pytest.warns(FutureWarning): m.logpt() with pytest.warns(FutureWarning): m.dlogpt() with pytest.warns(FutureWarning): m.d2logpt() with pytest.warns(FutureWarning): m.datalogpt with pytest.warns(FutureWarning): m.varlogpt with pytest.warns(FutureWarning): m.observedlogpt with pytest.warns(FutureWarning): m.potentiallogpt with pytest.warns(FutureWarning): m.varlogp_nojact
def test_vector_ode_1_param(self): """Test running model for a vector ODE with 1 parameter""" def system(y, t, p): ds = -p[0] * y[0] * y[1] di = p[0] * y[0] * y[1] - y[1] return [ds, di] times = np.array( [0.0, 0.8, 1.6, 2.4, 3.2, 4.0, 4.8, 5.6, 6.4, 7.2, 8.0]) yobs = np.array([ [1.02, 0.02], [0.86, 0.12], [0.43, 0.37], [0.14, 0.42], [0.05, 0.43], [0.03, 0.14], [0.02, 0.08], [0.02, 0.04], [0.02, 0.01], [0.02, 0.01], [0.02, 0.01], ]) ode_model = DifferentialEquation(func=system, t0=0, times=times, n_states=2, n_theta=1) with pm.Model() as model: R = pm.LogNormal("R", 1, 5, initval=1) sigma = pm.HalfCauchy("sigma", 1, shape=2, initval=[0.5, 0.5]) forward = ode_model(theta=[R], y0=[0.99, 0.01]) y = pm.LogNormal("y", mu=pm.math.log(forward), sigma=sigma, observed=yobs) with aesara.config.change_flags(mode=fast_unstable_sampling_mode): idata = pm.sample(50, tune=0, chains=1) assert idata.posterior["R"].shape == (1, 50) assert idata.posterior["sigma"].shape == (1, 50, 2)
def test_rvs_to_value_vars_nested(): # Test that calling rvs_to_value_vars in models with nested transformations # does not change the original rvs in place. See issue #5172 with pm.Model() as m: one = pm.LogNormal("one", mu=0) two = pm.LogNormal("two", mu=at.log(one)) # We add potentials or deterministics that are not in topological order pm.Potential("two_pot", two) pm.Potential("one_pot", one) before = aesara.clone_replace(m.free_RVs) # This call would change the model free_RVs in place in #5172 res, _ = rvs_to_value_vars(m.potentials, apply_transforms=True) after = aesara.clone_replace(m.free_RVs) assert equal_computations(before, after)
def track_1var_2par_ode_ess(self): def freefall(y, t, p): return 2.0 * p[1] - p[0] * y[0] # Times for observation times = np.arange(0, 10, 0.5) y = np.array([ -2.01, 9.49, 15.58, 16.57, 27.58, 32.26, 35.13, 38.07, 37.36, 38.83, 44.86, 43.58, 44.59, 42.75, 46.9, 49.32, 44.06, 49.86, 46.48, 48.18, ]).reshape(-1, 1) ode_model = pm.ode.DifferentialEquation(func=freefall, times=times, n_states=1, n_theta=2, t0=0) with pm.Model() as model: # Specify prior distributions for some of our model parameters sigma = pm.HalfCauchy("sigma", 1) gamma = pm.LogNormal("gamma", 0, 1) # If we know one of the parameter values, we can simply pass the value. ode_solution = ode_model(y0=[0], theta=[gamma, 9.8]) # The ode_solution has a shape of (n_times, n_states) Y = pm.Normal("Y", mu=ode_solution, sd=sigma, observed=y) t0 = time.time() idata = pm.sample(500, tune=1000, chains=2, cores=2, random_seed=0) tot = time.time() - t0 ess = az.ess(idata) return np.mean([ess.sigma, ess.gamma]) / tot
def test_eval_rv_shapes(self): with pm.Model(coords={ "city": ["Sydney", "Las Vegas", "Düsseldorf"], }) as pmodel: pm.Data("budget", [1, 2, 3, 4], dims="year") pm.Normal("untransformed", size=(1, 2)) pm.Uniform("transformed", size=(7, )) obs = pm.Uniform("observed", size=(3, ), observed=[0.1, 0.2, 0.3]) pm.LogNormal("lognorm", mu=at.log(obs)) pm.Normal("from_dims", dims=("city", "year")) shapes = pmodel.eval_rv_shapes() assert shapes["untransformed"] == (1, 2) assert shapes["transformed"] == (7, ) assert shapes["transformed_interval__"] == (7, ) assert shapes["lognorm"] == (3, ) assert shapes["lognorm_log__"] == (3, ) assert shapes["from_dims"] == (3, 4)
def test_vector_ode_2_param(self): """Test running model for a vector ODE with 2 parameters""" def system(y, t, p): ds = -p[0] * y[0] * y[1] di = p[0] * y[0] * y[1] - p[1] * y[1] return [ds, di] times = np.array( [0.0, 0.8, 1.6, 2.4, 3.2, 4.0, 4.8, 5.6, 6.4, 7.2, 8.0]) yobs = np.array([ [1.02, 0.02], [0.86, 0.12], [0.43, 0.37], [0.14, 0.42], [0.05, 0.43], [0.03, 0.14], [0.02, 0.08], [0.02, 0.04], [0.02, 0.01], [0.02, 0.01], [0.02, 0.01], ]) ode_model = DifferentialEquation(func=system, t0=0, times=times, n_states=2, n_theta=2) with pm.Model() as model: beta = pm.HalfCauchy("beta", 1, initval=1) gamma = pm.HalfCauchy("gamma", 1, initval=1) sigma = pm.HalfCauchy("sigma", 1, shape=2, initval=[1, 1]) forward = ode_model(theta=[beta, gamma], y0=[0.99, 0.01]) y = pm.LogNormal("y", mu=pm.math.log(forward), sd=sigma, observed=yobs) idata = pm.sample(100, tune=0, chains=1) assert idata.posterior["beta"].shape == (1, 100) assert idata.posterior["gamma"].shape == (1, 100) assert idata.posterior["sigma"].shape == (1, 100, 2)
def test_edge_case(self): # Edge case discovered in #2948 ndim = 3 with pm.Model() as m: pm.LogNormal("sigma", mu=np.zeros(ndim), tau=np.ones(ndim), shape=ndim) # variance for the correlation matrix pm.HalfCauchy("nu", beta=10) step = pm.NUTS() func = step._logp_dlogp_func func.set_extra_values(m.initial_point) q = func.dict_to_array(m.initial_point) logp, dlogp = func(q) assert logp.size == 1 assert dlogp.size == 4 npt.assert_allclose(dlogp, 0.0, atol=1e-5)
def test_sample_find_MAP_does_not_modify_start(): # see https://github.com/pymc-devs/pymc/pull/4458 with pm.Model(): pm.LogNormal("untransformed") # make sure find_Map does not modify the start dict start = {"untransformed": 2} pm.find_MAP(start=start) assert start == {"untransformed": 2} # make sure sample does not modify the start dict start = {"untransformed": 0.2} pm.sample(draws=10, step=pm.Metropolis(), tune=5, start=start, chains=3) assert start == {"untransformed": 0.2} # make sure sample does not modify the start when passes as list of dict start = [{"untransformed": 2}, {"untransformed": 0.2}] pm.sample(draws=10, step=pm.Metropolis(), tune=5, start=start, chains=2) assert start == [{"untransformed": 2}, {"untransformed": 0.2}]
def test_model_d2logp(jacobian): with pm.Model() as m: x = pm.Normal("x", 0, 1, size=2) y = pm.LogNormal("y", 0, 1, size=2) test_vals = np.array([0.0, -1.0]) state = {"x": test_vals, "y_log__": test_vals} expected_x_d2logp = expected_y_d2logp = np.eye(2) dlogps = m.compile_d2logp(jacobian=jacobian)(state) assert np.all(np.isclose(dlogps[:2, :2], expected_x_d2logp)) assert np.all(np.isclose(dlogps[2:, 2:], expected_y_d2logp)) x_dlogp2 = m.compile_d2logp(vars=[x], jacobian=jacobian)(state) assert np.all(np.isclose(x_dlogp2, expected_x_d2logp)) y_dlogp2 = m.compile_d2logp(vars=[y], jacobian=jacobian)(state) assert np.all(np.isclose(y_dlogp2, expected_y_d2logp))