Skip to content

Commit

Permalink
Convert networks to classes and remove labels
Browse files Browse the repository at this point in the history
Addresses #234.
  • Loading branch information
jgosmann committed Oct 19, 2019
1 parent 4255e0f commit c04c04c
Show file tree
Hide file tree
Showing 5 changed files with 292 additions and 282 deletions.
72 changes: 38 additions & 34 deletions nengo_spa/networks/circularconvolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ def dft_half(n):
return np.exp((-2.j * np.pi / n) * (w[:, None] * x[None, :]))


def CircularConvolution(n_neurons, dimensions, invert_a=False, invert_b=False,
input_magnitude=1.0, **kwargs):
class CircularConvolution(nengo.Network):
r"""Compute the circular convolution of two vectors.
The circular convolution :math:`c` of vectors :math:`a` and :math:`b`
Expand Down Expand Up @@ -112,16 +111,17 @@ def CircularConvolution(n_neurons, dimensions, invert_a=False, invert_b=False,
**kwargs : dict
Keyword arguments to pass through to the `nengo.Network` constructor.
Returns
-------
nengo.Network
The newly built product network with attributes:
* **input_a** (`nengo.Node`): The first vector to be convolved.
* **input_b** (`nengo.Node`): The second vector to be convolved.
* **product** (`nengo.networks.Product`): Network created to do the
element-wise product of the :math:`DFT` components.
* **output** (`nengo.Node`): The resulting convolved vector.
Attributes
----------
input_a : nengo.Node
The first vector to be convolved.
input_b : nengo.Node
The second vector to be convolved.
product : nengo.networks.Product
Network created to do the element-wise product of the :math:`DFT`
components.
output : nengo.Node
The resulting convolved vector.
Examples
--------
Expand Down Expand Up @@ -165,25 +165,29 @@ def CircularConvolution(n_neurons, dimensions, invert_a=False, invert_b=False,
only the real part of :math:`c` since the imaginary part
is analytically zero.
"""
kwargs.setdefault('label', "CircularConvolution")

tr_a = transform_in(dimensions, 'A', invert_a)
tr_b = transform_in(dimensions, 'B', invert_b)
tr_out = transform_out(dimensions)

with nengo.Network(**kwargs) as net:
net.input_a = nengo.Node(size_in=dimensions, label="input_a")
net.input_b = nengo.Node(size_in=dimensions, label="input_b")
net.product = Product(
n_neurons, tr_out.shape[1],
input_magnitude=2 * input_magnitude / np.sqrt(2.))
net.output = nengo.Node(size_in=dimensions, label="output")

nengo.Connection(
net.input_a, net.product.input_a, transform=tr_a, synapse=None)
nengo.Connection(
net.input_b, net.product.input_b, transform=tr_b, synapse=None)
nengo.Connection(
net.product.output, net.output, transform=tr_out, synapse=None)

return net

def __init__(self, n_neurons, dimensions, invert_a=False, invert_b=False,
input_magnitude=1.0, **kwargs):
super().__init__(**kwargs)

tr_a = transform_in(dimensions, 'A', invert_a)
tr_b = transform_in(dimensions, 'B', invert_b)
tr_out = transform_out(dimensions)

with self:
self.input_a = nengo.Node(size_in=dimensions, label="input_a")
self.input_b = nengo.Node(size_in=dimensions, label="input_b")
self.product = Product(
n_neurons, tr_out.shape[1],
input_magnitude=2 * input_magnitude / np.sqrt(2.))
self.output = nengo.Node(size_in=dimensions, label="output")

