Exemple #1
0
    def _encodeSynSparse(self,
                         synIds,
                         weights,
                         cIdxOffset,
                         cIdxMult,
                         signMode,
                         kernelIds=None,
                         delays=None,
                         softReset=False):
        """Encode synapses using SPARSE compression.

        :param np.ndarray synIds: Synapse indices.
        :param np.ndarray weights: Weight values.
        :param int cIdxOffset: cIdxOffset.
        :param int cIdxMult: cIdxMult.
        :param int signMode: Defines how inhibitory and excitatory weights are
            treated. 1: Signs are not shared. 2: Excitatory connections with
            shared sign. 3: Inhibitory connections with shared sign.
        :param np.ndarray kernelIds: Global indices of synapse weights. Only
            needed for plotting and reconstructing kernelIdMap to validate
            partition.
        :param np.ndarray delays: Delay values
        :param bool softReset: True if synapse is used in soft-reset mode.

        :return: List of synaptic entries.
        :rtype: list[SynEntry]
        """

        kIds = None
        dlys = None
        numSyn = len(synIds)
        numSynEntries = int(math.ceil(numSyn / self._maxNumSynPerSynEntry))
        for i in range(numSynEntries):
            # Compute id range of up to 60 synapses of current synEntry
            cIdStart = i * self._maxNumSynPerSynEntry
            cIdEnd = min(cIdStart + self._maxNumSynPerSynEntry, numSyn)

            # Get synaptic configuration
            idx = synIds[cIdStart:cIdEnd]
            if kernelIds is not None:
                kIds = kernelIds[cIdStart:cIdEnd]
            wgts = weights[cIdStart:cIdEnd]
            if delays is not None:
                dlys = delays[cIdStart:cIdEnd]
            numIdxBits = self._getNumIdxBits(np.max(idx))

            # Generate synapses and synEntries
            synFmt = SynFmt(len(self._synFmts), cIdxOffset, cIdxMult,
                            numIdxBits, 0, self.numWeightBits,
                            Compression.SPARSE, signMode, self.numDelayBits,
                            softReset)
            self._synFmts.append(synFmt)

            synEntry = SynEntry(0, idx, wgts, synFmt, kIds, dlys)
            self._synEntries.append(synEntry)
