def test_get_swapping_matrix(rng): gen = UnitLengthVectors(64, rng) a = SemanticPointer(next(gen), algebra=VtbAlgebra()).v b = SemanticPointer(next(gen), algebra=VtbAlgebra()).v m = VtbAlgebra().get_swapping_matrix(64) assert np.allclose(VtbAlgebra().bind(a, b), np.dot(m, VtbAlgebra().bind(b, a)))
def test_unitary_pointers(rng): algebra = HrrAlgebra() g = UnitaryVectors(64, algebra, rng) a = SemanticPointer(next(g), algebra=algebra) b = SemanticPointer(next(g), algebra=algebra) c = SemanticPointer(next(g), algebra=algebra) assert np.allclose(a.compare(c), (a * b).compare(c * b))
def ssp(X, Y, x, y, alg=HrrAlgebra()): # Return a ssp if ((type(X) == SemanticPointer) & (type(Y) == SemanticPointer)): return (X**x) * (Y**y) else: return (SemanticPointer(data=X, algebra=alg)**x) * (SemanticPointer( data=Y, algebra=alg)**y)
def test_copy(): a = SemanticPointer(next(UnitLengthVectors(5))) b = a.copy() assert a is not b assert a.v is not b.v assert np.allclose(a.v, b.v) assert a.algebra is b.algebra assert a.vocab is b.vocab assert a.name is b.name
def test_make_unitary(algebra, d, rng): if not algebra.is_valid_dimensionality(d): return a = SemanticPointer(next(UnitLengthVectors(d, rng)), algebra=algebra) b = a.unitary() assert a is not b assert np.allclose(1, b.length()) assert np.allclose(1, (b * b).length()) assert np.allclose(1, (b * b * b).length())
def test_compare(rng): gen = UnitLengthVectors(50, rng) a = SemanticPointer(next(gen)) * 10 b = SemanticPointer(next(gen)) * 0.1 assert a.compare(a) > 0.99 assert a.compare(b) < 0.2 assert np.allclose(a.compare(b), a.dot(b) / (a.length() * b.length()))
def translate(self, vocab, populate=None, keys=None, solver=None): """Translate the Semantic Pointer to vocabulary *vocab*. The translation of a Semantic Pointer uses some form of projection to convert the Semantic Pointer to a Semantic Pointer of another vocabulary. By default the outer products of terms in the source and target vocabulary are used, but if *solver* is given, it is used to find a least squares solution for this projection. Parameters ---------- vocab : Vocabulary Target vocabulary. populate : bool, optional Whether the target vocabulary should be populated with missing keys. This is done by default, but with a warning. Set this explicitly to *True* or *False* to silence the warning or raise an error. keys : list, optional All keys to translate. If *None*, all keys in the source vocabulary will be translated. solver : nengo.Solver, optional If given, the solver will be used to solve the least squares problem to provide a better projection for the translation. """ tr = self.vocab.transform_to(vocab, populate, solver) return SemanticPointer(np.dot(tr, self.evaluate().v), vocab=vocab, name=self.name)
def reinterpret(self, vocab): """Reinterpret the Semantic Pointer as part of vocabulary *vocab*. The *vocab* parameter can be set to *None* to clear the associated vocabulary and allow the *source* to be interpreted as part of the vocabulary of any Semantic Pointer it is combined with. """ return SemanticPointer(self.v, vocab=vocab, name=self.name)
def ssp_weighted_plane_basis(K, W): # The above but plane waves aren't just all summed. Instead there's a weighted sum - can get distortions in patterns # or make place cells more refined this way d = K.shape[0] FX = np.ones((d * 2 + 1, ), dtype="complex") FX[0:d] = W * np.exp(1.j * K[:, 0]) FX[-d:] = np.flip(np.conj(FX[0:d])) FX = np.fft.ifftshift(FX) FY = np.ones((d * 2 + 1, ), dtype="complex") FY[0:d] = W * np.exp(1.j * K[:, 1]) FY[-d:] = np.flip(np.conj(FY[0:d])) FY = np.fft.ifftshift(FY) X = SemanticPointer(data=np.fft.ifft(FX), algebra=HrrAlgebra()) Y = SemanticPointer(data=np.fft.ifft(FY), algebra=HrrAlgebra()) return X, Y
def test_binary_operation_on_modules_with_fixed_pointer( Simulator, algebra, op, order, rng): vocab = spa.Vocabulary(16, pointer_gen=rng, algebra=algebra) vocab.populate("A; B") b = SemanticPointer(vocab["B"].v) # noqa: F841 with spa.Network() as model: a = spa.Transcode("A", output_vocab=vocab) # noqa: F841 if order == "AB": x = eval("a" + op + "b") elif order == "BA": x = eval("b" + op + "a") else: raise ValueError("Invalid order argument.") p = nengo.Probe(x.construct(), synapse=0.03) with Simulator(model) as sim: sim.run(0.3) assert_sp_close( sim.trange(), sim.data[p], vocab.parse(order[0] + op + order[1]), skip=0.2, atol=0.3, )
def coerce_callable(self, obj, fn): t = 0.0 if obj.input_vocab is not None: args = ( t, SemanticPointer( np.zeros(obj.input_vocab.dimensions), vocab=obj.input_vocab ), ) elif obj.size_in is not None: args = (t, np.zeros(obj.size_in)) else: args = (t,) _, invoked = checked_call(fn, *args) fn(*args) if not invoked: if obj.input_vocab is not None: raise ValidationError( "Transcode function %r is expected to accept exactly 2 " "arguments: time as a float, and a SemanticPointer", attr=self.name, obj=obj, ) else: raise ValidationError( "Transcode function %r is expected to accept exactly 1 or " "2 arguments: time as a float, and optionally the input " "data as NumPy array.", attr=self.name, obj=obj, ) return fn
def ssp_plane_basis(K): # Create the bases vectors X,Y as described in the paper with the wavevectors # (k_i = (u_i,v_i)) given in a matrix K. To get hexganal patterns use 3 K vectors 120 degs apart # To get mulit-scales/orientation, give many such sets of 3 K vectors # K is _ by 2 d = K.shape[0] FX = np.ones((d * 2 + 1, ), dtype="complex") FX[0:d] = np.exp(1.j * K[:, 0]) FX[-d:] = np.flip(np.conj(FX[0:d])) FX = np.fft.ifftshift(FX) FY = np.ones((d * 2 + 1, ), dtype="complex") FY[0:d] = np.exp(1.j * K[:, 1]) FY[-d:] = np.flip(np.conj(FY[0:d])) FY = np.fft.ifftshift(FY) X = SemanticPointer(data=np.fft.ifft(FX), algebra=HrrAlgebra()) Y = SemanticPointer(data=np.fft.ifft(FY), algebra=HrrAlgebra()) return X, Y
def fractional_bind(self, other): """Return the fractional binding of a SemanticPointer.""" type_ = infer_types(self) vocab = None if type_ == TAnyVocab else type_.vocab a, b = self.v, other return SemanticPointer(data=self.algebra.fractional_bind(a, b), vocab=vocab, algebra=self.algebra, name=self._get_binary_name(other, "**", False))
def test_dot(rng): gen = UnitLengthVectors(50, rng) a = SemanticPointer(next(gen)) * 1.1 b = SemanticPointer(next(gen)) * (-1.5) assert np.allclose(a.dot(b), np.dot(a.v, b.v)) assert np.allclose(a.dot(b.v), np.dot(a.v, b.v)) assert np.allclose(a.dot(list(b.v)), np.dot(a.v, b.v)) assert np.allclose(a.dot(tuple(b.v)), np.dot(a.v, b.v))
def __invert__(self): """Return a reorganized vector that acts as an inverse for convolution. This reorganization turns circular convolution into circular correlation, meaning that ``A*B*~B`` is approximately ``A``. For the vector ``[1, 2, 3, 4, 5]``, the inverse is ``[1, 5, 4, 3, 2]``. """ return SemanticPointer(data=self.algebra.invert(self.v), vocab=self.vocab, algebra=self.algebra, name=self._get_unary_name("~"))
def test_binding_and_inversion(algebra, d, rng): if not algebra.is_valid_dimensionality(d): return gen = UnitLengthVectors(d, rng) a = SemanticPointer(next(gen), algebra=algebra) b = SemanticPointer(next(gen), algebra=algebra) identity = Identity(d, algebra=algebra) c = a.copy() c *= b conv_ans = algebra.bind(a.v, b.v) assert np.allclose((a * b).v, conv_ans) assert np.allclose(a.bind(b).v, conv_ans) assert np.allclose(c.v, conv_ans) assert np.allclose((a * identity).v, a.v) assert (a * b * ~b).compare(a) > 0.6
def unitary(self): """Make the Semantic Pointer unitary and return it as a new object. The original object is not modified. A unitary Semantic Pointer has the property that it does not change the length of Semantic Pointers it is bound with using circular convolution. """ return SemanticPointer(self.algebra.make_unitary(self.v), vocab=self.vocab, algebra=self.algebra, name=self._get_method_name("unitary"))
def _mul(self, other, swap=False): if is_array(other): raise TypeError( "Multiplication of Semantic Pointers with arrays in not " "allowed.") elif is_number(other): return SemanticPointer(data=self.v * other, vocab=self.vocab, algebra=self.algebra, name=self._get_binary_name( other, "*", swap)) elif isinstance(other, Fixed): if other.type == TScalar: return SemanticPointer(data=self.v * other.evaluate(), vocab=self.vocab, algebra=self.algebra, name=self._get_binary_name( other, "*", swap)) else: return self._bind(other, swap=swap) else: return NotImplemented
def normalized(self): """Normalize the Semantic Pointer and return it as a new object. If the vector length is zero, the Semantic Pointer will be returned unchanged. The original object is not modified. """ nrm = np.linalg.norm(self.v) if nrm <= 0.: nrm = 1. return SemanticPointer(self.v / nrm, vocab=self.vocab, algebra=self.algebra, name=self._get_method_name("normalized"))
def _bind(self, other, swap=False): type_ = infer_types(self, other) vocab = None if type_ == TAnyVocab else type_.vocab if vocab is None: self._ensure_algebra_match(other) other_pointer = other.evaluate() a, b = self.v, other_pointer.v if swap: a, b = b, a return SemanticPointer(data=self.algebra.bind(a, b), vocab=vocab, algebra=self.algebra, name=self._get_binary_name( other_pointer, "*", swap))
def test_binding_matrix(algebra, rng): gen = UnitLengthVectors(64, rng) a = SemanticPointer(next(gen), algebra=algebra) b = SemanticPointer(next(gen), algebra=algebra) m = b.get_binding_matrix() m_swapped = a.get_binding_matrix(swap_inputs=True) assert np.allclose((a * b).v, np.dot(m, a.v)) assert np.allclose((a * b).v, np.dot(m_swapped, b.v))
def test_multiply(): a = SemanticPointer(next(UnitLengthVectors(50))) assert np.allclose((a * 5).v, a.v * 5) assert np.allclose((5 * a).v, a.v * 5) assert np.allclose((a * 5.7).v, a.v * 5.7) assert np.allclose((5.7 * a).v, a.v * 5.7) assert np.allclose((0 * a).v, np.zeros(50)) assert np.allclose((1 * a).v, a.v) with pytest.raises(Exception): a * None with pytest.raises(Exception): a * 'string' with pytest.raises(TypeError): a * np.array([1, 2])
def test_init(): a = SemanticPointer([1, 2, 3, 4]) assert len(a) == 4 a = SemanticPointer([1, 2, 3, 4, 5]) assert len(a) == 5 a = SemanticPointer(list(range(100))) assert len(a) == 100 with pytest.raises(ValidationError): a = SemanticPointer(np.zeros((2, 2))) with pytest.raises(ValidationError): a = SemanticPointer(-1) with pytest.raises(ValidationError): a = SemanticPointer(0) with pytest.raises(ValidationError): a = SemanticPointer(1.7) with pytest.raises(ValidationError): a = SemanticPointer(None) with pytest.raises(TypeError): a = SemanticPointer(int)
def test_add_output(Simulator, seed, rng, plt): d = 8 pointer = next(UnitLengthVectors(d, rng)) with nengo.Network(seed=seed) as model: ea = IdentityEnsembleArray(15, d, 4) input_node = nengo.Node(pointer) nengo.Connection(input_node, ea.input) out = ea.add_output('const', lambda x: -x) assert ea.const is out p = nengo.Probe(out, synapse=0.01) with Simulator(model) as sim: sim.run(0.3) plt.plot(sim.trange(), np.dot(sim.data[p], -pointer)) assert_sp_close(sim.trange(), sim.data[p], SemanticPointer(-pointer), skip=0.2, atol=0.3)
def test_add_sub(algebra, rng): gen = UnitLengthVectors(10, rng) a = SemanticPointer(next(gen), algebra=algebra) b = SemanticPointer(next(gen), algebra=algebra) c = a.copy() d = b.copy() c += b d -= -a assert np.allclose((a + b).v, algebra.superpose(a.v, b.v)) assert np.allclose((a + b).v, c.v) assert np.allclose((a + b).v, d.v) assert np.allclose((a + b).v, (a - (-b)).v)
def make_good_unitary(D, eps=1e-3, rng=np.random): a = rng.rand((D - 1) // 2) sign = rng.choice((-1, +1), len(a)) phi = sign * np.pi * (eps + a * (1 - 2 * eps)) assert np.all(np.abs(phi) >= np.pi * eps) assert np.all(np.abs(phi) <= np.pi * (1 - eps)) fv = np.zeros(D, dtype='complex64') fv[0] = 1 fv[1:(D + 1) // 2] = np.cos(phi) + 1j * np.sin(phi) fv[-1:D // 2:-1] = np.conj(fv[1:(D + 1) // 2]) if D % 2 == 0: fv[D // 2] = 1 assert np.allclose(np.abs(fv), 1) v = np.fft.ifft(fv) # assert np.allclose(v.imag, 0, atol=1e-5) v = v.real assert np.allclose(np.fft.fft(v), fv) assert np.allclose(np.linalg.norm(v), 1) return SemanticPointer(v)
def test_add_output_multiple_fn(Simulator, seed, rng, plt): d = 8 pointer = next(UnitLengthVectors(d, rng)) with nengo.Network(seed=seed) as model: ea = IdentityEnsembleArray(15, d, 4) input_node = nengo.Node(pointer) nengo.Connection(input_node, ea.input) out = ea.add_output("const", (lambda x: -x, lambda x: 0.5 * x, lambda x: x)) assert ea.const is out p = nengo.Probe(out, synapse=0.01) with Simulator(model) as sim: sim.run(0.3) expected = np.array(pointer) expected[0] *= -1.0 expected[1:4] *= 0.5 plt.plot(sim.trange(), np.dot(sim.data[p], expected)) assert_sp_close( sim.trange(), sim.data[p], SemanticPointer(expected), skip=0.2, atol=0.3 )
def test_binary_operation_on_fixed_pointer_with_pointer_symbol( Simulator, op, order, rng): vocab = spa.Vocabulary(64, pointer_gen=rng) vocab.populate('A; B') a = PointerSymbol('A', TVocabulary(vocab)) # noqa: F841 b = SemanticPointer(vocab['B'].v) # noqa: F841 with spa.Network() as model: if order == 'AB': x = eval('a' + op + 'b') elif order == 'BA': x = eval('b' + op + 'a') else: raise ValueError('Invalid order argument.') p = nengo.Probe(x.construct(), synapse=0.03) with Simulator(model) as sim: sim.run(0.5) assert_sp_close(sim.trange(), sim.data[p], vocab.parse(order[0] + op + order[1]), skip=0.3)
def test_binary_operation_on_fixed_pointer_with_pointer_symbol( Simulator, op, order, rng ): vocab = spa.Vocabulary(64, pointer_gen=rng) vocab.populate("A; B") a = PointerSymbol("A", TVocabulary(vocab)) # noqa: F841 b = SemanticPointer(vocab["B"].v) # noqa: F841 with spa.Network() as model: if order == "AB": x = eval("a" + op + "b") elif order == "BA": x = eval("b" + op + "a") else: raise ValueError("Invalid order argument.") p = nengo.Probe(x.construct(), synapse=0.03) with Simulator(model) as sim: sim.run(0.5) assert_sp_close( sim.trange(), sim.data[p], vocab.parse(order[0] + op + order[1]), skip=0.3 )
def test_name(): a = SemanticPointer(np.ones(4), name='a') b = SemanticPointer(np.ones(4), name='b') unnamed = SemanticPointer(np.ones(4), name=None) assert str(a) == "SemanticPointer<a>" assert repr(a) == ( "SemanticPointer({!r}, vocab={!r}, algebra={!r}, name={!r}".format( a.v, a.vocab, a.algebra, a.name)) assert (-a).name == "-(a)" assert (~a).name == "~(a)" assert a.normalized().name == "(a).normalized()" assert a.unitary().name == "(a).unitary()" assert (a + b).name == "(a)+(b)" assert (a * b).name == "(a)*(b)" assert (2. * a).name == "(2.0)*(a)" assert (a + unnamed).name is None assert (a * unnamed).name is None