def test_pattern_array(self): array_pattern = paragami.NumericArrayPattern( shape=(4, ), lb=-1, ub=10.0) pattern_array = paragami.PatternArray((2, 3), array_pattern) valid_value = pattern_array.random() _test_pattern(self, pattern_array, valid_value) matrix_pattern = paragami.PSDSymmetricMatrixPattern(size=2) pattern_array = paragami.PatternArray((2, 3), matrix_pattern) valid_value = pattern_array.random() _test_pattern(self, pattern_array, valid_value) base_pattern_array = paragami.PatternArray((2, 1), matrix_pattern) pattern_array_array = paragami.PatternArray((1, 3), base_pattern_array) valid_value = pattern_array_array.random() _test_pattern(self, pattern_array_array, valid_value) # Test flat indices. matrix_pattern = paragami.PSDSymmetricMatrixPattern(size=2) pattern_array = paragami.PatternArray((2, 3), matrix_pattern) _test_array_flat_indices(self, pattern_array) self.assertTrue( paragami.PatternArray((3, 3), matrix_pattern) != paragami.PatternArray((2, 3), matrix_pattern)) self.assertTrue( paragami.PatternArray((2, 3), array_pattern) != paragami.PatternArray((2, 3), matrix_pattern)) pattern_array = paragami.PatternArray((2, 3), array_pattern) self.assertEqual((2, 3), pattern_array.array_shape()) self.assertEqual((2, 3, 4), pattern_array.shape()) self.assertTrue(array_pattern == pattern_array.base_pattern()) # Test bad arguments. with self.assertRaisesRegex(NotImplementedError, 'not numpy.ndarray types'): paragami.PatternArray((2, 3), paragami.PatternDict()) pattern_array = paragami.PatternArray((2, 3), array_pattern) with self.assertRaisesRegex(ValueError, 'Wrong number of dimensions'): pattern_array.flatten(np.full((2, 3), 0), free=False) with self.assertRaisesRegex(ValueError, 'Wrong number of dimensions'): pattern_array.flatten(np.full((2, 3, 4, 5), 0), free=False) with self.assertRaisesRegex(ValueError, 'Wrong shape'): pattern_array.flatten(np.full((2, 3, 5), 0), free=False) with self.assertRaisesRegex(ValueError, 'Bad value'): pattern_array.flatten(np.full((2, 3, 4), -10), free=False) with self.assertRaisesRegex(ValueError, 'must be a 1d vector'): pattern_array.fold(np.full((24, 1), -10), free=False) with self.assertRaisesRegex(ValueError, 'Wrong size'): pattern_array.fold(np.full((25, ), -10), free=False)
def test_psdsymmetric_matrix_patterns(self): dim = 3 valid_value = np.eye(dim) * 3 + np.full((dim, dim), 0.1) pattern = paragami.PSDSymmetricMatrixPattern(dim) _test_pattern(self, pattern, valid_value) pattern = paragami.PSDSymmetricMatrixPattern(dim, diag_lb=0.5) _test_pattern(self, pattern, valid_value) self.assertTrue( paragami.PSDSymmetricMatrixPattern(3) != paragami.PSDSymmetricMatrixPattern(4)) self.assertTrue( paragami.PSDSymmetricMatrixPattern(3, diag_lb=2) != paragami.PSDSymmetricMatrixPattern(3)) pattern = paragami.PSDSymmetricMatrixPattern(dim, diag_lb=0.5) self.assertEqual(dim, pattern.size()) self.assertEqual((dim, dim), pattern.shape()) self.assertEqual(0.5, pattern.diag_lb()) # Test bad inputs. with self.assertRaisesRegex(ValueError, 'diagonal lower bound'): paragami.PSDSymmetricMatrixPattern(3, diag_lb=-1) pattern = paragami.PSDSymmetricMatrixPattern(3, diag_lb=0.5) with self.assertRaisesRegex(ValueError, 'The matrix is not of shape'): pattern.flatten(np.eye(4), free=False) with self.assertRaisesRegex(ValueError, 'Diagonal is less than the lower bound'): pattern.flatten(0.25 * np.eye(3), free=False) with self.assertRaisesRegex(ValueError, 'not symmetric'): bad_mat = np.eye(3) bad_mat[0, 1] = 0.1 pattern.flatten(bad_mat, free=False) flat_val = pattern.flatten(pattern.random(), free=False) with self.assertRaisesRegex( ValueError, 'The argument to fold must be a 1d vector'): pattern.fold(np.atleast_2d(flat_val), free=False) flat_val = pattern.flatten(np.eye(3), free=False) with self.assertRaisesRegex(ValueError, 'Wrong length'): pattern.fold(flat_val[-1], free=False) flat_val = 0.25 * flat_val with self.assertRaisesRegex(ValueError, 'Diagonal is less than the lower bound'): pattern.fold(flat_val, free=False) # Test flat indices. pattern = paragami.PSDSymmetricMatrixPattern(3, diag_lb=0.5) _test_array_flat_indices(self, pattern)
def get_regression_array_pattern(num_obs, x_obs_dim): """Get a paragami pattern for an array of approximate regression posteriors. Parameters ------------- num_obs : `int` The number of distinct regressions. x_obs_dim : `int` The dimensionality of the regressors. Returns ---------- reg_params_pattern : A paragami pattern. The field ``beta_mean`` is the ordinary regression coefficient, and ``beta_info`` is the estimated inverse covariance matrix. The field ``y_info`` contains a point estimate for the inverse variance of each regressoin's residual. """ reg_params_pattern = paragami.PatternDict() reg_params_pattern['beta_mean'] = \ paragami.NumericArrayPattern(shape=(num_obs, x_obs_dim)) reg_params_pattern['beta_info'] = \ paragami.pattern_containers.PatternArray( array_shape=(num_obs, ), base_pattern=\ paragami.PSDSymmetricMatrixPattern(size=x_obs_dim)) reg_params_pattern['y_info'] = \ paragami.NumericVectorPattern(length=num_obs, lb=0.0) return reg_params_pattern
def get_prior_params_pattern(obs_dim, num_components): prior_params_pattern = paragami.PatternDict() prior_params_pattern['probs_alpha'] = \ paragami.NumericVectorPattern(length=num_components, lb=0.0) prior_params_pattern['centroid_prior_mean'] = \ paragami.NumericArrayPattern(shape=(num_components, obs_dim)) prior_params_pattern['centroid_prior_info'] = \ paragami.PSDSymmetricMatrixPattern(size=obs_dim) return prior_params_pattern
def get_small_test_pattern(): # autograd will pass invalid values, so turn off value checking. pattern = paragami.PatternDict() pattern['array'] = paragami.NumericArrayPattern((2, 3, 4), lb=-1, ub=10, default_validate=False) pattern['mat'] = paragami.PSDSymmetricMatrixPattern(3, default_validate=False) return pattern
def get_default_prior_params(dim): """ Returns a paragami patterned dictionary that stores the prior parameters. Default prior parameters are those set for the experiments in "Evaluating Sensitivity to the Stick Breaking Prior in Bayesian Nonparametrics" https://arxiv.org/abs/1810.06587 Parameters ---------- dim : int Dimension of the datapoints. Returns ------- prior_params_dict : dictionary A dictionary that contains the prior parameters. prior_params_paragami : paragami Patterned Dictionary A paragami patterned dictionary that contains the prior parameters. """ prior_params_dict = dict() prior_params_paragami = paragami.PatternDict() # DP prior parameter prior_params_dict['alpha'] = np.array([3.0]) prior_params_paragami['alpha'] = \ paragami.NumericArrayPattern(shape=(1, ), lb = 0.0) # prior on the centroids prior_params_dict['prior_centroid_mean'] = np.array([0.0]) prior_params_paragami['prior_centroid_mean'] = \ paragami.NumericArrayPattern(shape=(1, )) prior_params_dict['prior_centroid_info'] = np.array([0.1]) prior_params_paragami['prior_centroid_info'] = \ paragami.NumericArrayPattern(shape=(1, ), lb = 0.0) # prior on the variance prior_params_dict['prior_gamma_df'] = np.array([8.0]) prior_params_paragami['prior_gamma_df'] = \ paragami.NumericArrayPattern(shape=(1, ), lb = 0.0) prior_params_dict['prior_gamma_inv_scale'] = 0.62 * np.eye(dim) prior_params_paragami['prior_gamma_inv_scale'] = \ paragami.PSDSymmetricMatrixPattern(size=dim) return prior_params_dict, prior_params_paragami
def get_vb_params_paragami_object(dim, k_approx): """ Returns a paragami patterned dictionary that stores the variational parameters. Parameters ---------- dim : int Dimension of the datapoints. k_approx : int Number of components in the model. Returns ------- vb_params_dict : dictionary A dictionary that contains the variational parameters. vb_params_paragami : paragami patterned dictionary A paragami patterned dictionary that contains the variational parameters. """ vb_params_paragami = paragami.PatternDict() # cluster centroids vb_params_paragami['centroids'] = \ paragami.NumericArrayPattern(shape=(dim, k_approx)) # BNP sticks # variational distribution for each stick is logitnormal vb_params_paragami['stick_propn_mean'] = \ paragami.NumericArrayPattern(shape = (k_approx - 1,)) vb_params_paragami['stick_propn_info'] = \ paragami.NumericArrayPattern(shape = (k_approx - 1,), lb = 1e-4) # cluster covariances vb_params_paragami['gamma'] = \ paragami.pattern_containers.PatternArray(array_shape = (k_approx, ), \ base_pattern = paragami.PSDSymmetricMatrixPattern(size=dim)) vb_params_dict = vb_params_paragami.random() return vb_params_dict, vb_params_paragami
def get_test_pattern(): # autograd will pass invalid values, so turn off value checking. pattern = paragami.PatternDict() pattern['array'] = paragami.NumericArrayPattern((2, 3, 4), lb=-1, ub=20, default_validate=False) pattern['mat'] = paragami.PSDSymmetricMatrixPattern(3, default_validate=False) pattern['simplex'] = paragami.SimplexArrayPattern(2, (3, ), default_validate=False) subdict = paragami.PatternDict() subdict['array2'] = paragami.NumericArrayPattern((2, ), lb=-3, ub=10, default_validate=False) pattern['dict'] = subdict return pattern
def test_json_files(self): pattern = paragami.PatternDict() pattern['num'] = paragami.NumericArrayPattern((1, 2)) pattern['mat'] = paragami.PSDSymmetricMatrixPattern(5) val_folded = pattern.random() extra = np.random.random(5) outfile_name = '/tmp/paragami_test_' + str(np.random.randint(1e6)) paragami.save_folded(outfile_name, val_folded, pattern, extra=extra) val_folded_loaded, pattern_loaded, data = \ paragami.load_folded(outfile_name + '.npz') self.assertTrue(pattern_loaded == pattern) self.assertTrue(val_folded.keys() == val_folded_loaded.keys()) for keyname in val_folded.keys(): assert_array_almost_equal( val_folded[keyname], val_folded_loaded[keyname]) assert_array_almost_equal(extra, data['extra'])
def test_dictionary_patterns(self): def test_pattern(dict_pattern, dict_val): # autograd can't differentiate the folding of a dictionary # because it involves assignment to elements of a dictionary. _test_pattern(self, dict_pattern, dict_val, check_equal=check_dict_equal, jacobian_ad_test=False) def check_dict_equal(dict1, dict2): self.assertEqual(dict1.keys(), dict2.keys()) for key in dict1: if type(dict1[key]) is collections.OrderedDict: check_dict_equal(dict1[key], dict2[key]) else: assert_array_almost_equal(dict1[key], dict2[key]) print('dictionary pattern test: one element') dict_pattern = paragami.PatternDict() dict_pattern['a'] = \ paragami.NumericArrayPattern((2, 3, 4), lb=-1, ub=2) test_pattern(dict_pattern, dict_pattern.random()) print('dictionary pattern test: two elements') dict_pattern['b'] = \ paragami.NumericArrayPattern((5, ), lb=-1, ub=10) test_pattern(dict_pattern, dict_pattern.random()) print('dictionary pattern test: third matrix element') dict_pattern['c'] = \ paragami.PSDSymmetricMatrixPattern(size=3) test_pattern(dict_pattern, dict_pattern.random()) print('dictionary pattern test: sub-dictionary') subdict = paragami.PatternDict() subdict['suba'] = paragami.NumericArrayPattern((2, )) dict_pattern['d'] = subdict test_pattern(dict_pattern, dict_pattern.random()) # Test flat indices. _test_array_flat_indices(self, dict_pattern) # Test keys. self.assertEqual(list(dict_pattern.keys()), ['a', 'b', 'c', 'd']) # Check that it works with ordinary dictionaries, not only OrderedDict. print('dictionary pattern test: non-ordered dictionary') test_pattern(dict_pattern, dict(dict_pattern.random())) # Check deletion and non-equality. print('dictionary pattern test: deletion') old_dict_pattern = copy.deepcopy(dict_pattern) del dict_pattern['b'] self.assertTrue(dict_pattern != old_dict_pattern) test_pattern(dict_pattern, dict_pattern.random()) # Check modifying an existing array element. print('dictionary pattern test: modifying array') dict_pattern['a'] = paragami.NumericArrayPattern((2, ), lb=-1, ub=2) test_pattern(dict_pattern, dict_pattern.random()) # Check modifying an existing dictionary element. print('dictionary pattern test: modifying sub-dictionary') dict_pattern['d'] = \ paragami.NumericArrayPattern((4, ), lb=-1, ub=10) test_pattern(dict_pattern, dict_pattern.random()) # Check locking dict_pattern.lock() with self.assertRaises(ValueError): del dict_pattern['b'] with self.assertRaises(ValueError): dict_pattern['new'] = \ paragami.NumericArrayPattern((4, )) with self.assertRaises(ValueError): dict_pattern['a'] = \ paragami.NumericArrayPattern((4, )) # Check invalid values. bad_dict = dict_pattern.random() del bad_dict['a'] with self.assertRaisesRegex(ValueError, 'not in folded_val dictionary'): dict_pattern.flatten(bad_dict, free=True) bad_dict = dict_pattern.random() bad_dict['a'] = np.array(-10) with self.assertRaisesRegex(ValueError, 'is not valid'): dict_pattern.flatten(bad_dict, free=True) free_val = np.random.random(dict_pattern.flat_length(True)) with self.assertRaisesRegex(ValueError, 'argument to fold must be a 1d vector'): dict_pattern.fold(np.atleast_2d(free_val), free=True) with self.assertRaisesRegex(ValueError, 'Wrong size for pattern dictionary'): dict_pattern.fold(free_val[-1], free=True)