Exemple #2
0
def compressSynFmts(synFmts, maxNumSynFmt):
    """Compress ``synFmts`` by pruning and merging.

    Finds the unique set of synFmts and merges the remaining synFmts until the
    number of different synFmts is below ``maxNumSynFmts``.

    :param list[SynFmt] synFmts: List of all synFmt objects.
    :param int maxNumSynFmt: Maximum number of synFmts supported by core.
    :returns: tuple(synFmts, synEntryToFmtMap)
        synFmts is a list of merged synFmt objects.
        synEntryToFmtMap is a mapping vector from global synEntry
        index to set of merged synFmts.
    """

    # Extract synFmt properties into array for processing
    synFmtProperties = np.stack([synFmt.asArray() for synFmt in synFmts])

    # Extract unique synFmts properties and mapping from synEntries to synFmts
    synFmtProperties, synEntryToFmtMap = np.unique(synFmtProperties,
                                                   return_inverse=True,
                                                   axis=0)
    numSynFmts = synFmtProperties.shape[0]

    # Compute pairwise distances between rows of synFmtProperties
    # (cIdx{Offset/Mult} and compression receive high weight because they are
    # not allowed to differ). It's conceivable to merge different compressions
    # but that requires re-encoding of synEntries.
    distances = np.infty * np.ones((numSynFmts, numSynFmts))
    for i in range(numSynFmts):
        for j in range(i):
            distances[i, j] = _computeDistance(synFmtProperties[i],
                                               synFmtProperties[j])

    # Merge closest rows of synFmtProperties iteratively until number of
    # distinct synFmts is small enough.
    while numSynFmts > maxNumSynFmt:

        if np.all(np.isinf(distances)):
            print(numSynFmts)
            break

        # Find index of shortest distance in distances.
        idx = np.unravel_index([np.argmin(distances)], distances.shape)
        idx0, idx1 = sorted([idx[0][0], idx[1][0]])

        # Overwrite the first of the two closest rows with the merged row.
        # The merged row has the same cIdx{Offset/Mult} and compression but
        # uses their max of numIdxBits, numSkipBits and numWgtBits.
        synFmtProperties[idx0, 2:5] = \
            np.max(synFmtProperties[[idx0, idx1], 2:5], axis=0)

        # Delete the second of the two closest rows in synFmtProperties and in
        # distances.
        synFmtProperties = np.delete(synFmtProperties, idx1, axis=0)
        distances = np.delete(np.delete(distances, idx1, axis=0), idx1, axis=1)

        # Recompute distances of all other rows to merged row.
        for j in range(idx0):
            distances[idx0, j] = _computeDistance(synFmtProperties[idx0],
                                                  synFmtProperties[j])
        for j in range(idx0 + 1, distances.shape[1]):
            distances[j, idx0] = _computeDistance(synFmtProperties[j],
                                                  synFmtProperties[idx0])

        # Remap synEntryToFmtMap from redundant row to merged row.
        synEntryToFmtMap[synEntryToFmtMap == idx1] = idx0

        # Reduce all row indices above the redundant row by one.
        synEntryToFmtMap[synEntryToFmtMap > idx1] -= 1

        numSynFmts -= 1

    synFmts = []
    for i in range(numSynFmts):
        args = synFmtProperties[i, :-4]
        # Convert compression arg from int to Enum.
        kwargs = {
            'compression': Compression(synFmtProperties[i, -4]),
            'signMode': synFmtProperties[i, -3],
            'numDlyBits': synFmtProperties[i, -2],
            'softReset': synFmtProperties[i, -1]
        }
        synFmts.append(SynFmt(i, *args, **kwargs))

    return synFmts, synEntryToFmtMap
Exemple #3
0
    def _encodeSynDense2(self,
                         synIds,
                         weights,
                         cIdxOffset,
                         cIdxMult,
                         signMode,
                         kernelIds=None,
                         delays=None,
                         softReset=False):
        """Encode synapses using DENSE compression.

        This encoder does not create synaptic entries whenever the
        compartment index increments by more than 1. Instead it inserts dummy
        connections with weight 0.

        :param np.ndarray synIds: Synapse indices.
        :param np.ndarray weights: Weight values.
        :param int cIdxOffset: cIdxOffset.
        :param int cIdxMult: cIdxMult.
        :param int signMode: Defines how inhibitory and excitatory weights are
            treated. 1: Signs are not shared. 2: Excitatory connections with
            shared sign. 3: Inhibitory connections with shared sign.
        :param np.ndarray kernelIds: Global indices of synapse weights. Only
            needed for plotting and reconstructing kernelIdMap to validate
            partition.
        :param np.ndarray delays: Delay values
         :param bool softReset: True if synapse is used in soft-reset mode.

        :return: List of synaptic entries.
        :rtype: list[SynEntry]
        """

        cIdsUnprocessed = np.copy(synIds)
        wgtsUnprocessed = np.copy(weights)
        dlysUnprocessed = None if delays is None else np.copy(delays)
        kIdsUnprocessed = None if kernelIds is None else np.copy(kernelIds)
        kIds = None
        dlys = None

        while len(cIdsUnprocessed):
            # Extract compartment index range of at most size maxNumSynPerEntry
            cIdStart = cIdsUnprocessed[0]
            mask = cIdsUnprocessed < (cIdStart + self._maxNumSynPerSynEntry)
            notMask = np.logical_not(mask)
            cIds = cIdsUnprocessed[mask]
            cIdEnd = np.max(cIds) + 1

            # Get synaptic configuration
            idx = np.arange(cIdEnd - cIdStart)
            prefixOffset = cIdStart

            if kernelIds is not None:
                kIds = np.zeros(idx.shape, int)
                kIds[cIds - cIdStart] = kIdsUnprocessed[mask]
                kIdsUnprocessed = kIdsUnprocessed[notMask]

            wgts = np.zeros(idx.shape, int)
            wgts[cIds - cIdStart] = wgtsUnprocessed[mask]

            if delays is not None:
                dlys = np.zeros(idx.shape, int)
                dlys[cIds - cIdStart] = dlysUnprocessed[mask]
                dlysUnprocessed = dlysUnprocessed[notMask]

            numIdxBits = self._getNumIdxBits(prefixOffset)

            # Discard processed synaptic configuration
            cIdsUnprocessed = cIdsUnprocessed[notMask]
            wgtsUnprocessed = wgtsUnprocessed[notMask]

            # Generate synapses and synEntries
            synFmt = SynFmt(len(self._synFmts), cIdxOffset, cIdxMult,
                            numIdxBits, 0, self.numWeightBits,
                            Compression.DENSE, signMode, self.numDelayBits,
                            softReset)
            self._synFmts.append(synFmt)

            synEntry = SynEntry(prefixOffset, idx, wgts, synFmt, kIds, dlys)
            self._synEntries.append(synEntry)
