def test_chain_jacob_det(): chain_tranf = tr.Chain([tr.logodds, tr.ordered]) check_jacobian_det(chain_tranf, Vector(R, 4), at.dvector, np.zeros(4), elemwise=False)
def test_exponential_ordered(self, lam, size): initval = np.sort(np.abs(np.random.randn(*size))) model = self.build_model( pm.Exponential, {"lam": lam}, size=size, initval=initval, transform=tr.Chain([tr.log, tr.ordered]), ) self.check_vectortransform_elementwise_logp(model)
def test_half_normal_ordered(self, sigma, size): initval = np.sort(np.abs(np.random.randn(*size))) model = self.build_model( pm.HalfNormal, {"sigma": sigma}, size=size, initval=initval, transform=tr.Chain([tr.log, tr.ordered]), ) self.check_vectortransform_elementwise_logp(model)
def test_vonmises_ordered(self, mu, kappa, size): initval = np.sort(np.abs(np.random.rand(*size))) model = self.build_model( pm.VonMises, {"mu": mu, "kappa": kappa}, size=size, initval=initval, transform=tr.Chain([tr.circular, tr.ordered]), ) self.check_vectortransform_elementwise_logp(model)
def test_beta_ordered(self, a, b, size): initval = np.sort(np.abs(np.random.rand(*size))) model = self.build_model( pm.Beta, {"alpha": a, "beta": b}, size=size, initval=initval, transform=tr.Chain([tr.logodds, tr.ordered]), ) self.check_vectortransform_elementwise_logp(model)
def test_uniform_ordered(self, lower, upper, size): def transform_params(*inputs): _, _, _, lower, upper = inputs lower = at.as_tensor_variable(lower) if lower is not None else None upper = at.as_tensor_variable(upper) if upper is not None else None return lower, upper interval = tr.Interval(bounds_fn=transform_params) initval = np.sort(np.abs(np.random.rand(*size))) model = self.build_model( pm.Uniform, {"lower": lower, "upper": upper}, size=size, initval=initval, transform=tr.Chain([interval, tr.ordered]), ) self.check_vectortransform_elementwise_logp(model)
class TestElementWiseLogp(SeededTest): def build_model(self, distfam, params, size, transform, initval=None): if initval is not None: initval = pm.floatX(initval) with pm.Model() as m: distfam("x", size=size, transform=transform, initval=initval, **params) return m def check_transform_elementwise_logp(self, model): x = model.free_RVs[0] x_val_transf = x.tag.value_var pt = model.initial_point(0) test_array_transf = floatX( np.random.randn(*pt[x_val_transf.name].shape)) transform = x_val_transf.tag.transform test_array_untransf = transform.backward(test_array_transf, *x.owner.inputs).eval() # Create input variable with same dimensionality as untransformed test_array x_val_untransf = at.constant(test_array_untransf).type() jacob_det = transform.log_jac_det(test_array_transf, *x.owner.inputs) assert joint_logpt(x, sum=False)[0].ndim == x.ndim == jacob_det.ndim v1 = joint_logpt(x, x_val_transf, jacobian=False).eval( {x_val_transf: test_array_transf}) v2 = joint_logpt(x, x_val_untransf, transformed=False).eval( {x_val_untransf: test_array_untransf}) close_to(v1, v2, tol) def check_vectortransform_elementwise_logp(self, model): x = model.free_RVs[0] x_val_transf = x.tag.value_var pt = model.initial_point(0) test_array_transf = floatX( np.random.randn(*pt[x_val_transf.name].shape)) transform = x_val_transf.tag.transform test_array_untransf = transform.backward(test_array_transf, *x.owner.inputs).eval() # Create input variable with same dimensionality as untransformed test_array x_val_untransf = at.constant(test_array_untransf).type() jacob_det = transform.log_jac_det(test_array_transf, *x.owner.inputs) # Original distribution is univariate if x.owner.op.ndim_supp == 0: assert joint_logpt( x, sum=False)[0].ndim == x.ndim == (jacob_det.ndim + 1) # Original distribution is multivariate else: assert joint_logpt( x, sum=False)[0].ndim == (x.ndim - 1) == jacob_det.ndim a = joint_logpt(x, x_val_transf, jacobian=False).eval({x_val_transf: test_array_transf}) b = joint_logpt(x, x_val_untransf, transformed=False).eval( {x_val_untransf: test_array_untransf}) # Hack to get relative tolerance close_to(a, b, np.abs(0.5 * (a + b) * tol)) @pytest.mark.parametrize( "sigma,size", [ (2.5, 2), (5.0, (2, 3)), (np.ones(3) * 10.0, (4, 3)), ], ) def test_half_normal(self, sigma, size): model = self.build_model(pm.HalfNormal, {"sigma": sigma}, size=size, transform=tr.log) self.check_transform_elementwise_logp(model) @pytest.mark.parametrize("lam,size", [(2.5, 2), (5.0, (2, 3)), (np.ones(3), (4, 3))]) def test_exponential(self, lam, size): model = self.build_model(pm.Exponential, {"lam": lam}, size=size, transform=tr.log) self.check_transform_elementwise_logp(model) @pytest.mark.parametrize( "a,b,size", [ (1.0, 1.0, 2), (0.5, 0.5, (2, 3)), (np.ones(3), np.ones(3), (4, 3)), ], ) def test_beta(self, a, b, size): model = self.build_model(pm.Beta, { "alpha": a, "beta": b }, size=size, transform=tr.logodds) self.check_transform_elementwise_logp(model) @pytest.mark.parametrize( "lower,upper,size", [ (0.0, 1.0, 2), (0.5, 5.5, (2, 3)), (pm.floatX(np.zeros(3)), pm.floatX(np.ones(3)), (4, 3)), ], ) def test_uniform(self, lower, upper, size): def transform_params(*inputs): _, _, _, lower, upper = inputs lower = at.as_tensor_variable(lower) if lower is not None else None upper = at.as_tensor_variable(upper) if upper is not None else None return lower, upper interval = tr.Interval(bounds_fn=transform_params) model = self.build_model(pm.Uniform, { "lower": lower, "upper": upper }, size=size, transform=interval) self.check_transform_elementwise_logp(model) @pytest.mark.parametrize( "lower, c, upper, size", [ (0.0, 1.0, 2.0, 2), (-10, 0, 200, (2, 3)), (np.zeros(3), np.ones(3), np.ones(3), (4, 3)), ], ) def test_triangular(self, lower, c, upper, size): def transform_params(*inputs): _, _, _, lower, _, upper = inputs lower = at.as_tensor_variable(lower) if lower is not None else None upper = at.as_tensor_variable(upper) if upper is not None else None return lower, upper interval = tr.Interval(bounds_fn=transform_params) model = self.build_model(pm.Triangular, { "lower": lower, "c": c, "upper": upper }, size=size, transform=interval) self.check_transform_elementwise_logp(model) @pytest.mark.parametrize("mu,kappa,size", [(0.0, 1.0, 2), (-0.5, 5.5, (2, 3)), (np.zeros(3), np.ones(3), (4, 3))]) def test_vonmises(self, mu, kappa, size): model = self.build_model(pm.VonMises, { "mu": mu, "kappa": kappa }, size=size, transform=tr.circular) self.check_transform_elementwise_logp(model) @pytest.mark.parametrize("a,size", [(np.ones(2), None), (np.ones((2, 3)) * 0.5, None), (np.ones(3), (4, ))]) def test_dirichlet(self, a, size): model = self.build_model(pm.Dirichlet, {"a": a}, size=size, transform=tr.simplex) self.check_vectortransform_elementwise_logp(model) def test_normal_ordered(self): model = self.build_model( pm.Normal, { "mu": 0.0, "sigma": 1.0 }, size=3, initval=np.asarray([-1.0, 1.0, 4.0]), transform=tr.ordered, ) self.check_vectortransform_elementwise_logp(model) @pytest.mark.parametrize( "sigma,size", [ (2.5, (2, )), (np.ones(3), (4, 3)), ], ) def test_half_normal_ordered(self, sigma, size): initval = np.sort(np.abs(np.random.randn(*size))) model = self.build_model( pm.HalfNormal, {"sigma": sigma}, size=size, initval=initval, transform=tr.Chain([tr.log, tr.ordered]), ) self.check_vectortransform_elementwise_logp(model) @pytest.mark.parametrize("lam,size", [(2.5, (2, )), (np.ones(3), (4, 3))]) def test_exponential_ordered(self, lam, size): initval = np.sort(np.abs(np.random.randn(*size))) model = self.build_model( pm.Exponential, {"lam": lam}, size=size, initval=initval, transform=tr.Chain([tr.log, tr.ordered]), ) self.check_vectortransform_elementwise_logp(model) @pytest.mark.parametrize( "a,b,size", [ ( 1.0, 1.0, (2, ), ), (np.ones(3), np.ones(3), (4, 3)), ], ) def test_beta_ordered(self, a, b, size): initval = np.sort(np.abs(np.random.rand(*size))) model = self.build_model( pm.Beta, { "alpha": a, "beta": b }, size=size, initval=initval, transform=tr.Chain([tr.logodds, tr.ordered]), ) self.check_vectortransform_elementwise_logp(model) @pytest.mark.parametrize( "lower,upper,size", [(0.0, 1.0, (2, )), (pm.floatX(np.zeros(3)), pm.floatX(np.ones(3)), (4, 3))], ) def test_uniform_ordered(self, lower, upper, size): def transform_params(*inputs): _, _, _, lower, upper = inputs lower = at.as_tensor_variable(lower) if lower is not None else None upper = at.as_tensor_variable(upper) if upper is not None else None return lower, upper interval = tr.Interval(bounds_fn=transform_params) initval = np.sort(np.abs(np.random.rand(*size))) model = self.build_model( pm.Uniform, { "lower": lower, "upper": upper }, size=size, initval=initval, transform=tr.Chain([interval, tr.ordered]), ) self.check_vectortransform_elementwise_logp(model) @pytest.mark.parametrize("mu,kappa,size", [(0.0, 1.0, (2, )), (np.zeros(3), np.ones(3), (4, 3))]) def test_vonmises_ordered(self, mu, kappa, size): initval = np.sort(np.abs(np.random.rand(*size))) model = self.build_model( pm.VonMises, { "mu": mu, "kappa": kappa }, size=size, initval=initval, transform=tr.Chain([tr.circular, tr.ordered]), ) self.check_vectortransform_elementwise_logp(model) @pytest.mark.parametrize( "lower,upper,size,transform", [ (0.0, 1.0, (2, ), tr.simplex), (0.5, 5.5, (2, 3), tr.simplex), (np.zeros(3), np.ones(3), (4, 3), tr.Chain([tr.sum_to_1, tr.logodds])), ], ) def test_uniform_other(self, lower, upper, size, transform): initval = np.ones(size) / size[-1] model = self.build_model( pm.Uniform, { "lower": lower, "upper": upper }, size=size, initval=initval, transform=transform, ) self.check_vectortransform_elementwise_logp(model) @pytest.mark.parametrize( "mu,cov,size,shape", [ (np.zeros(2), np.diag(np.ones(2)), None, (2, )), (np.zeros(3), np.diag(np.ones(3)), (4, ), (4, 3)), ], ) def test_mvnormal_ordered(self, mu, cov, size, shape): initval = np.sort(np.random.randn(*shape)) model = self.build_model(pm.MvNormal, { "mu": mu, "cov": cov }, size=size, initval=initval, transform=tr.ordered) self.check_vectortransform_elementwise_logp(model)
def test_chain_vector_transform(): chain_tranf = tr.Chain([tr.logodds, tr.ordered]) check_vector_transform(chain_tranf, UnitSortedVector(3))
def test_chain_values(): chain_tranf = tr.Chain([tr.logodds, tr.ordered]) vals = get_values(chain_tranf, Vector(R, 5), at.dvector, np.zeros(5)) close_to_logical(np.diff(vals) >= 0, True, tol)
class TestElementWiseLogp(SeededTest): def build_model(self, distfam, params, size, transform, initval=None): if initval is not None: initval = pm.floatX(initval) with pm.Model() as m: distfam("x", size=size, transform=transform, initval=initval, **params) return m def check_transform_elementwise_logp(self, model): x = model.free_RVs[0] x0 = x.tag.value_var assert x.ndim == logpt(x, sum=False).ndim pt = model.initial_point array = np.random.randn(*pt[x0.name].shape) transform = x0.tag.transform logp_notrans = logpt(x, transform.backward(array, *x.owner.inputs), transformed=False) jacob_det = transform.log_jac_det(aesara.shared(array), *x.owner.inputs) assert logpt(x, sum=False).ndim == jacob_det.ndim v1 = logpt(x, array, jacobian=False).eval() v2 = logp_notrans.eval() close_to(v1, v2, tol) def check_vectortransform_elementwise_logp(self, model, vect_opt=0): x = model.free_RVs[0] x0 = x.tag.value_var # TODO: For some reason the ndim relations # dont hold up here. But final log-probablity # values are what we expected. # assert (x.ndim - 1) == logpt(x, sum=False).ndim pt = model.initial_point array = np.random.randn(*pt[x0.name].shape) transform = x0.tag.transform logp_nojac = logpt(x, transform.backward(array, *x.owner.inputs), transformed=False) jacob_det = transform.log_jac_det(aesara.shared(array), *x.owner.inputs) # assert logpt(x).ndim == jacob_det.ndim # Hack to get relative tolerance a = logpt(x, array.astype(aesara.config.floatX), jacobian=False).eval() b = logp_nojac.eval() close_to(a, b, np.abs(0.5 * (a + b) * tol)) @pytest.mark.parametrize( "sd,size", [ (2.5, 2), (5.0, (2, 3)), (np.ones(3) * 10.0, (4, 3)), ], ) def test_half_normal(self, sd, size): model = self.build_model(pm.HalfNormal, {"sd": sd}, size=size, transform=tr.log) self.check_transform_elementwise_logp(model) @pytest.mark.parametrize("lam,size", [(2.5, 2), (5.0, (2, 3)), (np.ones(3), (4, 3))]) def test_exponential(self, lam, size): model = self.build_model(pm.Exponential, {"lam": lam}, size=size, transform=tr.log) self.check_transform_elementwise_logp(model) @pytest.mark.parametrize( "a,b,size", [ (1.0, 1.0, 2), (0.5, 0.5, (2, 3)), (np.ones(3), np.ones(3), (4, 3)), ], ) def test_beta(self, a, b, size): model = self.build_model(pm.Beta, { "alpha": a, "beta": b }, size=size, transform=tr.logodds) self.check_transform_elementwise_logp(model) @pytest.mark.parametrize( "lower,upper,size", [ (0.0, 1.0, 2), (0.5, 5.5, (2, 3)), (pm.floatX(np.zeros(3)), pm.floatX(np.ones(3)), (4, 3)), ], ) def test_uniform(self, lower, upper, size): def transform_params(*inputs): _, _, _, lower, upper = inputs lower = at.as_tensor_variable(lower) if lower is not None else None upper = at.as_tensor_variable(upper) if upper is not None else None return lower, upper interval = tr.interval(transform_params) model = self.build_model(pm.Uniform, { "lower": lower, "upper": upper }, size=size, transform=interval) self.check_transform_elementwise_logp(model) @pytest.mark.parametrize( "lower, c, upper, size", [ (0.0, 1.0, 2.0, 2), (-10, 0, 200, (2, 3)), (np.zeros(3), np.ones(3), np.ones(3), (4, 3)), ], ) def test_triangular(self, lower, c, upper, size): def transform_params(*inputs): _, _, _, lower, _, upper = inputs lower = at.as_tensor_variable(lower) if lower is not None else None upper = at.as_tensor_variable(upper) if upper is not None else None return lower, upper interval = tr.interval(transform_params) model = self.build_model(pm.Triangular, { "lower": lower, "c": c, "upper": upper }, size=size, transform=interval) self.check_transform_elementwise_logp(model) @pytest.mark.parametrize("mu,kappa,size", [(0.0, 1.0, 2), (-0.5, 5.5, (2, 3)), (np.zeros(3), np.ones(3), (4, 3))]) def test_vonmises(self, mu, kappa, size): model = self.build_model(pm.VonMises, { "mu": mu, "kappa": kappa }, size=size, transform=tr.circular) self.check_transform_elementwise_logp(model) @pytest.mark.parametrize("a,size", [(np.ones(2), None), (np.ones((2, 3)) * 0.5, None), (np.ones(3), (4, ))]) def test_dirichlet(self, a, size): model = self.build_model(pm.Dirichlet, {"a": a}, size=size, transform=tr.simplex) self.check_vectortransform_elementwise_logp(model, vect_opt=1) def test_normal_ordered(self): model = self.build_model( pm.Normal, { "mu": 0.0, "sd": 1.0 }, size=3, initval=np.asarray([-1.0, 1.0, 4.0]), transform=tr.ordered, ) self.check_vectortransform_elementwise_logp(model, vect_opt=0) @pytest.mark.parametrize( "sd,size", [ (2.5, (2, )), (np.ones(3), (4, 3)), ], ) def test_half_normal_ordered(self, sd, size): initval = np.sort(np.abs(np.random.randn(*size))) model = self.build_model( pm.HalfNormal, {"sd": sd}, size=size, initval=initval, transform=tr.Chain([tr.log, tr.ordered]), ) self.check_vectortransform_elementwise_logp(model, vect_opt=0) @pytest.mark.parametrize("lam,size", [(2.5, (2, )), (np.ones(3), (4, 3))]) def test_exponential_ordered(self, lam, size): initval = np.sort(np.abs(np.random.randn(*size))) model = self.build_model( pm.Exponential, {"lam": lam}, size=size, initval=initval, transform=tr.Chain([tr.log, tr.ordered]), ) self.check_vectortransform_elementwise_logp(model, vect_opt=0) @pytest.mark.parametrize( "a,b,size", [ ( 1.0, 1.0, (2, ), ), (np.ones(3), np.ones(3), (4, 3)), ], ) def test_beta_ordered(self, a, b, size): initval = np.sort(np.abs(np.random.rand(*size))) model = self.build_model( pm.Beta, { "alpha": a, "beta": b }, size=size, initval=initval, transform=tr.Chain([tr.logodds, tr.ordered]), ) self.check_vectortransform_elementwise_logp(model, vect_opt=0) @pytest.mark.parametrize( "lower,upper,size", [(0.0, 1.0, (2, )), (pm.floatX(np.zeros(3)), pm.floatX(np.ones(3)), (4, 3))], ) def test_uniform_ordered(self, lower, upper, size): def transform_params(*inputs): _, _, _, lower, upper = inputs lower = at.as_tensor_variable(lower) if lower is not None else None upper = at.as_tensor_variable(upper) if upper is not None else None return lower, upper interval = tr.interval(transform_params) initval = np.sort(np.abs(np.random.rand(*size))) model = self.build_model( pm.Uniform, { "lower": lower, "upper": upper }, size=size, initval=initval, transform=tr.Chain([interval, tr.ordered]), ) self.check_vectortransform_elementwise_logp(model, vect_opt=1) @pytest.mark.parametrize("mu,kappa,size", [(0.0, 1.0, (2, )), (np.zeros(3), np.ones(3), (4, 3))]) def test_vonmises_ordered(self, mu, kappa, size): initval = np.sort(np.abs(np.random.rand(*size))) model = self.build_model( pm.VonMises, { "mu": mu, "kappa": kappa }, size=size, initval=initval, transform=tr.Chain([tr.circular, tr.ordered]), ) self.check_vectortransform_elementwise_logp(model, vect_opt=0) @pytest.mark.parametrize( "lower,upper,size,transform", [ (0.0, 1.0, (2, ), tr.simplex), (0.5, 5.5, (2, 3), tr.simplex), (np.zeros(3), np.ones(3), (4, 3), tr.Chain([tr.sum_to_1, tr.logodds])), ], ) def test_uniform_other(self, lower, upper, size, transform): initval = np.ones(size) / size[-1] model = self.build_model( pm.Uniform, { "lower": lower, "upper": upper }, size=size, initval=initval, transform=transform, ) self.check_vectortransform_elementwise_logp(model, vect_opt=1) @pytest.mark.parametrize( "mu,cov,size,shape", [ (np.zeros(2), np.diag(np.ones(2)), None, (2, )), (np.zeros(3), np.diag(np.ones(3)), (4, ), (4, 3)), ], ) def test_mvnormal_ordered(self, mu, cov, size, shape): initval = np.sort(np.random.randn(*shape)) model = self.build_model(pm.MvNormal, { "mu": mu, "cov": cov }, size=size, initval=initval, transform=tr.ordered) self.check_vectortransform_elementwise_logp(model, vect_opt=1)