Skip to content

Commit

Permalink
Minimise ensemble filter routing regions
Browse files Browse the repository at this point in the history
Extend the minimisation of filter routing tables to also work for
ensembles. Each filter routing region reports the set of keys and masks
it contains and these form the "off-set"s against which other regions
are minimised.
  • Loading branch information
mundya committed Oct 25, 2016
1 parent 392fa89 commit 293e8cc
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 5 deletions.
22 changes: 21 additions & 1 deletion nengo_spinnaker/operators/lif.py
Expand Up @@ -518,8 +518,28 @@ def get_signal_constraints(self):
def load_to_machine(self, netlist, controller):
"""Load the ensemble data into memory."""
# Prepare the routing regions
# Begin by building the set of keys and masks expected by each region
on_sets = {
region: self.regions[region].get_expected_keys_and_masks() for
region in RoutingRegions
}

# Hence build the set of keys and masks which should NOT match against
# each routing region.
off_sets = collections.defaultdict(set)
for a, on_set in iteritems(on_sets):
for b in RoutingRegions:
# Add the on-set for this region `b` to the off-set
off_sets[a].update(on_sets[b])

# Elements which are in the on-set for `a` cannot be in the off-set
off_sets[a].difference_update(on_sets[a])

# Build the filter routing region, minimising the entries subject to
# the off-sets which were just constructed.
for region in RoutingRegions:
self.regions[region].build_routes()
self.regions[region].build_routes(minimise=True,
off_set=off_sets[region])

# Delegate the task of loading to the machine
for cluster in self.clusters:
Expand Down
42 changes: 38 additions & 4 deletions nengo_spinnaker/regions/filters.py
Expand Up @@ -353,8 +353,40 @@ def get_signal_constraints(self):

return constraints

def build_routes(self, minimise=False):
"""Build the data structure to be written to memory."""
def get_expected_keys_and_masks(self):
"""Extract the set of keys and masks which are expected to match
against the filter routing region.
Returns
-------
{(key, mask), ...}
Set of keys and masks.
"""
keys_and_masks = set()

# Loop of the list of signals matched by this region and extract their
# keys and masks.
for signal, _ in self.signal_routes:
ks = signal.keyspace
keys_and_masks.add((ks.get_value(tag=self.filter_routing_tag),
ks.get_mask(tag=self.filter_routing_tag)))

return keys_and_masks

def build_routes(self, minimise=False, off_set=set()):
"""Build the data structure to be written to memory.
Parameters
----------
minimise : bool
Whether to use logic minimisation to reduce the size of the routing
tables. The minimisation used is greedy (not exact) so an off-set
(`off_set`) must be provided if it is desired that some packets do
not match against the minimised table.
off_set : {(key, mask), ...}
Set of keys and masks which should not match against the minimised
set of filter routes.
"""
# Generate a list of signals (hashing by ID) to the filters they
# target.
signal_id_to_signals = dict()
Expand Down Expand Up @@ -391,13 +423,15 @@ def build_routes(self, minimise=False):
if target_set != other_target_set:
off_sets[target_set].update(keymasks)

# (Minimise) and build the routing entries.
# (Minimise) and build the routing entries using the off-sets that were
# created above and the general off-set provided to this function.
self.filter_routes = list()
for (dmask, targets), keymasks in iteritems(targets_to_keymasks):
for target in targets:
all_keymasks = (
keymasks if not minimise else
ccf_minimise(keymasks, off_sets[(dmask, targets)])
ccf_minimise(keymasks,
off_set.union(off_sets[(dmask, targets)]))
)

# Write in an entry for each key and mask as usual
Expand Down
8 changes: 8 additions & 0 deletions tests/regions/test_filters.py
Expand Up @@ -318,6 +318,14 @@ def test_filter_routing_region():
# Check that the memory requirement is sane
assert filter_region.sizeof() == 4 * (1 + 4*len(signal_routes))

# Check that the set of expected keys and masks can be extracted
assert filter_region.get_expected_keys_and_masks() == {
(ks_a.get_value(tag=ksc.filter_routing_tag),
ks_a.get_mask(tag=ksc.filter_routing_tag)),
(ks_b.get_value(tag=ksc.filter_routing_tag),
ks_b.get_mask(tag=ksc.filter_routing_tag)),
}

# Check that the written out data is sensible
fp = tempfile.TemporaryFile()
filter_region.build_routes()
Expand Down

0 comments on commit 293e8cc

Please sign in to comment.