Exemple #4
0
    def _encodeSynDense1(self,
                         synIds,
                         weights,
                         cIdxOffset,
                         cIdxMult,
                         signMode,
                         kernelIds=None,
                         delays=None,
                         softReset=False):
        """Encode synapses using DENSE compression.

        This encoder creates a new synaptic entry whenever a compartment
        index increment greater than 1 is detected. That means no dummy
        connections with zero weight are created.

        :param np.ndarray synIds: Synapse indices.
        :param np.ndarray kernelIds: Weight indices.
        :param int cIdxOffset: cIdxOffset.
        :param int cIdxMult: cIdxMult.
        :param int signMode: Defines how inhibitory and excitatory weights are
            treated. 1: Signs are not shared. 2: Excitatory connections with
            shared sign. 3: Inhibitory connections with shared sign.
        :param np.ndarray kernelIds: Global indices of synapse weights. Only
            needed for plotting and reconstructing kernelIdMap to validate
            partition.
        :param np.ndarray delays: Delay values
        :param bool softReset: True if synapse is used in soft-reset mode.

        :return: List of synaptic entries.
        :rtype: list[SynEntry]
        """

        kIds = None
        dlys = None
        numSyn = len(synIds)
        cIdStart = 0
        # Find indices of gaps in the connection vector, in descending order.
        gapIds = list(np.flatnonzero(np.diff(synIds) > 1))[::-1]
        while cIdStart < numSyn:
            # Compute id range of up to 60 synapses of current synEntry or
            # until next non-1 compartment index increment
            cIdEnd = min(cIdStart + self._maxNumSynPerSynEntry, numSyn)
            if len(gapIds) and gapIds[-1] < cIdEnd:
                cIdEnd = gapIds.pop() + 1

            # Get synaptic configuration
            idx = synIds[cIdStart:cIdEnd]
            prefixOffset = idx[0]
            if kernelIds is not None:
                kIds = kernelIds[cIdStart:cIdEnd]
            wgts = weights[cIdStart:cIdEnd]
            if delays is not None:
                dlys = delays[cIdStart:cIdEnd]
            numIdxBits = self._getNumIdxBits(prefixOffset)

            # Generate synapses and synEntries
            synFmt = SynFmt(len(self._synFmts), cIdxOffset, cIdxMult,
                            numIdxBits, 0, self.numWeightBits,
                            Compression.DENSE, signMode, self.numDelayBits,
                            softReset)
            self._synFmts.append(synFmt)

            synEntry = SynEntry(prefixOffset, idx - prefixOffset, wgts, synFmt,
                                kIds, dlys)
            self._synEntries.append(synEntry)

            cIdStart = cIdEnd
