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)
예제 #11
0
    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
예제 #12
0
    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
예제 #13
0
    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
예제 #14
0
    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
                )
예제 #15
0
    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