nengo.Connection(
self.input_a, self.product.input_a, transform=tr_a,
synapse=None)
nengo.Connection(
self.input_b, self.product.input_b, transform=tr_b,
synapse=None)
nengo.Connection(
self.product.output, self.output, transform=tr_out,
synapse=None)
13 changes: 6 additions & 7 deletions nengo_spa/networks/identity_ensemble_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,12 @@ class IdentityEnsembleArray(nengo.Network):
**kwargs : dict
Keyword arguments to pass through to the `nengo.Network` constructor.
Returns
-------
nengo.Network
Network with attributes:
* **input** (`nengo.Node`): Input node.
* **output** (`nengo.Node`): Output node.
Attributes
----------
input : nengo.Node
Input node.
output : nengo.Node
Output node.
"""
def __init__(
self, neurons_per_dimension, dimensions, subdimensions, **kwargs):
Expand Down
152 changes: 77 additions & 75 deletions nengo_spa/networks/matrix_multiplication.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import numpy as np


def MatrixMult(n_neurons, shape_left, shape_right, **kwargs):
class MatrixMult(nengo.Network):
"""Computes the matrix product A*B.
Both matrices need to be two dimensional.
Expand All @@ -25,78 +25,80 @@ def MatrixMult(n_neurons, shape_left, shape_right, **kwargs):
**kwargs : dict
Keyword arguments to pass through to the `nengo.Network` constructor.
Returns
-------
net : Network
The newly built matrix multiplication network with attributes:
* **input_left** (`nengo.Node`): The left matrix (A) to multiply.
* **input_right** (`nengo.Node`): The left matrix (A) to multiply.
* **C** (`nengo.networks.Product`): The product network doing the
matrix multiplication.
* **output** (`nengo.node`): The resulting matrix result.
Attributes
----------
input_left : nengo.Node
The left matrix (A) to multiply.
input_right : nengo.Node
The left matrix (A) to multiply.
C : nengo.networks.Product
The product network doing the matrix multiplication.
output : nengo.node
The resulting matrix result.
"""

if len(shape_left) != 2:
raise ValueError("Shape {} is not two dimensional.".format(shape_left))
if len(shape_right) != 2:
raise ValueError(
"Shape {} is not two dimensional.".format(shape_right))
if shape_left[1] != shape_right[0]:
raise ValueError(
"Matrix dimensions {} and {} are incompatible".format(
shape_left, shape_right))

size_left = np.prod(shape_left)
size_right = np.prod(shape_right)

with nengo.Network(**kwargs) as net:
net.input_left = nengo.Node(size_in=size_left)
net.input_right = nengo.Node(size_in=size_right)

# The C matrix is composed of populations that each contain
# one element of A (left) and one element of B (right).
# These elements will be multiplied together in the next step.
size_c = size_left * shape_right[1]
net.C = nengo.networks.Product(n_neurons, size_c)

# Determine the transformation matrices to get the correct pairwise
# products computed. This looks a bit like black magic but if
# you manually try multiplying two matrices together, you can see
# the underlying pattern. Basically, we need to build up D1*D2*D3
# pairs of numbers in C to compute the product of. If i,j,k are the
# indexes into the D1*D2*D3 products, we want to compute the product
# of element (i,j) in A with the element (j,k) in B. The index in
# A of (i,j) is j+i*D2 and the index in B of (j,k) is k+j*D3.
# The index in C is j+k*D2+i*D2*D3, multiplied by 2 since there are
# two values per ensemble. We add 1 to the B index so it goes into
# the second value in the ensemble.
transform_left = np.zeros((size_c, size_left))
transform_right = np.zeros((size_c, size_right))

for i, j, k in np.ndindex(shape_left[0], *shape_right):
c_index = (j + k * shape_right[0] + i * size_right)
transform_left[c_index][j + i * shape_right[0]] = 1
transform_right[c_index][k + j * shape_right[1]] = 1

nengo.Connection(
net.input_left, net.C.input_a, transform=transform_left,
synapse=None)
nengo.Connection(
net.input_right, net.C.input_b, transform=transform_right,
synapse=None)

# Now do the appropriate summing
size_output = shape_left[0] * shape_right[1]
net.output = nengo.Node(size_in=size_output)

# The mapping for this transformation is much easier, since we want to
# combine D2 pairs of elements (we sum D2 products together)
transform_c = np.zeros((size_output, size_c))
for i in range(size_c):
transform_c[i // shape_right[0]][i] = 1

nengo.Connection(
net.C.output, net.output, transform=transform_c, synapse=None)

return net
def __init__(self, n_neurons, shape_left, shape_right, **kwargs):
if len(shape_left) != 2:
raise ValueError(
"Shape {} is not two dimensional.".format(shape_left))
if len(shape_right) != 2:
raise ValueError(
"Shape {} is not two dimensional.".format(shape_right))
if shape_left[1] != shape_right[0]:
raise ValueError(
"Matrix dimensions {} and {} are incompatible".format(
shape_left, shape_right))

super().__init__(**kwargs)

size_left = np.prod(shape_left)
size_right = np.prod(shape_right)

with self:
self.input_left = nengo.Node(size_in=size_left)
self.input_right = nengo.Node(size_in=size_right)

# The C matrix is composed of populations that each contain
# one element of A (left) and one element of B (right).
# These elements will be multiplied together in the next step.
size_c = size_left * shape_right[1]
self.C = nengo.networks.Product(n_neurons, size_c)

# Determine the transformation matrices to get the correct pairwise
# products computed. This looks a bit like black magic but if
# you manually try multiplying two matrices together, you can see
# the underlying pattern. Basically, we need to build up D1*D2*D3
# pairs of numbers in C to compute the product of. If i,j,k are
# the indexes into the D1*D2*D3 products, we want to compute the
# product # of element (i,j) in A with the element (j,k) in B. The
# index in # A of (i,j) is j+i*D2 and the index in B of (j,k) is
# k+j*D3. The index in C is j+k*D2+i*D2*D3, multiplied by 2 since
# there are # two values per ensemble. We add 1 to the B index so
# it goes into # the second value in the ensemble.
transform_left = np.zeros((size_c, size_left))
transform_right = np.zeros((size_c, size_right))

for i, j, k in np.ndindex(shape_left[0], *shape_right):
c_index = (j + k * shape_right[0] + i * size_right)
transform_left[c_index][j + i * shape_right[0]] = 1
transform_right[c_index][k + j * shape_right[1]] = 1

nengo.Connection(
self.input_left, self.C.input_a, transform=transform_left,
synapse=None)
nengo.Connection(
self.input_right, self.C.input_b, transform=transform_right,
synapse=None)

# Now do the appropriate summing
size_output = shape_left[0] * shape_right[1]
self.output = nengo.Node(size_in=size_output)

# The mapping for this transformation is much easier, since we want
# to combine D2 pairs of elements (we sum D2 products together)
transform_c = np.zeros((size_output, size_c))
for i in range(size_c):
transform_c[i // shape_right[0]][i] = 1

nengo.Connection(
self.C.output, self.output, transform=transform_c,
synapse=None)

0 comments on commit c04c04c

Please sign in to comment.