def test_filter_routing_region_duplicate_connection(): """Test that an error is raised if mismatched connections with the same key are identified. """ # Define a single keyspace ksc = KeyspaceContainer() ks = ksc["nengo"](connection_id=3) ksc.assign_fields() # Define some signals to hold these keyspaces sig_a = SignalParameters(keyspace=ks) sig_b = SignalParameters(keyspace=ks) # Define the filter routes, these map a keyspace to an integer signal_routes = [(sig_a, 12), (sig_b, 12), (sig_b, 17)] # Create the region filter_region = FilterRoutingRegion( signal_routes, filter_routing_tag=ksc.filter_routing_tag, index_field="index") # Extract a dictionary of the constraints on the signal keys (no # constraints because the keyspace was specified before). assert len(filter_region.get_signal_constraints()) == 0 # Check that an error is raised because two signals with the same key route # in different directions fp = tempfile.TemporaryFile() with pytest.raises(AssertionError): filter_region.build_routes()
def test_forced_filter_width(self): """Test construction of filter regions from signals and keyspaces.""" # Create two keyspaces, two signals and two connections with equivalent # synapses. # Create two keyspaces, two signals and two reception parameters with # different synapses. ks_a = mock.Mock(name="Keyspace[A]") signal_a = SignalParameters(keyspace=ks_a, latching=False) ks_b = mock.Mock(name="Keyspace[B]") signal_b = SignalParameters(keyspace=ks_b, latching=False) rp_a = ReceptionParameters(nengo.Lowpass(0.01), 3, None) rp_b = ReceptionParameters(None, 5, None) # Create the type of dictionary that is expected as input specs = [ ReceptionSpec(signal_a, rp_a), ReceptionSpec(signal_b, rp_b), ] # Create the regions, with minimisation filter_region, routing_region = make_filter_regions(specs, 0.001, width=1) # Check that the filter region is as expected for f in filter_region.filters: assert (f == LowpassFilter(1, False, 0.01) or f == NoneFilter(1, False)) # noqa: E711
def test_filter_routing_region(): """Test creation of a filter routing region.""" # Define some keyspaces ksc = KeyspaceContainer() ks_a = ksc["nengo"](connection_id=3) ks_b = ksc["nengo"](connection_id=255, cluster=63, index=15) ksc.assign_fields() # Define some signals to hold these keyspaces sig_a = SignalParameters(keyspace=ks_a) sig_b = SignalParameters(keyspace=ks_b) # Define the filter routes, these map a keyspace to an integer signal_routes = [(sig_a, 12), (sig_b, 17)] # Create the region filter_region = FilterRoutingRegion( signal_routes, filter_routing_tag=ksc.filter_routing_tag, index_field="index") # 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() filter_region.write_subregion_to_file(fp) # Check that the data is sensible fp.seek(0) length, = struct.unpack("<I", fp.read(4)) assert length == 2 # Determine valid values valid_mask = ksc["nengo"].get_mask(tag=ksc.filter_routing_tag) valid_d_mask = ksc["nengo"].get_mask(field="index") for _ in range(len(signal_routes)): key, mask, d_mask, i = struct.unpack("<4I", fp.read(16)) assert mask == valid_mask, hex(mask) + " != " + hex(valid_mask) assert d_mask == valid_d_mask for signal, j in signal_routes: ks = signal.keyspace if key == ks.get_value(tag=ksc.filter_routing_tag): assert i == j break else: assert False, "Unexpected key " + hex(key)
def test_get_net_keyspaces_fails_for_inconsistent_cluster(): """Test specification of keyspaces for nets fails in the case that inconsistent cluster IDs are assigned (this is unlikely to happen unless a Net somehow ends up having two different Nengo objects in its source list).""" # Create the vertices vertex_A = [Vertex() for _ in range(4)] vertex_B = Vertex() # Create placements such that vertex A and B fall on two chips and A[0] and # A[1] are on the same chip. placements = { vertex_A[0]: (0, 0), vertex_A[1]: (0, 0), vertex_A[2]: (0, 1), vertex_A[3]: (0, 1), vertex_B: (0, 0) } resources = {v: {} for v in placements} allocations = {v: {} for v in placements} # Create a container for the keyspaces ksc = KeyspaceContainer() # Create the signals and nets signal_a = Signal(object(), [], SignalParameters(keyspace=ksc["nengo"](connection_id=0))) signal_b = Signal(object(), [], SignalParameters(keyspace=ksc["nengo"](connection_id=1))) signal_c = Signal(object(), [], SignalParameters(keyspace=ksc["spam"])) nets = { signal_a: NMNet(vertex_A, vertex_B, 1.0), signal_b: NMNet(vertex_B, vertex_A, 2.0), signal_c: NMNet(vertex_A, vertex_A, 3.0), } # Identify groups groups = [set(vertex_A)] # Manually identify clusters (and do it such that it is inconsistent) vertex_A[0].cluster = 0 vertex_A[1].cluster = 1 vertex_A[2].cluster = 2 vertex_A[3].cluster = 3 # Get the routing nets _, _, _, _, derived_nets = utils.get_nets_for_routing( resources, nets, placements, allocations) # Get the net keyspaces with pytest.raises(AssertionError): utils.get_net_keyspaces(placements, nets, derived_nets)
def test_get_transforms_and_keys(): """Test that the complete transform matrix is constructed correctly and that appropriate keys are assigned. """ # Create 2 mock signals and associated connections sig_a_ks_0 = mock.Mock() sig_a_ks_1 = mock.Mock() sig_a_kss = { 0: sig_a_ks_0, 1: sig_a_ks_1, } sig_a_ks = mock.Mock() sig_a_ks.side_effect = lambda index: sig_a_kss[index] sig_a = SignalParameters(keyspace=sig_a_ks) conn_a = PassthroughNodeTransmissionParameters(np.eye(2)) sig_b_ks_0 = mock.Mock() sig_b_kss = { 0: sig_b_ks_0, } sig_b_ks = mock.Mock() sig_b_ks.side_effect = lambda index: sig_b_kss[index] sig_b = SignalParameters(keyspace=sig_b_ks) conn_b = PassthroughNodeTransmissionParameters(np.array([[0.5, 0.5]])) transform_b = conn_b.transform # Create the dictionary type that will be used pars = [(sig_a, conn_a), (sig_b, conn_b)] # Get the transforms and keys transforms, keys, signal_parameter_slices = get_transforms_and_keys(pars) # Check that the transforms and keys are correct assert set(keys) == set([sig_a_ks_0, sig_a_ks_1, sig_b_ks_0]) assert transforms.shape == (len(keys), 2) assert (np.all(transforms[0] == transform_b) or np.all(transforms[2] == transform_b)) # Check that the signal parameter slices are correct for (par, sl) in signal_parameter_slices: if par == conn_a: assert sl == set(range(0, 2)) or sl == set(range(1, 3)) else: assert par == conn_b assert sl == set(range(0, 1)) or sl == set(range(2, 3))
def test_equivalent_filters(self, minimise): """Test construction of filter regions from signals and keyspaces.""" # Create two keyspaces, two signal parameters and two reception # parameters with equivalent synapses. ks_a = mock.Mock(name="Keyspace[A]") signal_a = SignalParameters(keyspace=ks_a, latching=False) ks_b = mock.Mock(name="Keyspace[B]") signal_b = SignalParameters(keyspace=ks_b, latching=False) rp_a = ReceptionParameters(nengo.Lowpass(0.01), 3, None) rp_b = ReceptionParameters(nengo.Lowpass(0.01), 3, None) # Create the data structure that is expected as input specs = [ ReceptionSpec(signal_a, rp_a), ReceptionSpec(signal_b, rp_b), ] # Create the regions, with minimisation filter_region, routing_region = make_filter_regions( specs, 0.001, minimise=minimise, filter_routing_tag="spam", index_field="eggs") # Check that the filter region is as expected assert filter_region.dt == 0.001 if minimise: assert len(filter_region.filters) == 1 assert filter_region.filters[0] == LowpassFilter(3, False, 0.01) else: assert len(filter_region.filters) == 2 assert filter_region.filters[0] == LowpassFilter(3, False, 0.01) assert filter_region.filters[1] == LowpassFilter(3, False, 0.01) # Check that the routing region is as expected assert routing_region.filter_routing_tag == "spam" assert routing_region.index_field == "eggs" if minimise: assert (signal_a, 0) in routing_region.signal_routes assert (signal_b, 0) in routing_region.signal_routes else: if (signal_a, 0) in routing_region.signal_routes: assert (signal_b, 1) in routing_region.signal_routes else: assert (signal_b, 0) in routing_region.signal_routes
def test_removes_sinkless_filters(self): """Test that making a netlist correctly filters out passthrough Nodes with no outgoing connections. """ # Create the first operator object_a = mock.Mock(name="object A") vertex_a = mock.Mock(name="vertex A") load_fn_a = mock.Mock(name="load function A") pre_fn_a = mock.Mock(name="pre function A") post_fn_a = mock.Mock(name="post function A") operator_a = mock.Mock(name="operator A") operator_a.make_vertices.return_value = \ netlistspec(vertex_a, load_fn_a, pre_fn_a, post_fn_a) # Create the second operator object_b = mock.Mock(name="object B") operator_b = operators.Filter(16) # Shouldn't need building # Create the model, add the items and add an entry to the connection # map. model = Model() model.object_operators[object_a] = operator_a model.object_operators[object_b] = operator_b model.connection_map.add_connection(operator_a, None, SignalParameters(), None, operator_b, None, None) netlist = model.make_netlist(1) # The netlist should contain vertex a and no nets assert netlist.nets == list() assert netlist.vertices == [vertex_a]
def test_get_transforms_and_keys_removes_zeroed_rows(latching): """Check that zeroed rows (those that would always result in zero valued packets) are removed, and the keys miss this value as well. """ transform = np.ones((10, 5)) transform[1, :] = 0.0 transform[4:7, :] = 0.0 transform[:, 1] = 0.0 # Create a signal and keyspace sig = SignalParameters(latching=latching) # Create a mock connection conn = PassthroughNodeTransmissionParameters( Transform(size_in=5, size_out=10, transform=transform)) signals_connections = [(sig, conn)] # Get the transform and keys t, keys, _ = get_transforms_and_keys(signals_connections, slice(0, 5)) if not latching: # Check the transform is correct assert np.all(t == np.vstack((transform[0], transform[2:4], transform[7:]))) # Check the keys were called for correctly assert keys == [(sig, {"index": i}) for i in [0, 2, 3, 7, 8, 9]] else: # Check the transform is correct assert np.all(t == t) # Check the keys were called for correctly assert keys == [(sig, {"index": i}) for i in range(10)]
def test_from_parameters_force_width(self, latching, width): # Create the mock signal and connection signal = SignalParameters(latching=latching) rps = ReceptionParameters(None, width, None) # Build the filter nf = NoneFilter.from_parameters(signal, rps, width=1) assert NoneFilter(1, latching) == nf
def test_from_parameters_force_width(self): # Create the mock signal and connection signal = SignalParameters(latching=True) rps = ReceptionParameters(nengo.LinearFilter([1.0], [0.5, 1.0]), 1) # Create the filter lpf = LinearFilter.from_parameters(signal, rps, width=2) assert lpf == LinearFilter(2, True, [1.0], [0.5, 1.0])
def test_from_parameters_force_width(self, width, latching, tc): # Create the mock signal and connection signal = SignalParameters(latching=latching) rps = ReceptionParameters(nengo.Lowpass(tc), width, None) # Create the filter lpf = LowpassFilter.from_parameters(signal, rps, width=2) assert lpf == LowpassFilter(2, latching, tc)
def test_get_transforms_and_keys(): """Test that the complete transform matrix is constructed correctly and that appropriate keys are assigned. """ # Create 2 mock signals and associated connections sig_a = SignalParameters() conn_a = PassthroughNodeTransmissionParameters( Transform(size_in=2, size_out=2, transform=np.eye(2))) sig_b = SignalParameters() conn_b = PassthroughNodeTransmissionParameters( Transform(size_in=2, size_out=1, transform=np.array([[0.5, 0.5]]))) transform_b = conn_b.transform # Create the dictionary type that will be used pars = [(sig_a, conn_a), (sig_b, conn_b)] # Get the transforms and keys transforms, keys, signal_parameter_slices = \ get_transforms_and_keys(pars, slice(0, 2)) # Check that the transforms and keys are correct assert (keys == [(sig_b, { "index": 0 }), (sig_a, { "index": 0 }), (sig_a, { "index": 1 })] or keys == [(sig_a, { "index": 0 }), (sig_a, { "index": 1 }), (sig_b, { "index": 0 })]) assert transforms.shape == (len(keys), 2) assert (np.all(transforms[0] == transform_b) or np.all(transforms[2] == transform_b)) # Check that the signal parameter slices are correct for (par, sl) in signal_parameter_slices: if par == conn_a: assert sl == set(range(0, 2)) or sl == set(range(1, 3)) else: assert par == conn_b assert sl == set(range(0, 1)) or sl == set(range(2, 3))
def test_filter_routing_region_get_signal_constraints(): """Test the reporting of which signals cannot share a routing identifier. """ # Define some signals sig_a = SignalParameters() sig_b = SignalParameters() # Define the filter routes, these map a keyspace to an integer signal_routes = [(sig_a, 12), (sig_b, 12), (sig_b, 17)] # Create the region filter_region = FilterRoutingRegion(signal_routes) # Extract a dictionary of the constraints on the signal keys assert filter_region.get_signal_constraints() == { id(sig_a): {id(sig_b)}, id(sig_b): {id(sig_a)}, }
def _multiply_signals(in_kwargs, out_conn_kwargs): """Multiply an input connection by a selection of outgoing connection and yield keywords for every new connection. Yields ------ dict Keyword arguments for `ConnectionMap.add_connection` """ # For every outgoing connection for out_conn in out_conn_kwargs: # Combine the transmission parameters transmission_parameters, sink_port = _combine_transmission_params( in_kwargs["transmission_parameters"], out_conn["transmission_parameters"], out_conn["sink_port"]) # If the connection has been optimised out then move on if transmission_parameters is None and sink_port is None: continue # Combine the reception parameters reception_parameters = _combine_reception_params( in_kwargs["reception_parameters"], out_conn["reception_parameters"], ) # Combine the signal parameters: the new signal will be latching if # either the input or the output signals require it be so, it will have # the weight assigned by the reception parameters. If either the input # or output keyspace are None then the keyspace assigned to the other # signal will be used; if neither are None then we break because # there's no clear way to merge keyspaces. in_sig_pars = in_kwargs["signal_parameters"] out_sig_pars = out_conn["signal_parameters"] latching = in_sig_pars.latching or out_sig_pars.latching weight = out_sig_pars.weight if in_sig_pars.keyspace is None or out_sig_pars.keyspace is None: keyspace = in_sig_pars.keyspace or out_sig_pars.keyspace else: raise NotImplementedError("Cannot merge keyspaces") # Construct the new signal parameters signal_parameters = SignalParameters(latching, weight, keyspace) # Yield the new keyword arguments yield { "source_object": in_kwargs["source_object"], "source_port": in_kwargs["source_port"], "signal_parameters": signal_parameters, "transmission_parameters": transmission_parameters, "sink_object": out_conn["sink_object"], "sink_port": sink_port, "reception_parameters": reception_parameters, }
def test_different_filters(self): """Test construction of filter regions from signals and keyspaces.""" # Create two keyspaces, two signals and two reception parameters with # different synapses. ks_a = mock.Mock(name="Keyspace[A]") signal_a = SignalParameters(keyspace=ks_a, latching=False) ks_b = mock.Mock(name="Keyspace[B]") signal_b = SignalParameters(keyspace=ks_b, latching=False) rp_a = ReceptionParameters(nengo.Lowpass(0.01), 3, None) rp_b = ReceptionParameters(None, 3, None) # Create the type of dictionary that is expected as input specs = [ ReceptionSpec(signal_a, rp_a), ReceptionSpec(signal_b, rp_b), ] # Create the regions, with minimisation filter_region, routing_region = make_filter_regions( specs, 0.001, minimise=True, # Shouldn't achieve anything filter_routing_tag="spam", index_field="eggs") # Check that the filter region is as expected assert filter_region.dt == 0.001 assert len(filter_region.filters) == 2 for f in filter_region.filters: assert (f == LowpassFilter(3, False, 0.01) or f == NoneFilter(3, False)) # noqa: E711 # Check that the routing region is as expected assert routing_region.filter_routing_tag == "spam" assert routing_region.index_field == "eggs" if (signal_a, 0) in routing_region.signal_routes: assert (signal_b, 1) in routing_region.signal_routes else: assert (signal_b, 0) in routing_region.signal_routes
def test_get_transforms_and_keys_removes_zeroed_rows(latching): """Check that zeroed rows (those that would always result in zero valued packets) are removed, and the keys miss this value as well. """ ks = mock.Mock() transform = np.ones((10, 5)) transform[1, :] = 0.0 transform[4:7, :] = 0.0 transform[:, 1] = 0.0 # Create a signal and keyspace sig = mock.Mock() sig.keyspace = ks sig.latching = latching sig = SignalParameters(keyspace=ks, latching=latching) # Create a mock connection conn = PassthroughNodeTransmissionParameters(transform) signals_connections = [(sig, conn)] # Get the transform and keys t, keys, _ = get_transforms_and_keys(signals_connections) if not latching: # Check the transform is correct assert np.all(t == np.vstack((transform[0], transform[2:4], transform[7:]))) # Check the keys were called for correctly ks.assert_has_calls([mock.call(index=0), mock.call(index=2), mock.call(index=3), mock.call(index=7), mock.call(index=8), mock.call(index=9)]) else: # Check the transform is correct assert np.all(t == t) # Check the keys were called for correctly ks.assert_has_calls([mock.call(index=0), mock.call(index=1), mock.call(index=2), mock.call(index=3), mock.call(index=4), mock.call(index=5), mock.call(index=6), mock.call(index=7), mock.call(index=8), mock.call(index=9)])
def test_make_vertices_one_group_many_cores_1_chip(self): """Test that many vertices are returned if the matrix has many rows and that there is an appropriate constraint forcing the co-location of the vertices. """ # Create a small filter operator filter_op = Filter(3) # Create a model and add some connections which will cause packets to # be transmitted from the filter operator. m = Model() signal_parameters = SignalParameters(False, 3, m.keyspaces["nengo"]) signal_parameters.keyspace.length = 32 transmission_parameters = PassthroughNodeTransmissionParameters( Transform(size_in=3, size_out=96, transform=np.ones((96, 3)))) m.connection_map.add_connection(filter_op, OutputPort.standard, signal_parameters, transmission_parameters, None, None, None) # Make vertices using the model netlistspec = filter_op.make_vertices(m, 10000) assert len(netlistspec.vertices) == 2 # Two vertices for vx in netlistspec.vertices: assert "filter" in vx.application assert vx.resources[Cores] == 1 assert vx.regions[Regions.system].column_slice == slice(0, 3) keys_region = vx.regions[Regions.keys] assert keys_region.signals_and_arguments == [ (signal_parameters, dict(index=i)) for i in range(32 * 3) ] assert len(keys_region.fields) == 1 assert keys_region.partitioned is True assert vx.regions[Regions.transform].matrix.shape == (32 * 3, 3)
def test_multiple_source_vertices(self): """Test that each of the vertices associated with a source is correctly included in the sources of a net. """ class MyVertexSlice(VertexSlice): def __init__(self, *args, **kwargs): super(MyVertexSlice, self).__init__(*args, **kwargs) self.args = None def transmits_signal(self, signal_parameters, transmission_parameters): self.args = (signal_parameters, transmission_parameters) return False # Create the first operator vertex_a0 = VertexSlice(slice(0, 1)) vertex_a1 = VertexSlice(slice(1, 2)) vertex_a2 = MyVertexSlice(slice(2, 3)) load_fn_a = mock.Mock(name="load function A") pre_fn_a = mock.Mock(name="pre function A") post_fn_a = mock.Mock(name="post function A") object_a = mock.Mock(name="object A") operator_a = mock.Mock(name="operator A", spec_set=["make_vertices"]) operator_a.make_vertices.return_value = \ netlistspec([vertex_a0, vertex_a1, vertex_a2], load_fn_a, pre_fn_a, post_fn_a) # Create the second operator vertex_b = Vertex() load_fn_b = mock.Mock(name="load function B") object_b = mock.Mock(name="object B") operator_b = mock.Mock(name="operator B", spec_set=["make_vertices"]) operator_b.make_vertices.return_value = \ netlistspec((vertex_b, ), load_fn_b) # Create a signal between the operators keyspace = mock.Mock(name="keyspace") keyspace.length = 32 signal_ab_parameters = SignalParameters(keyspace=keyspace, weight=43) # Create the model, add the items and then generate the netlist model = Model() model.object_operators[object_a] = operator_a model.object_operators[object_b] = operator_b model.connection_map.add_connection(operator_a, None, signal_ab_parameters, None, operator_b, None, None) netlist = model.make_netlist() # Check that the netlist is as expected assert netlist.operator_vertices == { operator_a: (vertex_a0, vertex_a1, vertex_a2), operator_b: (vertex_b, ), } assert len(netlist.nets) == 1 for net in itervalues(netlist.nets): assert net.sources == [vertex_a0, vertex_a1] assert net.sinks == [vertex_b] assert len(netlist.constraints) == 0 # Check that `transmit_signal` was called correctly sig, tp = vertex_a2.args assert sig.keyspace is keyspace assert tp is None
def test_multiple_sink_vertices(self): """Test that each of the vertices associated with a sink is correctly included in the sinks of a net. """ # Create the first operator vertex_a = mock.Mock(name="vertex A") load_fn_a = mock.Mock(name="load function A") pre_fn_a = mock.Mock(name="pre function A") post_fn_a = mock.Mock(name="post function A") object_a = mock.Mock(name="object A") operator_a = mock.Mock(name="operator A", spec_set=["make_vertices"]) operator_a.make_vertices.return_value = \ netlistspec((vertex_a, ), load_fn_a, pre_fn_a, post_fn_a) # Create the second operator vertex_b0 = mock.Mock(name="vertex B0") vertex_b1 = mock.Mock(name="vertex B1") load_fn_b = mock.Mock(name="load function B") object_b = mock.Mock(name="object B") operator_b = mock.Mock(name="operator B", spec_set=["make_vertices"]) operator_b.make_vertices.return_value = \ netlistspec([vertex_b0, vertex_b1], load_fn_b) # Create a third operator, which won't accept the signal vertex_c = mock.Mock(name="vertex C") vertex_c.accepts_signal.side_effect = lambda _, __: False object_c = mock.Mock(name="object C") operator_c = mock.Mock(name="operator C", spec_set=["make_vertices"]) operator_c.make_vertices.return_value = netlistspec((vertex_c, )) # Create a signal between the operators keyspace = mock.Mock(name="keyspace") keyspace.length = 32 signal_ab_parameters = SignalParameters(keyspace=keyspace, weight=3) # Create the model, add the items and then generate the netlist model = Model() model.object_operators[object_a] = operator_a model.object_operators[object_b] = operator_b model.object_operators[object_c] = operator_c model.connection_map.add_connection(operator_a, None, signal_ab_parameters, None, operator_b, None, None) model.connection_map.add_connection(operator_a, None, signal_ab_parameters, None, operator_c, None, None) netlist = model.make_netlist() # Check that the "accepts_signal" method of vertex_c was called with # reasonable arguments assert vertex_c.accepts_signal.called # Check that the netlist is as expected assert netlist.operator_vertices == { operator_a: (vertex_a, ), operator_b: (vertex_b0, vertex_b1), operator_c: (vertex_c, ), } assert len(netlist.nets) == 1 for net in itervalues(netlist.nets): assert net.sources == [vertex_a] assert net.sinks == [vertex_b0, vertex_b1] assert net.weight == signal_ab_parameters.weight assert len(netlist.constraints) == 0
def test_single_vertices(self): """Test that operators which produce single vertices work correctly and that all functions and signals are correctly collected and included in the final netlist. """ # Create the first operator vertex_a = mock.Mock(name="vertex A") load_fn_a = mock.Mock(name="load function A") pre_fn_a = mock.Mock(name="pre function A") post_fn_a = mock.Mock(name="post function A") constraint_a = mock.Mock(name="Constraint B") object_a = mock.Mock(name="object A") operator_a = mock.Mock(name="operator A", spec_set=["make_vertices"]) operator_a.make_vertices.return_value = \ netlistspec((vertex_a, ), load_fn_a, pre_fn_a, post_fn_a, constraint_a) # Create the second operator vertex_b = mock.Mock(name="vertex B") load_fn_b = mock.Mock(name="load function B") constraint_b = mock.Mock(name="Constraint B") object_b = mock.Mock(name="object B") operator_b = mock.Mock(name="operator B", spec_set=["make_vertices"]) operator_b.make_vertices.return_value = \ netlistspec((vertex_b, ), load_fn_b, constraints=[constraint_b]) # Create a signal between the operators keyspace = mock.Mock(name="keyspace") keyspace.length = 32 signal_ab_parameters = SignalParameters(keyspace=keyspace, weight=43) # Create the model, add the items and then generate the netlist model = Model() model.object_operators[object_a] = operator_a model.object_operators[object_b] = operator_b model.connection_map.add_connection(operator_a, None, signal_ab_parameters, None, operator_b, None, None) netlist = model.make_netlist() # Check that the make_vertices functions were called operator_a.make_vertices.assert_called_once_with(model) operator_b.make_vertices.assert_called_once_with(model) # Check that the netlist is as expected assert len(netlist.nets) == 1 for net in itervalues(netlist.nets): assert net.sources == [vertex_a] assert net.sinks == [vertex_b] assert net.weight == signal_ab_parameters.weight assert netlist.operator_vertices == { operator_a: (vertex_a, ), operator_b: (vertex_b, ), } assert netlist.keyspaces is model.keyspaces assert set(netlist.constraints) == set([constraint_a, constraint_b]) assert set(netlist.load_functions) == set([load_fn_a, load_fn_b]) assert netlist.before_simulation_functions == [pre_fn_a] assert netlist.after_simulation_functions == [post_fn_a]
def test_standard(self, use_make_connection): """Test building a single connection, ensure that all appropriate methods are called and that the signal is added to the connection map. """ class A(object): pass # Create the connection (as a mock) connection_source = A() connection_sink = A() connection = mock.Mock() connection.pre_obj = connection_source connection.post_obj = connection_sink # Create the Model which we'll build with m = Model() # Modify the Model so that we can interpret calls to the connection map m.connection_map = mock.Mock(name="ConnectionMap") m.connection_map.insert_and_stack_interposers = mock.Mock( return_value=([], m.connection_map) # NOP ) source = mock.Mock(name="Source Object") source_port = mock.Mock(name="Source Port") sink = mock.Mock(name="Sink Object") sink_port = mock.Mock(name="Sink Port") # Add some build methods def source_getter(model, conn): assert model is m assert conn is connection return spec(ObjectPort(source, source_port)) def sink_getter(model, conn): assert model is m assert conn is connection return spec(ObjectPort(sink, sink_port)) source_getters = {A: mock.Mock(side_effect=source_getter)} sink_getters = {A: mock.Mock(side_effect=sink_getter)} transmission_parameters = mock.Mock(name="Transmission Params") def transmission_builder(model, conn): assert model is m assert conn is connection return transmission_parameters reception_parameters = mock.Mock(name="Reception Params") def reception_builder(model, conn): assert model is m assert conn is connection return reception_parameters transmission_parameter_builders = { A: mock.Mock(side_effect=transmission_builder) } reception_parameter_builders = { A: mock.Mock(side_effect=reception_builder) } # Make the connection if use_make_connection: # Set an RNG to build with m.rng = np.random # Set the builders m._source_getters = source_getters m._sink_getters = sink_getters m._transmission_parameter_builders = \ transmission_parameter_builders m._reception_parameter_builders = reception_parameter_builders # Build the connection directly m.make_connection(connection) else: # Embed the connection in a mock Nengo network and build that # instead. network = mock.Mock() network.seed = None network.connections = [connection] network.ensembles = [] network.nodes = [] network.networks = [] network.probes = [] # Build this (having overridden the builders) with mock.patch.object(m, "source_getters", source_getters), \ mock.patch.object(m, "sink_getters", sink_getters), \ mock.patch.object(m, "transmission_parameter_builders", transmission_parameter_builders), \ mock.patch.object(m, "reception_parameter_builders", reception_parameter_builders): m.build(network) # Assert the connection map received an appropriate call m.connection_map.add_connection.assert_called_once_with( source, source_port, SignalParameters(), transmission_parameters, sink, sink_port, reception_parameters)
def test_get_net_keyspaces(): """Test the correct specification of keyspaces for nets.""" # Create the vertices vertex_A = [Vertex() for _ in range(4)] vertex_B = Vertex() # Create placements such that vertex A and B fall on two chips and A[0] and # A[1] are on the same chip. placements = { vertex_A[0]: (0, 0), vertex_A[1]: (0, 0), vertex_A[2]: (0, 1), vertex_A[3]: (0, 1), vertex_B: (0, 0) } resources = {v: {} for v in placements} allocations = {v: {} for v in placements} # Manually assign cluster IDs vertex_A[0].cluster = 0 vertex_A[1].cluster = 0 vertex_A[2].cluster = 1 vertex_A[3].cluster = 1 # Create a container for the keyspaces ksc = KeyspaceContainer() # Create the signals and nets signal_a = Signal(object(), [], SignalParameters(keyspace=ksc["nengo"](connection_id=0))) signal_b = Signal(object(), [], SignalParameters(keyspace=ksc["nengo"](connection_id=1))) signal_c = Signal(object(), [], SignalParameters(keyspace=ksc["spam"])) nets = { signal_a: NMNet(vertex_A, vertex_B, 1.0), signal_b: NMNet(vertex_B, vertex_A, 2.0), signal_c: NMNet(vertex_A, vertex_A, 3.0), } # Get the routing nets _, _, _, _, derived_nets = utils.get_nets_for_routing( resources, nets, placements, allocations) # Get the net keyspaces net_keyspaces = utils.get_net_keyspaces(placements, nets, derived_nets) # Check the net keyspaces are correct # A -> B for xy, vertex in [((0, 0), vertex_A[0]), ((0, 1), vertex_A[2])]: net = derived_nets[nets[signal_a]][xy] cluster = vertex.cluster assert net_keyspaces[net] == signal_a.keyspace(cluster=cluster) # B -> A net = derived_nets[nets[signal_b]][(0, 0)] assert net_keyspaces[net] == signal_b.keyspace(cluster=0) # A -> A for xy in [(0, 0), (0, 1)]: net = derived_nets[nets[signal_c]][xy] assert net_keyspaces[net] == signal_c.keyspace # No change