Skip to content

Commit

Permalink
Add parsing for special Semantic Pointers.
Browse files Browse the repository at this point in the history
Addresses #176.
  • Loading branch information
jgosmann committed Jul 6, 2018
1 parent a2ecf3a commit e22af43
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 6 deletions.
6 changes: 6 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@ Release History
0.6.0 (unreleased)
==================

**Added**

- The Semantic Pointer names *AbsorbingElement*, *Identity*, and *Zero* now
have a special meaning in *Vocabulary* and *nengo_spa.sym* and will return
the respective special Semantic Pointers.
(`#195 <https://github.com/nengo/nengo_spa/pull/195>`_,
`#176 <https://github.com/nengo/nengo_spa/issues/176>`_)


0.5.2 (July 6, 2018)
Expand Down
13 changes: 11 additions & 2 deletions nengo_spa/tests/test_vocabulary.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from nengo_spa.exceptions import SpaParseError
from nengo_spa.pointer import Identity, SemanticPointer
from nengo_spa.vocab import (
VocabularyMap, VocabularyMapParam, VocabularyOrDimParam)
special_sps, VocabularyMap, VocabularyMapParam, VocabularyOrDimParam)


def test_add(rng):
Expand Down Expand Up @@ -71,13 +71,22 @@ def test_populate(rng):
v.populate(u'Aα = A')


@pytest.mark.parametrize('name', ('None', 'True', 'False'))
@pytest.mark.parametrize('name', (
'None', 'True', 'False', 'Zero', 'AbsorbingElement', 'Identity'))
def test_reserved_names(name):
v = Vocabulary(16)
with pytest.raises(SpaParseError):
v.populate(name)


@pytest.mark.parametrize('name,sp', special_sps.items())
def test_special_sps(name, sp):
v = Vocabulary(16)
assert name in v
assert np.allclose(v[name].v, sp(16).v)
assert np.allclose(v.parse(name).v, sp(16).v)


def test_populate_with_transform_on_first_vector(rng):
v = Vocabulary(64, rng=rng)

Expand Down
20 changes: 16 additions & 4 deletions nengo_spa/vocab.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@

from nengo_spa import pointer
from nengo_spa.exceptions import SpaParseError
from nengo_spa.pointer import Identity
from nengo_spa.pointer import AbsorbingElement, Identity, Zero


valid_sp_regex = re.compile('^[A-Z][_a-zA-Z0-9]*$')
reserved_sp_names = {'None', 'True', 'False'}
special_sps = {
'AbsorbingElement': AbsorbingElement,
'Identity': Identity,
'Zero': Zero,
}
reserved_sp_names = {'None', 'True', 'False'} | special_sps.keys()


class Vocabulary(Mapping):
Expand All @@ -25,6 +30,10 @@ class Vocabulary(Mapping):
themselves. The names of Semantic Pointers must be valid Python 2
identifiers starting with a capital letter.
Every vocabulary knows the special elements *AbsorbingElement*, *Identity*,
and *Zero*. However, these are not included in the keys returned by `.keys`
or the vectors returned by `.vectors`.
Parameters
-----------
dimensions : int
Expand Down Expand Up @@ -141,7 +150,7 @@ def create_pointer(self, attempts=100, transform=None):
return best_p

def __contains__(self, key):
return key in self._key2idx
return key in special_sps or key in self._key2idx

def __len__(self):
return len(self._vectors)
Expand All @@ -159,6 +168,8 @@ def __getitem__(self, key):
# exception.
if key == '__tracebackhide__':
raise KeyError()
if key in special_sps:
return special_sps[key](self.dimensions, self)
if not self.strict and key not in self:
self.add(key, self.create_pointer())
return pointer.SemanticPointer(
Expand All @@ -174,7 +185,8 @@ def add(self, key, p):
----------
key : str
Name of the Semantic Pointer. Must be a valid Python 2 identifier
starting with a capital letter.
starting with a capital letter. Must not be *AbsorbingElement*,
*Identity*, or *Zero*.
p : SemanticPointer or array_like
Semantic Pointer to add.
"""
Expand Down

0 comments on commit e22af43

Please sign in to comment.