Exemple #5
0
    def _encodeSynRunLength(self,
                            synIds,
                            weights,
                            cIdxOffset,
                            cIdxMult,
                            signMode,
                            kernelIds=None,
                            delays=None,
                            softReset=False):
        """Encode synapses using RUNLENGTH compression.

        Creates a new ``SynEntry`` whenever it detects a gap >= 2**5 (limit on
        ``skipIdxBits``).

        .. note:: Assumes that first skip index is zero!

        :param np.ndarray synIds: Synapse indices.
        :param np.ndarray kernelIds: Weight indices.
        :param int cIdxOffset: cIdxOffset.
        :param int cIdxMult: cIdxMult.
        :param int signMode: Defines how inhibitory and excitatory weights are
            treated. 1: Signs are not shared. 2: Excitatory connections with
            shared sign. 3: Inhibitory connections with shared sign.
        :param np.ndarray kernelIds: Global indices of synapse weights. Only
            needed for plotting and reconstructing kernelIdMap to validate
            partition.
        :param np.ndarray delays: Delay values
        :param bool softReset: True if synapse is used in soft-reset mode.

        :return: List of synaptic entries.
        :rtype: list[SynEntry]
        """

        kIds = None
        dlys = None
        numSyn = len(synIds)
        cIdStart = 0
        # Find indices of gaps in the connection vector, in descending order.
        gapIds = list(
            np.flatnonzero(np.diff(synIds) >= 2**self._maxNumSkipBits))[::-1]
        while cIdStart < numSyn:
            # Compute id range of up to 60 synapses of current synEntry or
            # until next compartment index increment >= 2**5.
            cIdEnd = min(cIdStart + self._maxNumSynPerSynEntry, numSyn)
            if len(gapIds) and gapIds[-1] < cIdEnd:
                cIdEnd = gapIds.pop() + 1

            # Get synaptic configuration
            idx = synIds[cIdStart:cIdEnd]
            skipIdx = np.insert(np.diff(idx), 0, 0)
            prefixOffset = idx[0]
            if kernelIds is not None:
                kIds = kernelIds[cIdStart:cIdEnd]
            wgts = weights[cIdStart:cIdEnd]
            if delays is not None:
                dlys = delays[cIdStart:cIdEnd]
            numIdxBits = self._getNumIdxBits(prefixOffset)
            numSkipBits = self._getNumSkipBits(np.max(skipIdx))

            # Generate synapses and synEntries
            synFmt = SynFmt(len(self._synFmts), cIdxOffset, cIdxMult,
                            numIdxBits, numSkipBits, self.numWeightBits,
                            Compression.RUNLENGTH, signMode, self.numDelayBits,
                            softReset)
            self._synFmts.append(synFmt)

            synEntry = SynEntry(prefixOffset, skipIdx, wgts, synFmt, kIds,
                                dlys)
            self._synEntries.append(synEntry)

            cIdStart = cIdEnd
