def test_equivalence_decoders(self): """Parameters are only equivalent if they have the same decoders.""" transform = Transform(1, 1, 1) tp1 = EnsembleTransmissionParameters(np.ones((3, 100)), transform) tp2 = EnsembleTransmissionParameters(np.zeros((3, 100)), transform) assert tp1 != tp2 tp3 = EnsembleTransmissionParameters(np.ones((3, 100)), transform) assert hash(tp1) == hash(tp3) assert tp1 == tp3
def test_concat_no_connection(self): a = EnsembleTransmissionParameters( decoders=[[1.0, 2.0, 3.0, 4.0], [4.0, 3.0, 2.0, 1.0]], transform=Transform(2, 4, 1, slice_out=(1, 2)) ) b = PassthroughNodeTransmissionParameters( Transform(size_in=4, size_out=2, transform=1.0, slice_in=(0, 3)) ) # Combine the parameters assert a.concat(b) is None
def test_concat_no_connection(self): a = EnsembleTransmissionParameters(decoders=[[1.0, 2.0, 3.0, 4.0], [4.0, 3.0, 2.0, 1.0]], transform=Transform(2, 4, 1, slice_out=(1, 2))) b = PassthroughNodeTransmissionParameters( Transform(size_in=4, size_out=2, transform=1.0, slice_in=(0, 3))) # Combine the parameters assert a.concat(b) is None
def test_projects_to(self): """Test that the parameters correctly report if they transmit any values to the dimensions listed. """ tp = EnsembleTransmissionParameters( decoders=np.ones((1, 4)), transform=Transform(size_in=1, size_out=16, transform=1.0, slice_out=slice(4)) ) assert tp.projects_to(slice(1)) assert tp.projects_to(slice(5)) assert not tp.projects_to(slice(4, 8)) assert tp.projects_to((0, 1, 2, 4))
def test_projects_to(self): """Test that the parameters correctly report if they transmit any values to the dimensions listed. """ tp = EnsembleTransmissionParameters(decoders=np.ones((1, 4)), transform=Transform( size_in=1, size_out=16, transform=1.0, slice_out=slice(4))) assert tp.projects_to(slice(1)) assert tp.projects_to(slice(5)) assert not tp.projects_to(slice(4, 8)) assert tp.projects_to((0, 1, 2, 4))
def test_equivalence_learning_rule(self): """Parameters are equivalent only if they both have no learning rule.""" t = Transform(1, 1, 1) tp1 = EnsembleTransmissionParameters([[1]], t, learning_rule=None) tp2 = EnsembleTransmissionParameters([[1]], t, learning_rule=object()) assert tp1 != tp2 tp3 = EnsembleTransmissionParameters([[1]], t) assert hash(tp1) == hash(tp3) assert tp1 == tp3 tp4 = EnsembleTransmissionParameters([[1]], t, learning_rule=tp2.learning_rule) assert tp4 != tp2
def test_concat_no_learning_rule(self): a = EnsembleTransmissionParameters( decoders=[[1.0, 2.0, 3.0, 4.0], [4.0, 3.0, 2.0, 1.0]], transform=Transform(2, 4, 1, slice_out=(1, 2)) ) b = PassthroughNodeTransmissionParameters( Transform(size_in=4, size_out=2, transform=1.0, slice_in=(1, 2)) ) # Combine the parameters c = a.concat(b) # Check the results assert isinstance(c, EnsembleTransmissionParameters) assert c.learning_rule is None assert c.size_out == b.size_out assert np.array_equal(c.slice_out, b.slice_out) assert np.array_equal(c.decoders, a.decoders)
def test_full_decoders(self): """Test that the decoders and transform are combined correctly.""" decoders = np.array([[0.5, 2.5, -.3, 1.0]]) transform = Transform(size_in=1, size_out=2, transform=[[-1.0], [1.0]]) tp = EnsembleTransmissionParameters(decoders=decoders, transform=transform) assert np.array_equal( tp.full_decoders, np.array([[-0.5, -2.5, 0.3, -1.0], [0.5, 2.5, -.3, 1.0]]))
def test_global_inhibition(self): tp = EnsembleTransmissionParameters( decoders=np.random.normal(size=(10, 100)), transform=Transform(size_in=10, size_out=200, transform=np.ones((200, 10)))) assert tp.supports_global_inhibition tp2 = tp.as_global_inhibition_connection assert tp2.size_out == 1 and tp2.slice_out.size == 1 assert np.array_equal(tp2.full_transform(), np.ones((1, 10)))
def test_concat_no_learning_rule(self): a = EnsembleTransmissionParameters(decoders=[[1.0, 2.0, 3.0, 4.0], [4.0, 3.0, 2.0, 1.0]], transform=Transform(2, 4, 1, slice_out=(1, 2))) b = PassthroughNodeTransmissionParameters( Transform(size_in=4, size_out=2, transform=1.0, slice_in=(1, 2))) # Combine the parameters c = a.concat(b) # Check the results assert isinstance(c, EnsembleTransmissionParameters) assert c.learning_rule is None assert c.size_out == b.size_out assert np.array_equal(c.slice_out, b.slice_out) assert np.array_equal(c.decoders, a.decoders)
def test_stack_interposers_no_interposer(self): # Create a network consisting of two ensembles targeting a sink MockEnsemble = collections.namedtuple("MockEnsemble", "size_in") source_1 = EnsembleLIF(MockEnsemble(1)) source_2 = EnsembleLIF(MockEnsemble(1)) sink = object() # Create a connection map and add the connections cm = model.ConnectionMap() cm.add_connection( source_1, OutputPort.standard, model.SignalParameters(weight=512), EnsembleTransmissionParameters( decoders=np.ones((1, 100)), transform=Transform( size_in=1, size_out=1, transform=1.0 ) ), sink, InputPort.standard, model.ReceptionParameters(None, 1, None) ) cm.add_connection( # Make sure the transform is distinct! source_2, OutputPort.standard, model.SignalParameters(weight=512), EnsembleTransmissionParameters( decoders=np.ones((1, 100)), transform=Transform( size_in=1, size_out=1, transform=0.5 ) ), sink, InputPort.standard, model.ReceptionParameters(None, 512, None) ) # Insert and stack the interposers interposers, new_cm = cm.insert_and_stack_interposers() assert len(interposers) == 0 # The connection map should be unchanged assert new_cm._connections == cm._connections
def test_stack_interposers_no_stack(self): # Create a network consisting of two ensembles targeting a sink, insert # interposers into this network and then stack the interposers to # reduce later connectivity. MockEnsemble = collections.namedtuple("MockEnsemble", "size_in") source_1 = EnsembleLIF(MockEnsemble(1)) source_2 = EnsembleLIF(MockEnsemble(1)) sink = object() # Create a connection map and add the connections cm = model.ConnectionMap() cm.add_connection( source_1, OutputPort.standard, model.SignalParameters(weight=512), EnsembleTransmissionParameters( decoders=np.ones((1, 100)), transform=Transform( size_in=1, size_out=512, transform=np.ones((512, 1)) ) ), sink, InputPort.standard, model.ReceptionParameters(None, 512, None) ) cm.add_connection( # Transform and the filter are distinct! source_2, OutputPort.standard, model.SignalParameters(weight=512), EnsembleTransmissionParameters( decoders=np.ones((1, 100)), transform=Transform( size_in=1, size_out=512, transform=0.5*np.ones((512, 1)) ) ), sink, InputPort.standard, model.ReceptionParameters(object(), 512, None) ) # Insert and stack the interposers interposers, new_cm = cm.insert_and_stack_interposers() new_cm = new_cm._connections assert len(interposers) == 2
def test_stack_interposers(self): """Test that interposers with equivalent output sets are stacked correctly and that this modifies both their incoming and output connections. """ # Create a network consisting of two ensembles targeting a sink, insert # interposers into this network and then stack the interposers to # reduce later connectivity. MockEnsemble = collections.namedtuple("MockEnsemble", "size_in") source_1 = EnsembleLIF(MockEnsemble(1)) source_2 = EnsembleLIF(MockEnsemble(1)) sink = object() # Create a connection map and add the connections cm = model.ConnectionMap() cm.add_connection( source_1, OutputPort.standard, model.SignalParameters(weight=512), EnsembleTransmissionParameters( decoders=np.ones((1, 100)), transform=Transform( size_in=1, size_out=512, transform=np.ones((512, 1)) ) ), sink, InputPort.standard, model.ReceptionParameters(None, 512, None) ) cm.add_connection( # Make sure the transform is distinct! source_2, OutputPort.standard, model.SignalParameters(weight=512), EnsembleTransmissionParameters( decoders=np.ones((1, 100)), transform=Transform( size_in=1, size_out=512, transform=0.5*np.ones((512, 1)) ) ), sink, InputPort.standard, model.ReceptionParameters(None, 512, None) ) # Insert and stack the interposers interposers, new_cm = cm.insert_and_stack_interposers() new_cm = new_cm._connections assert len(interposers) == 1 # Should only be one interposer interposer = interposers[0] assert interposer.size_in == 2 # The connections from the sources and from the interposer can be one # of two forms, attempt to determine which and then check that the rest # of the connections are correct. assert set(new_cm.keys()) == {source_1, source_2, interposer} assert len(new_cm[source_1][OutputPort.standard]) == 1 assert len(new_cm[source_2][OutputPort.standard]) == 1 assert len(new_cm[interposer][OutputPort.standard]) == 1 for params, sinks in iteritems(new_cm[source_1][OutputPort.standard]): sps, tps = params # Extract signal and transmission parameters assert isinstance(sps, model.SignalParameters) assert sps.weight == 1 # Weight should not be modified assert isinstance(tps, EnsembleTransmissionParameters) assert tps.size_in == 1 assert tps.size_out == 2 if np.array_equal(tps.slice_out, np.array([0])): # Source 1 points to the first dimension of the interposer. # Assert that Source 2 points to the other dimension of the # interposer. expected_source_2_slice = np.array([1]) expected_transform = np.hstack( (np.ones((512, 1)), 0.5*np.ones((512, 1))) ) elif np.array_equal(tps.slice_out, np.array([1])): # Source 2 points to the second dimension of the interposer. # Assert that Source 2 points to the other dimension of the # interposer. expected_source_2_slice = np.array([0]) expected_transform = np.hstack( (0.5*np.ones((512, 1)), np.ones((512, 1))) ) else: assert False, "Unexpected dimension in slice" # Check that the sinks are as expected assert len(sinks) == 1 for new_sink in sinks: assert new_sink.sink_object is interposer for params, sinks in iteritems(new_cm[source_2][OutputPort.standard]): sps, tps = params # Extract signal and transmission parameters assert isinstance(sps, model.SignalParameters) assert sps.weight == 1 assert isinstance(tps, EnsembleTransmissionParameters) assert tps.size_in == 1 assert tps.size_out == 2 assert np.array_equal(tps.slice_out, expected_source_2_slice) assert len(sinks) == 1 for new_sink in sinks: assert new_sink.sink_object is interposer # Check the connection from the interposer for params, sinks in iteritems( new_cm[interposer][OutputPort.standard]): sps, tps = params # Extract signal and transmission parameters assert isinstance(sps, model.SignalParameters) assert sps.weight == 512 # Not changed assert isinstance(tps, PassthroughNodeTransmissionParameters) assert tps.size_in == 2 assert tps.size_out == 512 assert np.array_equal( tps.full_transform(False, False), expected_transform ) assert len(sinks) == 1 for new_sink in sinks: assert new_sink.sink_object is sink
def test_insert_interposer_after_ensemble(self): """Test that an interposer can be inserted after a connection from an ensemble. """ # Create an ensemble and connect it to another ensemble with a # significantly larger size in. mock_ensemble_1 = mock.Mock(spec_set=["size_in"]) mock_ensemble_1.size_in = 1 e1 = EnsembleLIF(mock_ensemble_1) mock_ensemble_2 = mock.Mock(spec_set=["size_in"]) mock_ensemble_2.size_in = 512 e2 = EnsembleLIF(mock_ensemble_2) # Create a new connection map and add a connection between the # ensembles. transform = Transform(2, 512, np.ones((512, 2))) tps = EnsembleTransmissionParameters(np.ones((2, 100)), transform) sps = model.SignalParameters(weight=512) filt = object() cm = model.ConnectionMap() cm.add_connection( e1, OutputPort.standard, sps, tps, e2, InputPort.standard, model.ReceptionParameters(filt, 512, None) ) # Insert interposers interposers, new_cm = cm.insert_interposers() # Check that an interposer was inserted assert len(interposers) == 1 interposer = interposers[0] # Grab the interposer assert interposer.size_in == 2 # Check that the connection from e1 to the interposer is as expected assert len(new_cm._connections[e1][OutputPort.standard]) == 1 for conn, sinks in iteritems( new_cm._connections[e1][OutputPort.standard]): new_sps, new_tps = conn # Get signal and transmission pars assert isinstance(tps, EnsembleTransmissionParameters) assert np.array_equal(tps.decoders, new_tps.decoders) assert new_tps.size_out == 2 assert new_sps.weight == 2 assert np.array_equal( new_tps.full_transform(False, False), np.eye(2) ) assert len(sinks) == 1 for sink in sinks: assert sink.sink_object is interposer assert sink.reception_parameters == model.ReceptionParameters( None, 2, None ) # Check that the connection from the interposer to e2 is as expected assert len(new_cm._connections[interposer][OutputPort.standard]) == 1 for conn, sinks in iteritems( new_cm._connections[interposer][OutputPort.standard]): new_sps, new_tps = conn # Check that the transform is as expected assert isinstance(new_tps, PassthroughNodeTransmissionParameters) assert np.array_equal(tps.full_transform(False, False), new_tps.full_transform(False, False)) assert np.array_equal(tps.slice_out, new_tps.slice_out) # Check the sinks are correct assert len(sinks) == 1 for sink in sinks: assert sink.sink_object is e2 assert sink.reception_parameters == model.ReceptionParameters( filt, 512, None )
def _copy_connections_from_source(self, source, target_map, interposers): """Copy the pattern of connectivity from a source object, inserting the determined connectivity into a new connection map instance and inserting connections to interposers as appropriate. Parameters ---------- source : object Object in the connection map whose outgoing connections should be copied into the new connection map. target_map: :py:class:`~.ConnectionMap` Connection map into which the new connections should be copied. interposers : {(PassthroughNode, port, conn): Filter, ...} Dictionary mapping selected nodes, ports and connections to the operators which will be used to simulate them. Returns ------- {(PassthroughNode, port, conn), ...} Set of interposers who were reached by connections from this object. """ used_interposers = set() # Interposers fed by this object # For every port and set of connections originating at the source for source_port, conns_sinks in iteritems(self._connections[source]): for conn, sinks in iteritems(conns_sinks): # Extract the signal and transmission parameters signal_parameters, transmission_parameters = conn if (source, source_port, conn) in interposers: # If this connection is to be replaced by an interposer # then we instead add a connection to the interposer, the # nature of this connection depends on the nature of the # source. assert isinstance(source, EnsembleLIF) interposer = interposers[(source, source_port, conn)] # Create a new connection to the interposer and mark the # interposer as reached. new_sps = SignalParameters( weight=transmission_parameters.size_in) new_tps = EnsembleTransmissionParameters( transmission_parameters.decoders, Transform(transmission_parameters.size_in, transmission_parameters.size_in, 1)) target_map.add_connection( source, source_port, new_sps, new_tps, interposer, InputPort.standard, ReceptionParameters(None, new_sps.weight, None)) used_interposers.add((source, source_port, conn)) else: # Otherwise we add the connection. # Copy the connections and mark which interposers are # reached. for sink in sinks: # NOTE: The None indicates that no additional reception # parameters beyond those in the sink are to be # considered. used_interposers.update( self._copy_connection(target_map, interposers, source, source_port, signal_parameters, transmission_parameters, sink.sink_object, sink.port, sink.reception_parameters)) return used_interposers