def test_elemwise_velocity(): scaling = np.array([1, 2, 3]) x = floatX(np.ones_like(scaling)) pot = quadpotential.quad_potential(scaling, True) v = pot.velocity(x) npt.assert_allclose(v, scaling) assert v.dtype == pot.dtype
def test_random_diag(): d = np.arange(10) + 1 np.random.seed(42) pots = [ quadpotential.quad_potential(d, True), quadpotential.quad_potential(1.0 / d, False), quadpotential.quad_potential(np.diag(d), True), quadpotential.quad_potential(np.diag(1.0 / d), False), ] if quadpotential.chol_available: d_ = scipy.sparse.csc_matrix(np.diag(d)) pot = quadpotential.quad_potential(d_, True) pots.append(pot) for pot in pots: vals = np.array([pot.random() for _ in range(1000)]) npt.assert_allclose(vals.std(0), np.sqrt(1.0 / d), atol=0.1)
def test_equal_diag(): np.random.seed(42) for _ in range(3): diag = np.random.rand(5) x = floatX(np.random.randn(5)) pots = [ quadpotential.quad_potential(diag, False), quadpotential.quad_potential(1.0 / diag, True), quadpotential.quad_potential(np.diag(diag), False), quadpotential.quad_potential(np.diag(1.0 / diag), True), ] if quadpotential.chol_available: diag_ = scipy.sparse.csc_matrix(np.diag(1.0 / diag)) pots.append(quadpotential.quad_potential(diag_, True)) v = np.diag(1.0 / diag).dot(x) e = x.dot(np.diag(1.0 / diag).dot(x)) / 2 for pot in pots: v_ = pot.velocity(x) e_ = pot.energy(x) npt.assert_allclose(v_, v, rtol=1e-6) npt.assert_allclose(e_, e, rtol=1e-6)
def test_equal_dense(): np.random.seed(42) for _ in range(3): cov = np.random.rand(5, 5) cov += cov.T cov += 10 * np.eye(5) inv = np.linalg.inv(cov) npt.assert_allclose(inv.dot(cov), np.eye(5), atol=1e-10) x = floatX(np.random.randn(5)) pots = [ quadpotential.quad_potential(cov, False), quadpotential.quad_potential(inv, True), ] if quadpotential.chol_available: pots.append(quadpotential.quad_potential(cov, False)) v = np.linalg.solve(cov, x) e = 0.5 * x.dot(v) for pot in pots: v_ = pot.velocity(x) e_ = pot.energy(x) npt.assert_allclose(v_, v, rtol=1e-4) npt.assert_allclose(e_, e, rtol=1e-4)
def test_elemwise_energy(): scaling = np.array([1, 2, 3]) x = floatX(np.ones_like(scaling)) pot = quadpotential.quad_potential(scaling, True) energy = pot.energy(x) npt.assert_allclose(energy, 0.5 * scaling.sum())
def test_elemwise_posdef(): scaling = np.array([0, 2, 3]) with pytest.raises(quadpotential.PositiveDefiniteError): quadpotential.quad_potential(scaling, True)
def __init__( self, vars=None, scaling=None, step_scale=0.25, is_cov=False, model=None, blocked=True, potential=None, dtype=None, Emax=1000, target_accept=0.8, gamma=0.05, k=0.75, t0=10, adapt_step_size=True, step_rand=None, **aesara_kwargs ): """Set up Hamiltonian samplers with common structures. Parameters ---------- vars: list, default=None List of Aesara variables. If None, all continuous RVs from the model are included. scaling: array_like, ndim={1,2} Scaling for momentum distribution. 1d arrays interpreted matrix diagonal. step_scale: float, default=0.25 Size of steps to take, automatically scaled down by 1/n**(1/4), where n is the dimensionality of the parameter space is_cov: bool, default=False Treat scaling as a covariance matrix/vector if True, else treat it as a precision matrix/vector model: pymc.Model blocked: bool, default=True potential: Potential, optional An object that represents the Hamiltonian with methods `velocity`, `energy`, and `random` methods. **aesara_kwargs: passed to Aesara functions """ self._model = modelcontext(model) if vars is None: vars = self._model.cont_vars else: vars = [self._model.rvs_to_values.get(var, var) for var in vars] super().__init__(vars, blocked=blocked, model=self._model, dtype=dtype, **aesara_kwargs) self.adapt_step_size = adapt_step_size self.Emax = Emax self.iter_count = 0 # We're using the initial/test point to determine the (initial) step # size. # XXX: If the dimensions of these terms change, the step size # dimension-scaling should change as well, no? test_point = self._model.initial_point nuts_vars = [test_point[v.name] for v in vars] size = sum(v.size for v in nuts_vars) self.step_size = step_scale / (size ** 0.25) self.step_adapt = step_sizes.DualAverageAdaptation( self.step_size, target_accept, gamma, k, t0 ) self.target_accept = target_accept self.tune = True if scaling is None and potential is None: mean = floatX(np.zeros(size)) var = floatX(np.ones(size)) potential = QuadPotentialDiagAdapt(size, mean, var, 10) if isinstance(scaling, dict): point = Point(scaling, model=self._model) scaling = guess_scaling(point, model=self._model, vars=vars) if scaling is not None and potential is not None: raise ValueError("Can not specify both potential and scaling.") if potential is not None: self.potential = potential else: self.potential = quad_potential(scaling, is_cov) self.integrator = integration.CpuLeapfrogIntegrator(self.potential, self._logp_dlogp_func) self._step_rand = step_rand self._warnings = [] self._samples_after_tune = 0 self._num_divs_sample = 0