Exemple #6
0
    def test_mapSynapses_3(self):
        """Check generation of synGrpMap."""

        verbose = False

        layer = Layer(layerId=0,
                      layerType='',
                      compartmentKwargs={},
                      connectionKwargs={"weightExponent": 2},
                      coreIdMap=np.array([]),
                      multiplicityMap=np.array([]),
                      postLayer=None)

        sf = SynFmt(synFmtId=0,
                    cIdxOffset=0,
                    cIdxMult=2,
                    numIdxBits=6,
                    numSkipBits=0,
                    numWgtBits=8,
                    compression=0,
                    signMode=1)

        se0 = SynEntry(prefixOffset=0,
                       idxs=np.array([0, 1, 2]),
                       weights=np.array([6, 7, 8]),
                       synFmt=sf)

        se1 = SynEntry(prefixOffset=10,
                       idxs=np.array([0, 1]),
                       weights=np.array([16, 17]),
                       synFmt=sf)

        se2 = SynEntry(prefixOffset=20,
                       idxs=np.array([0, 1, 2]),
                       weights=np.array([26, 27, 28]),
                       synFmt=sf)

        se3 = SynEntry(prefixOffset=30,
                       idxs=np.array([0, 1]),
                       weights=np.array([36, 37]),
                       synFmt=sf)

        sg0 = SynapseGroup(groupId=0, synEntries=[[se0, se1, se2], [se3]])

        sg1 = SynapseGroup(groupId=1, synEntries=[[se0], [se1], [se2, se3]])

        p = Partition(partitionId=0,
                      chipCounter=0,
                      sizeInterleaved=-1,
                      parentLayer=layer)

        p.addSynFmt(sf)

        p.addSynapseGroup(sg0)
        p.addSynapseGroup(sg1)

        layer.addPartition(p)

        numSyn = 10 * 2
        board = N2Board(0)
        c = DnnMapper(board)
        core = board.allocateCores(1, numSyn)[0]

        c._mapSynapses(p, core)  # pylint: disable=protected-access

        if verbose:
            print(c._synGrpMap)

        self.assertEqual(len(c._synGrpMap), 5)
        self.assertEqual(c._synGrpMap[(sg0, 0)], (0, 8))
        self.assertEqual(c._synGrpMap[(sg0, 1)], (8, 2))
        self.assertEqual(c._synGrpMap[(sg1, 0)], (10, 3))
        self.assertEqual(c._synGrpMap[(sg1, 1)], (13, 2))
        self.assertEqual(c._synGrpMap[(sg1, 2)], (15, 5))
Exemple #7
0
    def test_mapSynapses_2(self):
        """Check switching between synFmt for successive synEntries if
        synFmtId does not change."""

        verbose = False

        layer = Layer(layerId=0,
                      layerType='',
                      compartmentKwargs={},
                      connectionKwargs={"weightExponent": 2},
                      coreIdMap=np.array([]),
                      multiplicityMap=np.array([]),
                      postLayer=None)

        sf0 = SynFmt(synFmtId=0,
                     cIdxOffset=0,
                     cIdxMult=2,
                     numIdxBits=6,
                     numSkipBits=0,
                     numWgtBits=8,
                     compression=0,
                     signMode=1)

        sf1 = SynFmt(synFmtId=1,
                     cIdxOffset=0,
                     cIdxMult=2,
                     numIdxBits=7,
                     numSkipBits=0,
                     numWgtBits=8,
                     compression=1,
                     signMode=1)

        se00 = SynEntry(prefixOffset=0,
                        idxs=np.array([0, 1, 2]),
                        weights=np.array([6, 7, 8]),
                        synFmt=sf0)

        se01 = SynEntry(prefixOffset=10,
                        idxs=np.array([0, 1]),
                        weights=np.array([16, 17]),
                        synFmt=sf0)

        se02 = SynEntry(prefixOffset=20,
                        idxs=np.array([0, 1, 2]),
                        weights=np.array([26, 27, 28]),
                        synFmt=sf0)

        se10 = SynEntry(prefixOffset=30,
                        idxs=np.array([0, 1]),
                        weights=np.array([36, 37]),
                        synFmt=sf1)

        sg = SynapseGroup(groupId=0, synEntries=[[se00, se01, se02], [se10]])

        p = Partition(partitionId=0,
                      chipCounter=0,
                      sizeInterleaved=-1,
                      parentLayer=layer)

        p.addSynFmt(sf0)
        p.addSynFmt(sf1)

        p.addSynapseGroup(sg)

        layer.addPartition(p)

        numSyn = 10
        board = N2Board(0)
        c = DnnMapper(board)
        core = board.allocateCores(1, numSyn)[0]

        c._mapSynapses(p, core)  # pylint: disable=protected-access

        if verbose:
            c.printCore(core, synapses=True)

        cIdx = [0, 1, 2, 10, 11, 20, 21, 22, 30, 31]
        wgts = [6, 7, 8, 16, 17, 26, 27, 28, 36, 37]
        synFmtIds = [1, 1, 1, 2, 2, 1, 1, 1, 3, 3]

        for i in range(numSyn):
            self.assertEqual(core.synapses[i].CIdx, cIdx[i])
            self.assertEqual(core.synapses[i].Wgt, wgts[i])
            self.assertEqual(core.synapses[i].synFmtId, synFmtIds[i])
