예제 #1
0
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
예제 #2
0
    def __init__(self, dim):
        # Put lower bounds so we're testing the contraining functions
        # and so that derivatives of all orders are nonzero.
        self.dim = dim
        self.theta_pattern = \
            paragami.NumericArrayPattern(shape=(dim, ), lb=-10.)
        self.lambda_pattern = \
            paragami.NumericArrayPattern(shape=(dim, ), lb=-10.0)

        vec = np.linspace(0.1, 0.3, num=dim)
        self.matrix = np.outer(vec, vec) + np.eye(dim)

        self.lam = self.get_default_lambda()
예제 #3
0
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
예제 #4
0
    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)
예제 #5
0
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
예제 #6
0
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
예제 #7
0
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
예제 #8
0
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
예제 #9
0
def get_gmm_params_pattern(obs_dim, num_components):
    """A ``paragami`` pattern for a mixture model.

    ``centroids`` are the locations of the clusters.
    ``probs`` are the a priori probabilities of each cluster.
    """
    gmm_params_pattern = paragami.PatternDict()
    gmm_params_pattern['centroids'] = \
        paragami.NumericArrayPattern((num_components, obs_dim))
    gmm_params_pattern['probs'] = \
        paragami.SimplexArrayPattern(
            simplex_size=num_components, array_shape=(1,))
    return gmm_params_pattern
예제 #10
0
    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'])
예제 #11
0
def _get_data_pattern(x_shape, y_shape):
    data_pattern = paragami.PatternDict()
    data_pattern['y'] = paragami.NumericArrayPattern(y_shape)
    data_pattern['x'] = paragami.NumericArrayPattern(x_shape)
    return data_pattern
예제 #12
0
    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)
예제 #13
0
    def test_numeric_array_patterns(self):
        for test_shape in [(1, ), (2, ), (2, 3), (2, 3, 4)]:
            valid_value = np.random.random(test_shape)
            pattern = paragami.NumericArrayPattern(test_shape)
            _test_pattern(self, pattern, valid_value)

            pattern = paragami.NumericArrayPattern(test_shape, lb=-1)
            _test_pattern(self, pattern, valid_value)

            pattern = paragami.NumericArrayPattern(test_shape, ub=2)
            _test_pattern(self, pattern, valid_value)

            pattern = paragami.NumericArrayPattern(test_shape, lb=-1, ub=2)
            _test_pattern(self, pattern, valid_value)

        # Test scalar subclass.
        pattern = paragami.NumericScalarPattern()
        _test_pattern(self, pattern, 2)
        _test_pattern(self, pattern, [2])

        pattern = paragami.NumericScalarPattern(lb=-1)
        _test_pattern(self, pattern, 2)

        pattern = paragami.NumericScalarPattern(ub=3)
        _test_pattern(self, pattern, 2)

        pattern = paragami.NumericScalarPattern(lb=-1, ub=3)
        _test_pattern(self, pattern, 2)

        # Test vector subclass.
        valid_vec = np.random.random(3)
        pattern = paragami.NumericVectorPattern(length=3)
        _test_pattern(self, pattern, valid_vec)

        pattern = paragami.NumericVectorPattern(length=3, lb=-1)
        _test_pattern(self, pattern, valid_vec)

        pattern = paragami.NumericVectorPattern(length=3, ub=3)
        _test_pattern(self, pattern, valid_vec)

        pattern = paragami.NumericVectorPattern(length=3, lb=-1, ub=3)
        _test_pattern(self, pattern, valid_vec)

        # Test equality comparisons.
        self.assertTrue(
            paragami.NumericArrayPattern((1, 2)) !=
            paragami.NumericArrayPattern((1, )))

        self.assertTrue(
            paragami.NumericArrayPattern((1, 2)) !=
            paragami.NumericArrayPattern((1, 3)))

        self.assertTrue(
            paragami.NumericArrayPattern((1, 2), lb=2) !=
            paragami.NumericArrayPattern((1, 2)))

        self.assertTrue(
            paragami.NumericArrayPattern((1, 2), lb=2, ub=4) !=
            paragami.NumericArrayPattern((1, 2), lb=2))

        # Check that singletons work.
        pattern = paragami.NumericArrayPattern(shape=(1, ))
        _test_pattern(self, pattern, 1.0)

        # Test invalid values.
        with self.assertRaisesRegex(
            ValueError, 'ub must strictly exceed lower bound lb'):
            pattern = paragami.NumericArrayPattern((1, ), lb=1, ub=-1)

        pattern = paragami.NumericArrayPattern((1, ), lb=-1, ub=1)
        self.assertEqual((-1, 1), pattern.bounds())
        with self.assertRaisesRegex(ValueError, 'beneath lower bound'):
            pattern.flatten(-2, free=True)
        with self.assertRaisesRegex(ValueError, 'above upper bound'):
            pattern.flatten(2, free=True)
        with self.assertRaisesRegex(ValueError, 'Wrong size'):
            pattern.flatten([0, 0], free=True)
        with self.assertRaisesRegex(ValueError,
                                    'argument to fold must be a 1d vector'):
            pattern.fold([[0]], free=True)
        with self.assertRaisesRegex(ValueError, 'Wrong size for array'):
            pattern.fold([0, 0], free=True)
        with self.assertRaisesRegex(ValueError, 'beneath lower bound'):
            pattern.fold([-2], free=False)

        # Test flat indices.
        pattern = paragami.NumericArrayPattern((2, 3, 4), lb=-1, ub=1)
        _test_array_flat_indices(self, pattern)