def test_cosine_analytical(d, allclose): pytest.importorskip("scipy") # beta, betainc, betaincinv dt = 0.0001 x = np.arange(-1 + dt, 1, dt) def p(x, d): # unnormalized CosineSimilarity distribution, derived by Eric H. return (1 - x * x) ** ((d - 3) / 2.0) dist = CosineSimilarity(d) pdf_exp = dist.pdf(x) pdf_act = p(x, d) cdf_exp = dist.cdf(x) cdf_act = np.cumsum(pdf_act) / np.sum(pdf_act) # Check that we get the expected pdf after normalization assert allclose(pdf_exp / np.sum(pdf_exp), pdf_act / np.sum(pdf_act), atol=0.01) # Check that this accumulates to the expected cdf assert allclose(cdf_exp, cdf_act, atol=0.01) # Check that the inverse cdf gives back x assert allclose(dist.ppf(cdf_exp), x, atol=0.01)
def test_distributions(): check_init_args(PDF, ["x", "p"]) check_repr(PDF([1, 2, 3], [0.1, 0.8, 0.1])) assert (repr(PDF( [1, 2], [0.4, 0.6])) == "PDF(x=array([1., 2.]), p=array([0.4, 0.6]))") check_init_args(Uniform, ["low", "high", "integer"]) check_repr(Uniform(1, 3)) check_repr(Uniform(1, 4, integer=True)) assert repr(Uniform(0, 1)) == "Uniform(low=0, high=1)" assert repr(Uniform( 0, 5, integer=True)) == "Uniform(low=0, high=5, integer=True)" check_init_args(Gaussian, ["mean", "std"]) check_repr(Gaussian(0, 2)) assert repr(Gaussian(1, 0.1)) == "Gaussian(mean=1, std=0.1)" check_init_args(Exponential, ["scale", "shift", "high"]) check_repr(Exponential(2.0)) check_repr(Exponential(2.0, shift=0.1)) check_repr(Exponential(2.0, shift=0.1, high=10.0)) assert repr(Exponential(2.0)) == "Exponential(scale=2.0)" check_init_args(UniformHypersphere, ["surface", "min_magnitude"]) check_repr(UniformHypersphere()) check_repr(UniformHypersphere(surface=True)) check_repr(UniformHypersphere(min_magnitude=0.3)) assert repr(UniformHypersphere()) == "UniformHypersphere()" assert repr( UniformHypersphere(surface=True)) == "UniformHypersphere(surface=True)" check_init_args(Choice, ["options", "weights"]) check_repr(Choice([3, 2, 1])) check_repr(Choice([3, 2, 1], weights=[0.1, 0.2, 0.7])) assert repr(Choice([1, 2, 3])) == "Choice(options=array([1., 2., 3.]))" assert (repr( Choice([1, 2, 3], weights=[0.1, 0.5, 0.4]) ) == "Choice(options=array([1., 2., 3.]), weights=array([0.1, 0.5, 0.4]))") check_init_args(Samples, ["samples"]) check_repr(Samples([3, 2, 1])) assert repr(Samples([3, 2, 1])) == "Samples(samples=array([3., 2., 1.]))" check_init_args(SqrtBeta, ["n", "m"]) check_repr(SqrtBeta(3)) check_repr(SqrtBeta(3, m=2)) assert repr(SqrtBeta(3)) == "SqrtBeta(n=3)" assert repr(SqrtBeta(3, 2)) == "SqrtBeta(n=3, m=2)" check_init_args(SubvectorLength, ["dimensions", "subdimensions"]) check_repr(SubvectorLength(6)) check_repr(SubvectorLength(6, 2)) assert repr(SubvectorLength(3)) == "SubvectorLength(dimensions=3)" check_init_args(CosineSimilarity, ["dimensions"]) check_repr(CosineSimilarity(6)) assert repr(CosineSimilarity(6)) == "CosineSimilarity(dimensions=6)"
def test_cosine_sample_shape(seed, allclose): """"Tests that CosineSimilarity sample has correct shape.""" # sampling (n, d) should be the exact same as sampling (n*d,) n = 3 d = 4 dist = CosineSimilarity(2) a = dist.sample(n, d, rng=np.random.RandomState(seed)) b = dist.sample(n * d, rng=np.random.RandomState(seed)) assert allclose(a.flatten(), b)
def test_cosine_intercept(d, p, rng, allclose): """Tests CosineSimilarity inverse cdf for finding intercepts.""" pytest.importorskip("scipy") # betaincinv num_samples = 500 exp_dist = UniformHypersphere(surface=True) act_dist = CosineSimilarity(d) dots = exp_dist.sample(num_samples, d, rng=rng)[:, 0] # Find the desired intercept so that dots >= c with probability p c = act_dist.ppf(1 - p) assert allclose(np.sum(dots >= c) / float(num_samples), p, atol=0.05)
def test_cosine_similarity(d, rng): """Tests CosineSimilarity sampling.""" num_samples = 2500 num_bins = 8 # Check that it gives a single dimension from UniformHypersphere exp_dist = UniformHypersphere(surface=True) act_dist = CosineSimilarity(d) exp = exp_dist.sample(num_samples, d, rng=rng)[:, 0] act = act_dist.sample(num_samples, rng=rng) exp_hist, _ = np.histogram(exp, bins=num_bins) act_hist, _ = np.histogram(act, bins=num_bins) assert np.all(np.abs(np.asfarray(exp_hist - act_hist) / num_samples) < 0.15)
def prob_cleanup(similarity, dimensions, vocab_size): """Estimate the chance of successful cleanup. This returns the chance that, out of *vocab_size* randomly chosen vectors, none of them will be closer to a particular vector than the value given by *similarity*. To use this, compare your noisy vector with the ideal vector, pass that value in as the similarity parameter, and set *vocab_size* to be the number of competing vectors. Requires SciPy. """ p = CosineSimilarity(dimensions).cdf(similarity) if similarity < 1. and p == 1.: raise ArithmeticError( "Insufficient floating point precision to compute value.") return p**vocab_size
def test_argreprs(): def check_init_args(cls, args): assert getfullargspec(cls.__init__).args[1:] == args def check_repr(obj): assert eval(repr(obj)) == obj check_init_args(PDF, ['x', 'p']) check_repr(PDF([1, 2, 3], [0.1, 0.8, 0.1])) check_init_args(Uniform, ['low', 'high', 'integer']) check_repr(Uniform(1, 3)) check_repr(Uniform(1, 4, integer=True)) check_init_args(Gaussian, ['mean', 'std']) check_repr(Gaussian(0, 2)) check_init_args(Exponential, ['scale', 'shift', 'high']) check_repr(Exponential(2.)) check_repr(Exponential(2., shift=0.1)) check_repr(Exponential(2., shift=0.1, high=10.)) check_init_args(UniformHypersphere, ['surface', 'min_magnitude']) check_repr(UniformHypersphere()) check_repr(UniformHypersphere(surface=True)) check_repr(UniformHypersphere(min_magnitude=0.3)) check_init_args(Choice, ['options', 'weights']) check_repr(Choice([3, 2, 1])) check_repr(Choice([3, 2, 1], weights=[0.1, 0.2, 0.7])) check_init_args(Samples, ['samples']) check_repr(Samples([3, 2, 1])) check_init_args(SqrtBeta, ['n', 'm']) check_repr(SqrtBeta(3)) check_repr(SqrtBeta(3, m=2)) check_init_args(SubvectorLength, ['dimensions', 'subdimensions']) check_repr(SubvectorLength(6)) check_repr(SubvectorLength(6, 2)) check_init_args(CosineSimilarity, ['dimensions']) check_repr(CosineSimilarity(6))
def test_argreprs(): def check_init_args(cls, args): assert getfullargspec(cls.__init__).args[1:] == args def check_repr(obj): assert eval(repr(obj)) == obj check_init_args(PDF, ["x", "p"]) check_repr(PDF([1, 2, 3], [0.1, 0.8, 0.1])) check_init_args(Uniform, ["low", "high", "integer"]) check_repr(Uniform(1, 3)) check_repr(Uniform(1, 4, integer=True)) check_init_args(Gaussian, ["mean", "std"]) check_repr(Gaussian(0, 2)) check_init_args(Exponential, ["scale", "shift", "high"]) check_repr(Exponential(2.0)) check_repr(Exponential(2.0, shift=0.1)) check_repr(Exponential(2.0, shift=0.1, high=10.0)) check_init_args(UniformHypersphere, ["surface", "min_magnitude"]) check_repr(UniformHypersphere()) check_repr(UniformHypersphere(surface=True)) check_repr(UniformHypersphere(min_magnitude=0.3)) check_init_args(Choice, ["options", "weights"]) check_repr(Choice([3, 2, 1])) check_repr(Choice([3, 2, 1], weights=[0.1, 0.2, 0.7])) check_init_args(Samples, ["samples"]) check_repr(Samples([3, 2, 1])) check_init_args(SqrtBeta, ["n", "m"]) check_repr(SqrtBeta(3)) check_repr(SqrtBeta(3, m=2)) check_init_args(SubvectorLength, ["dimensions", "subdimensions"]) check_repr(SubvectorLength(6)) check_repr(SubvectorLength(6, 2)) check_init_args(CosineSimilarity, ["dimensions"]) check_repr(CosineSimilarity(6))
def VTB(n_neurons, dimensions, unbind_left=False, unbind_right=False, **kwargs): r"""Compute vector-derived transformation binding (VTB). VTB uses elementwise addition for superposition. The binding operation :math:`\mathcal{B}(x, y)` is defined as .. math:: \mathcal{B}(x, y) := V_y x = \left[\begin{array}{ccc} V_y' & 0 & 0 \\ 0 & V_y' & 0 \\ 0 & 0 & V_y' \end{array}\right] x with .. math:: V_y' = d^{\frac{1}{4}} \left[\begin{array}{cccc} y_1 & y_2 & \dots & y_{d'} \\ y_{d' + 1} & y_{d' + 2} & \dots & y_{2d'} \\ \vdots & \vdots & \ddots & \vdots \\ y_{d - d' + 1} & y_{d - d' + 2} & \dots & y_d \end{array}\right] and .. math:: d'^2 = d. The approximate inverse :math:`y^+` for :math:`y` is permuting the elements such that :math:`V_{y^+} = V_y`. Note that VTB requires the vector dimensionality to be square. The VTB binding operation is neither associative nor commutative. Publications with further information are forthcoming. Parameters ---------- n_neurons : int Number of neurons to use in each product computation. dimensions : int The number of dimensions of the input and output vectors. Needs to be a square number. unbind_left : bool Whether to unbind the left input vector from the right input vector. unbind_right : bool Whether to unbind the right input vector from the left input vector. kwargs : dict Arguments to pass through to the `nengo.Network` constructor. Returns ------- nengo.Network The newly built product network with attributes: * **input_left** (`nengo.Node`): The left operand vector to be bound. * **input_right** (`nengo.Node`): The right operand vector to be bound. * **mat** (`nengo.Node`): Representation of the matrix :math:`V_y'`. * **vec** (`nengo.Node`): Representation of the vector :math:`y`. * **matmuls** (`list`): Matrix multiplication networks. * **output** (`nengo.Node`): The resulting bound vector. """ sub_d = calc_sub_d(dimensions) shape_left = (sub_d, sub_d) shape_right = (sub_d, 1) with nengo.Network(**kwargs) as net: net.input_left = nengo.Node(size_in=dimensions) net.input_right = nengo.Node(size_in=dimensions) net.output = nengo.Node(size_in=dimensions) net.mat = nengo.Node(size_in=dimensions) net.vec = nengo.Node(size_in=dimensions) if unbind_left and unbind_right: raise ValueError("Cannot unbind both sides at the same time.") elif unbind_left: nengo.Connection(net.input_left, net.mat, transform=inversion_matrix(dimensions), synapse=None) nengo.Connection(net.input_right, net.vec, transform=swapping_matrix(dimensions), synapse=None) else: nengo.Connection(net.input_left, net.vec, synapse=None) if unbind_right: tr = inversion_matrix(dimensions) else: tr = 1. nengo.Connection(net.input_right, net.mat, transform=tr, synapse=None) with nengo.Config(nengo.Ensemble) as cfg: cfg[nengo.Ensemble].intercepts = CosineSimilarity(dimensions + 2) cfg[nengo.Ensemble].eval_points = CosineSimilarity(dimensions + 2) net.matmuls = [ MatrixMult(n_neurons, shape_left, shape_right) for i in range(sub_d) ] for i in range(sub_d): mm = net.matmuls[i] sl = slice(i * sub_d, (i + 1) * sub_d) nengo.Connection(net.mat, mm.input_left, synapse=None) nengo.Connection(net.vec[sl], mm.input_right, synapse=None) nengo.Connection(mm.output, net.output[sl], transform=np.sqrt(sub_d), synapse=None) return net