Exemple #8
0
    def test_mapSynapses_1(self):
        """Check allocation of synFmts."""

        verbose = False

        layer = Layer(layerId=0,
                      layerType='',
                      compartmentKwargs={},
                      connectionKwargs={"weightExponent": 2},
                      coreIdMap=np.array([]),
                      multiplicityMap=np.array([]),
                      postLayer=None)

        sf0 = SynFmt(synFmtId=0,
                     cIdxOffset=0,
                     cIdxMult=2,
                     numIdxBits=6,
                     numSkipBits=0,
                     numWgtBits=8,
                     compression=0,
                     signMode=2)

        sf1 = SynFmt(synFmtId=1,
                     cIdxOffset=0,
                     cIdxMult=2,
                     numIdxBits=6,
                     numSkipBits=0,
                     numWgtBits=6,
                     compression=0,
                     signMode=3)

        p = Partition(partitionId=0,
                      chipCounter=0,
                      sizeInterleaved=-1,
                      parentLayer=layer)

        p.addSynFmt(sf0)
        p.addSynFmt(sf1)

        layer.addPartition(p)

        board = N2Board(0)
        c = DnnMapper(board)
        core = board.allocateCores(1, 0)[0]

        c._mapSynapses(p, core)  # pylint: disable=protected-access

        if verbose:
            c.printCore(core, synFmts=True)

        # Validate number of synFmts
        self.assertEqual(len(core.synapseFmt.modified), 4)

        # Validate duplication of synFmts by checking unique fanoutTypes
        self.assertEqual(core.synapseFmt[1].fanoutType, 2)
        self.assertEqual(core.synapseFmt[2].fanoutType, 2)
        self.assertEqual(core.synapseFmt[3].fanoutType, 3)
        self.assertEqual(core.synapseFmt[4].fanoutType, 3)

        # Validate mapping of numWgtBits -> wgtBits
        self.assertEqual(core.synapseFmt[1].wgtBits, 7)
        self.assertEqual(core.synapseFmt[3].wgtBits, 6)

        # Validate wgtExp
        self.assertEqual(core.synapseFmt[1].wgtExp, 2)
Exemple #9
0
    def test_mapInputAxons_1(self):
        """Check mapping of InputAxonGroup with all input nodes having
        multiplicity 1."""

        verbose = False

        layer = Layer(layerId=0,
                      layerType='',
                      compartmentKwargs={},
                      connectionKwargs={"weightExponent": 2},
                      coreIdMap=np.array([]),
                      multiplicityMap=np.array([]),
                      postLayer=None)

        sf = SynFmt(synFmtId=0,
                    cIdxOffset=0,
                    cIdxMult=2,
                    numIdxBits=6,
                    numSkipBits=0,
                    numWgtBits=8,
                    compression=0,
                    signMode=1)

        se0 = SynEntry(prefixOffset=0,
                       idxs=np.array([0, 1, 2]),
                       weights=np.array([6, 7, 8]),
                       synFmt=sf)

        se1 = SynEntry(prefixOffset=10,
                       idxs=np.array([0, 1]),
                       weights=np.array([16, 17]),
                       synFmt=sf)

        se2 = SynEntry(prefixOffset=20,
                       idxs=np.array([0, 1, 2]),
                       weights=np.array([26, 27, 28]),
                       synFmt=sf)

        se3 = SynEntry(prefixOffset=30,
                       idxs=np.array([0, 1]),
                       weights=np.array([36, 37]),
                       synFmt=sf)

        sg = SynapseGroup(groupId=0,
                          synEntries=[[se0, se1], [se1, se2, se3], [se3]])

        p = Partition(partitionId=0,
                      chipCounter=0,
                      sizeInterleaved=-1,
                      parentLayer=layer)

        p.addSynFmt(sf)

        p.addSynapseGroup(sg)

        iag = InputAxonGroup(srcNodeIds=np.array([10, 11, 12]),
                             multiplicity=np.array([1, 1, 1]),
                             synGroup=sg,
                             cxBase=2,
                             parentPartition=p)

        p.addInputAxonGroup(iag)
        layer.addPartition(p)

        numSyn = 14
        board = N2Board(0)
        c = DnnMapper(board)
        core = board.allocateCores(1, numSyn)[0]

        c._mapSynapses(p, core)  # pylint: disable=protected-access
        c._mapInputAxons(p, core)  # pylint: disable=protected-access

        # Validate input axon
        sMap = core.synapseMap[0]
        self.assertEqual(sMap.synapsePtr, 0)
        self.assertEqual(sMap.synapseLen, [5, 7, 2])
        self.assertEqual(sMap.popSize, 3)
        self.assertEqual(sMap.population32MapEntry.ptr, 0)
        self.assertEqual(sMap.population32MapEntry.length, 3)
        self.assertEqual(sMap.population32MapEntry.cxBase, 2)

        # Validate inAxMap
        self.assertTrue(
            np.array_equal(c._inAxMap[iag.id],
                           np.array([[0, 0, 4], [0, 0, 4], [0, 0, 4]], int)))

        if verbose:
            c.printCore(core, inputAxons=True)
