Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for different binding operations #198

Merged
merged 29 commits into from
Aug 21, 2018
Merged

Add support for different binding operations #198

merged 29 commits into from
Aug 21, 2018

Conversation

jgosmann
Copy link
Collaborator

@jgosmann jgosmann commented Jul 13, 2018

Motivation and context:
This adds the possibility to change the binding (and superposition) operation used by Nengo SPA. It also implements vector-derived transformation binding (VTB) as one alternate binding method.

The specific choice of a superpositiion operation and a binding operation is called an algebra in this PR (as it roughly fits the mathematical definition of an algebra or algebraic structure). Such in algebra is implemented by a class providing pure math implementations of the operations, methods to obtain special elements like the identity, and two methods to provide neural implementations of the two operators.

Each vocabulary (and SemanticPointer which might not have a vocabulary) is assigned such an algbra determining the operations used when operands get combined in the SPA syntax (it defaults to CircularConvolutionAlgebra). Because operands are required to have the same vocabulary, it is always clear what algebra to use, i.e., there is no situation in which the operands might have different algebras (except for SemanticPointer which raises an exception in this case).

Currently there is not way to change the default algebra, but one has to explicitely create a vocabulary with the desired algbra. Not sure whether there should be a way to set this default ...

Closes #69.

Interactions with other PRs:
none

How has this been tested?

Tests have been added, updated, etc.
An algebra fixture has been added that will parametrize a test to run with both implemented algebras.

How long should this take to review?

  • Lengthy (more than 150 lines changed or changes are complicated)

Where should a reviewer start?

The commits should be self-contained, so that one could go commit by commit. But I revised some things multiple times and the back and forth might not be that helpful. Such it might be better to look at the final diff. There are multiple parts that stand mostly on its own:

  • Added matrix multiplication network nengo_spa/networks/matrix_multiplication.py.
  • Added module nengo_spa/modules/superposition.py.
  • The interface for algebras nengo_spa/algebras/base.py.
  • The circular convolution algebra nengo_spa/algebras/cconv.py. (Probably best to look at this one first as it uses familiar operations.)
  • The VTB algebra nengo_spa/algebras/vtb.py with the binding network nengo_spa/networks/vtb.py.
  • Several smaller changes in nengo_spa/vocab.py and nengo_spa/pointer.py and some other files to enable the use of algebras.
  • All of this is accompanied with changes in the respective test files and documentation.

Types of changes:

  • Breaking change (fix or feature that causes existing functionality to change)

Checklist:

  • I have read the CONTRIBUTING.rst document.
  • I have updated the documentation accordingly.
  • I have included a changelog entry.
  • I have added tests to cover my changes.
  • I have run the test suite locally and all tests passed.

Still to do:

  • Extract the VTB network into its own class.
  • Try to cut down on the increased test duration.

@jgosmann jgosmann added this to the 0.6 milestone Jul 13, 2018
@jgosmann jgosmann self-assigned this Jul 13, 2018
@jgosmann jgosmann force-pushed the algebras branch 2 times, most recently from a82d6b0 to 1756bb1 Compare July 17, 2018 19:02
@jgosmann jgosmann removed their assignment Jul 17, 2018
@jgosmann jgosmann requested review from Seanny123 and tcstewar July 17, 2018 19:03
@jgosmann jgosmann mentioned this pull request Jul 17, 2018
Vocabulary that the Semantic Pointer is considered to be part of.
Mutually exclusive with the *algebra* argument.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why different formatting for algebra and vocab?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

type_ = infer_types(self, other)
vocab = None if type_ == TAnyVocab else type_.vocab
return SemanticPointer(data=self.v - other.evaluate().v, vocab=vocab)
return self + (-other)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does __add__ need type checking, while __sub__ doesn't?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because sub re-expresses a - b as a + (-b) thus using the implementation of __add__ and __neg__ which already do type checking.

@@ -180,4 +180,4 @@ All of the control-like steps (e.g. “compared with”, “inferred”, and rou
information through the system), are implemented by a biologically plausible
basal ganglia model. This is one example of the 8 different tasks that Spaun is
able to perform. Videos for all tasks can be found `here
<http://nengo.ca/build-a-brain/spaunvideos/>`_.
<http://www.nengo.ca/build-a-brain/spaunvideos/>`_.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be changed to https://xchoo.github.io/spaun2.0/videos.html which it redirects to anyways. If I leave tiny nit-picks like this in my review, you can safely assume I'll change them myself once I've reviewed the other files.

@@ -58,10 +58,22 @@ def invert(cls, v):
return v.reshape((sub_d, sub_d)).T.flatten()

@classmethod
def get_binding_matrix(cls, v):
def get_binding_matrix(cls, v, swap_inputs=False):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand the point of swapping inputs as a function argument. Naively, it seems to me that the inputs should just be swapped in the connections and not as a parameter, if the user wants that. Would you mind explaining to me the intent of this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When using a binding matrix one vector is fixed (the one the matrix) is based on and one varies over time. Thus, there is no way to swap the inputs because there is only on time varying input.

@Seanny123
Copy link
Collaborator

I've read through the code once, but I'd like to read it again. It's pretty remarkable how you managed to abstract such a fundamental part of SPA.


Parameters
----------
v : n(d,) darray
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is n here?

@Seanny123
Copy link
Collaborator

Made some formatting fixes and added a test to make sure the unitary vector doesn't change the length of what it's binded with. This PR LGTM.

@jgosmann
Copy link
Collaborator Author

@Seanny123, can you “officially” approve this PR?

@jgosmann jgosmann merged commit caa714a into master Aug 21, 2018
@jgosmann jgosmann deleted the algebras branch August 21, 2018 01:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

Support for different binding methods
2 participants