def test_accepts_signal(self): # Create a series of vertex slices pfss = [ ParallelFilterSlice(slice(0, 16), slice(None)), ParallelFilterSlice(slice(8, 24), slice(None)), ParallelFilterSlice(slice(16, 32), slice(None)), ] # Create a series of transmission parameters, of current known types. ens_0_to_8 = np.random.uniform(size=(100, 10)) ens_0_to_8[:, 8:] = 0.0 tp0 = EnsembleTransmissionParameters(ens_0_to_8, 1.0) ptn_20_to_26 = np.zeros((32, 6)) ptn_20_to_26[20:26, :] = np.eye(6) tp1 = PassthroughNodeTransmissionParameters(ptn_20_to_26) # Check that `accepts_signal` responds correctly assert pfss[0].accepts_signal(None, tp0) assert not pfss[1].accepts_signal(None, tp0) assert not pfss[2].accepts_signal(None, tp0) assert not pfss[0].accepts_signal(None, tp1) assert pfss[1].accepts_signal(None, tp1) assert pfss[2].accepts_signal(None, tp1)
def test_x_to_x_optimize_out(self, from_type, final_port): # Create the ingoing connection parameters in_transmission_params = { "ensemble": EnsembleTransmissionParameters(np.dot([[1.0], [0.0]], np.random.uniform(size=(100, 1)).T), None), "node": NodeTransmissionParameters( slice(10, 20), mock.Mock(), np.array([[1.0], [0.0]]) ), "ptn": PassthroughNodeTransmissionParameters( np.array([[1.0], [0.0]]) ), }[from_type] # Create the outgoing connection parameters out_transmission_params = PassthroughNodeTransmissionParameters( np.array([[0.0, 0.0], [0.0, 1.0]]) ) # Combine the parameter sets new_tps, new_in_port = model_utils._combine_transmission_params( in_transmission_params, out_transmission_params, final_port ) # Check that the connection is optimised out assert new_tps is None assert new_in_port is None
def _combine_transmission_params(in_transmission_parameters, out_transmission_parameters, final_port): """Combine transmission parameters to join two signals into one, e.g., for optimising out a passthrough Node. Returns ------- transmission_parameters New transmission parameters port New receiving port for the connection """ assert isinstance(out_transmission_parameters, PassthroughNodeTransmissionParameters) # Compute the new transform new_transform = np.dot(out_transmission_parameters.transform, in_transmission_parameters.transform) # If the resultant transform is empty then we return None to indicate that # the connection should be dropped. if np.all(new_transform == 0.0): return None, None # If the connection is a global inhibition connection then truncate the # transform and modify the final port to reroute the connection. if (final_port is EnsembleInputPort.neurons and np.all(new_transform[0] == new_transform[1:])): # Truncate the transform new_transform = new_transform[0] new_transform.shape = (1, -1) # Ensure the result is a matrix # Change the final port final_port = EnsembleInputPort.global_inhibition # Construct the new transmission parameters if isinstance(in_transmission_parameters, EnsembleTransmissionParameters): transmission_params = EnsembleTransmissionParameters( in_transmission_parameters.untransformed_decoders, new_transform) elif isinstance(in_transmission_parameters, NodeTransmissionParameters): transmission_params = NodeTransmissionParameters( in_transmission_parameters.pre_slice, in_transmission_parameters.function, new_transform) elif isinstance(in_transmission_parameters, PassthroughNodeTransmissionParameters): transmission_params = PassthroughNodeTransmissionParameters( new_transform) else: raise NotImplementedError return transmission_params, final_port
def test_ens_to_gi(self): # Create the ingoing connection parameters in_transmission_params = EnsembleTransmissionParameters( np.random.uniform(size=(100, 7)), 1.0) # Create the outgoing connection parameters out_transmission_params = PassthroughNodeTransmissionParameters( np.ones((200, 7))) # Combine the parameter sets new_tps, new_in_port = model_utils._combine_transmission_params( in_transmission_params, out_transmission_params, EnsembleInputPort.neurons) # Check that all the parameters are correct assert np.all(new_tps.transform == 1.0) assert new_tps.transform.shape == (1, 7) assert new_tps.decoders.shape == (1, 100) assert new_in_port is EnsembleInputPort.global_inhibition
def test_ens_to_x(self, final_port): # Create the ingoing connection parameters in_transmission_params = EnsembleTransmissionParameters( np.random.uniform(size=(100, 10)), 1.0) # Create the outgoing connection parameters out_transmission_params = PassthroughNodeTransmissionParameters( np.hstack([np.eye(5), np.zeros((5, 5))])) # Combine the parameter sets new_tps, new_in_port = model_utils._combine_transmission_params( in_transmission_params, out_transmission_params, final_port) # Check that all the parameters are correct assert np.all(new_tps.untransformed_decoders == in_transmission_params.untransformed_decoders) assert np.all(new_tps.transform == out_transmission_params.transform) assert new_tps.decoders.shape == (5, 100) assert new_in_port is final_port
def test_remove_operator_from_connection_map_unforced(): """Check that a calculation is made to determine whether it is better to keep or remove an operator depending on the density of the outgoing connections. In the example: /- G[0] A[0] --\ /-- D[0] --\ /-- G[1] A[1] --- B --- C --- D[1] --- E --- F --- G[2] A[n] --/ \-- D[n] --/ \-- G[3] \- G[n] B, C and F should be removed but E should be retained: /- G[0] A[0] --- D[0] --\ /-- G[1] A[1] --- D[1] --- E --- G[2] A[n] --- D[n] --/ \-- G[3] \- G[n] """ # Create the operators D = 512 SD = 16 op_A = [mock.Mock(name="A{}".format(i)) for i in range(D // SD)] op_B = mock.Mock(name="B") op_C = mock.Mock(name="C") op_D = [mock.Mock(name="D{}".format(i)) for i in range(D // SD)] op_E = mock.Mock(name="E") op_F = mock.Mock(name="F") op_G = [mock.Mock(name="G{}".format(i)) for i in range(D)] # Create a connection map cm = model.ConnectionMap() # Create the fan-in connections for sources, sink in ((op_A, op_B), (op_D, op_E)): # Get the signal and reception parameters sps = model.SignalParameters(True, D) rps = model.ReceptionParameters(None, D) for i, source in enumerate(sources): # Get the transform transform = np.zeros((D, SD)) transform[i * SD:(i + 1) * SD, :] = np.eye(SD) # Get the parameters tps = EnsembleTransmissionParameters(np.ones((1, SD)), transform) cm.add_connection(source_object=source, source_port=None, signal_parameters=sps, transmission_parameters=tps, sink_object=sink, sink_port=None, reception_parameters=rps) # Create the fan-out connection C to D[...] # Get the signal and reception parameters sps = model.SignalParameters(True, SD) rps = model.ReceptionParameters(None, SD) for i, sink in enumerate(op_D): # Get the transform transform = np.zeros((SD, D)) transform[:, i * SD:(i + 1) * SD] = np.eye(SD) # Get the parameters tps = PassthroughNodeTransmissionParameters(transform) cm.add_connection(source_object=op_C, source_port=None, signal_parameters=sps, transmission_parameters=tps, sink_object=sink, sink_port=None, reception_parameters=rps) # Create the connection B to C sps = model.SignalParameters(True, D) rps = model.ReceptionParameters(None, D) tps = PassthroughNodeTransmissionParameters(np.eye(D)) cm.add_connection(source_object=op_B, source_port=None, signal_parameters=sps, transmission_parameters=tps, sink_object=op_C, sink_port=None, reception_parameters=rps) # Create the connection E to F transform = np.zeros((D, D)) for i in range(D): for j in range(D): transform[i, j] = i + j sps = model.SignalParameters(True, D) rps = model.ReceptionParameters(None, D) tps = PassthroughNodeTransmissionParameters(transform) cm.add_connection(source_object=op_E, source_port=None, signal_parameters=sps, transmission_parameters=tps, sink_object=op_F, sink_port=None, reception_parameters=rps) # Create the fan-out connections from F sps = model.SignalParameters(True, SD) rps = model.ReceptionParameters(None, SD) for i, sink in enumerate(op_G): # Get the transform transform = np.zeros((1, D)) transform[:, i] = 1.0 # Get the parameters tps = PassthroughNodeTransmissionParameters(transform) cm.add_connection(source_object=op_F, source_port=None, signal_parameters=sps, transmission_parameters=tps, sink_object=sink, sink_port=None, reception_parameters=rps) # Remove all of the passthrough Nodes, only E should be retained assert model_utils.remove_operator_from_connection_map(cm, op_B, force=False) assert model_utils.remove_operator_from_connection_map(cm, op_C, force=False) assert not model_utils.remove_operator_from_connection_map( cm, op_E, force=False) assert model_utils.remove_operator_from_connection_map(cm, op_F, force=False) # Check that each A has only one outgoing signal and that it terminates at # the paired D. Additionally check that each D has only one outgoing # signal and that it terminates at E. for a, d in zip(op_A, op_D): # Connections from A[n] from_a = cm._connections[a] assert len(from_a) == 1 assert len(from_a[None]) == 1 ((signal_parameters, transmission_parameters), sinks) = from_a[None][0] assert signal_parameters == model.SignalParameters(True, SD, None) assert transmission_parameters.transform.shape == (SD, SD) assert np.all(transmission_parameters.transform == np.eye(SD)) assert sinks == [(d, None, model.ReceptionParameters(None, SD))] # Connection(s) from D[n] from_d = cm._connections[d] assert len(from_d) == 1 assert len(from_d[None]) == 1 ((signal_parameters, transmission_parameters), sinks) = from_d[None][0] assert signal_parameters == model.SignalParameters(True, D, None) assert transmission_parameters.transform.shape == (D, SD) # Check that there are many connections from E from_e = cm._connections[op_E] assert len(from_e) == 1 print(from_e[None][0].parameters[1].transform) assert len(from_e[None]) == D