Exemple #10
0
    def test_mapInputAxons_4(self):
        """Check mapping of multiple InputAxonGroups."""

        verbose = False

        layer = Layer(layerId=0,
                      layerType='',
                      compartmentKwargs={},
                      connectionKwargs={"weightExponent": 2},
                      coreIdMap=np.array([]),
                      multiplicityMap=np.array([]),
                      postLayer=None)

        sf = SynFmt(synFmtId=0,
                    cIdxOffset=0,
                    cIdxMult=2,
                    numIdxBits=6,
                    numSkipBits=0,
                    numWgtBits=8,
                    compression=0,
                    signMode=1)

        se0 = SynEntry(prefixOffset=0,
                       idxs=np.array([0, 1, 2]),
                       weights=np.array([6, 7, 8]),
                       synFmt=sf)

        se1 = SynEntry(prefixOffset=10,
                       idxs=np.array([0, 1]),
                       weights=np.array([16, 17]),
                       synFmt=sf)

        se2 = SynEntry(prefixOffset=20,
                       idxs=np.array([0, 1, 2]),
                       weights=np.array([26, 27, 28]),
                       synFmt=sf)

        se3 = SynEntry(prefixOffset=30,
                       idxs=np.array([0, 1]),
                       weights=np.array([36, 37]),
                       synFmt=sf)

        sg0 = SynapseGroup(groupId=0,
                           synEntries=[[se0, se1], [se1, se2, se3], [se3]])

        sg1 = SynapseGroup(groupId=1,
                           synEntries=[[se0, se1], [se2], [se1, se2, se3]])

        p = Partition(partitionId=0,
                      chipCounter=0,
                      sizeInterleaved=-1,
                      parentLayer=layer)

        p.addSynFmt(sf)

        p.addSynapseGroup(sg0)
        p.addSynapseGroup(sg1)

        iag0 = InputAxonGroup(srcNodeIds=np.array([10, 11, 12]),
                              multiplicity=np.array([1, 1, 1]),
                              synGroup=sg0,
                              cxBase=1,
                              parentPartition=p)

        iag1 = InputAxonGroup(srcNodeIds=np.array([10, 11, 12]),
                              multiplicity=np.array([1, 2, 1]),
                              synGroup=sg0,
                              cxBase=2,
                              parentPartition=p)

        iag2 = InputAxonGroup(srcNodeIds=np.array([10, 11, 12]),
                              multiplicity=np.array([1, 2, 3]),
                              synGroup=sg1,
                              cxBase=3,
                              parentPartition=p)

        p.addInputAxonGroup(iag0)
        p.addInputAxonGroup(iag1)
        p.addInputAxonGroup(iag2)
        layer.addPartition(p)

        board = N2Board(0)
        c = DnnMapper(board)
        core = board.allocateCores(1, p.numSyn)[0]

        c._mapSynapses(p, core)  # pylint: disable=protected-access
        c._mapInputAxons(p, core)  # pylint: disable=protected-access

        # Validate axons of iag0
        sMapShared = core.synapseMap[0]
        self.assertEqual(sMapShared.synapsePtr, 0)
        self.assertEqual(sMapShared.synapseLen, [5, 7, 2])
        self.assertEqual(sMapShared.popSize, 3)
        self.assertEqual(sMapShared.population32MapEntry.ptr, 0)
        self.assertEqual(sMapShared.population32MapEntry.length, 3)
        self.assertEqual(sMapShared.population32MapEntry.cxBase, 1)

        # Validate axons of iag1
        sMapShared = core.synapseMap[1]
        self.assertEqual(sMapShared.synapsePtr, 0)
        self.assertEqual(sMapShared.synapseLen, [5, 7, 2])
        self.assertEqual(sMapShared.popSize, 3)
        self.assertEqual(sMapShared.population32MapEntry.ptr, 0)
        self.assertEqual(sMapShared.population32MapEntry.length, 3)
        self.assertEqual(sMapShared.population32MapEntry.cxBase, 2)

        sMapDiscrete = core.synapseMap[2]
        self.assertEqual(sMapDiscrete.synapsePtr, 5)
        self.assertEqual(sMapDiscrete.synapseLen, 7)
        self.assertEqual(sMapDiscrete.discreteMapEntry.ptr, 3)
        self.assertEqual(sMapDiscrete.discreteMapEntry.length, 3)
        self.assertEqual(sMapDiscrete.discreteMapEntry.cxBase, 2)

        # Validate axons of iag2
        sMapShared = core.synapseMap[3]
        self.assertEqual(sMapShared.synapsePtr, 14)
        self.assertEqual(sMapShared.synapseLen, [5, 3, 7])
        self.assertEqual(sMapShared.popSize, 3)
        self.assertEqual(sMapShared.population32MapEntry.ptr, 9)
        self.assertEqual(sMapShared.population32MapEntry.length, 3)
        self.assertEqual(sMapShared.population32MapEntry.cxBase, 3)

        sMapDiscrete = core.synapseMap[4]
        self.assertEqual(sMapDiscrete.synapsePtr, 19)
        self.assertEqual(sMapDiscrete.synapseLen, 3)
        self.assertEqual(sMapDiscrete.discreteMapEntry.ptr, 12)
        self.assertEqual(sMapDiscrete.discreteMapEntry.length, 1)
        self.assertEqual(sMapDiscrete.discreteMapEntry.cxBase, 3)

        sMapDiscrete = core.synapseMap[5]
        self.assertEqual(sMapDiscrete.synapsePtr, 22)
        self.assertEqual(sMapDiscrete.synapseLen, 7)
        self.assertEqual(sMapDiscrete.discreteMapEntry.ptr, 15)
        self.assertEqual(sMapDiscrete.discreteMapEntry.length, 3)
        self.assertEqual(sMapDiscrete.discreteMapEntry.cxBase, 3)

        # Validate inAxMap
        self.assertTrue(
            np.array_equal(c._inAxMap[iag0.id],
                           np.array([[0, 0, 4], [0, 0, 4], [0, 0, 4]], int)))
        self.assertTrue(
            np.array_equal(c._inAxMap[iag1.id],
                           np.array([[1, 0, 4], [2, 0, 4], [1, 0, 4]], int)))
        self.assertTrue(
            np.array_equal(c._inAxMap[iag2.id],
                           np.array([[3, 0, 4], [4, 0, 4], [5, 0, 4]], int)))

        if verbose:
            c.printCore(core, inputAxons=True)