From 8c370f8ae76babb5f1c1432660318e9d78de8b1f Mon Sep 17 00:00:00 2001 From: Marcus Lewis Date: Tue, 30 Aug 2016 17:48:15 -0700 Subject: [PATCH] Merge "Segment" with "SegmentData", "Synapse" with "SynapseData" --- src/nupic/research/connections.py | 408 +++++++----------- src/nupic/research/temporal_memory.py | 42 +- tests/unit/nupic/research/connections_test.py | 45 +- .../nupic/research/temporal_memory_test.py | 53 ++- 4 files changed, 238 insertions(+), 310 deletions(-) diff --git a/src/nupic/research/connections.py b/src/nupic/research/connections.py index 7381684ae0..a35f1496f8 100644 --- a/src/nupic/research/connections.py +++ b/src/nupic/research/connections.py @@ -26,92 +26,87 @@ # other floats + class Segment(object): """ Class containing minimal information to identify a unique segment """ - __slots__ = ['cell', 'idx', 'data'] + __slots__ = ["cell", "idx", "flatIdx", "_synapses", "_numDestroyedSynapses", + "_destroyed", "_lastUsedIteration"] - def __init__(self, cell, idx, data): + def __init__(self, cell, idx, flatIdx): """ - @param cell (int) Index of the cell that this segment is on - @param idx (int) Index of the segment on the cell + @param cell (int) Index of the cell that this segment is on. + @param idx (int) Index of the segment on the cell. + @param flatIdx (int) The segment's flattened list index. """ self.cell = cell self.idx = idx - self.data = data + self.flatIdx = flatIdx + self._synapses = [] + self._numDestroyedSynapses = 0 + self._destroyed = False + self._lastUsedIteration = -1 def __eq__(self, other): - return (self.idx, self.cell) == (other.idx, other.cell) + """ Explicitly implement this for unit testing. The flatIdx is not designed + to be consistent after serialize / deserialize. + + """ + return ((self.idx, self.cell, self._synapses, self._numDestroyedSynapses, + self._destroyed, self._lastUsedIteration) == + (other.idx, other.cell, other._synapses, self._numDestroyedSynapses, + other._destroyed, other._lastUsedIteration)) + class Synapse(object): """ Class containing minimal information to identify a unique synapse """ - __slots__ = ['idx', 'segment', 'data'] + __slots__ = ["segment", "idx", "presynapticCell", "permanence", "_destroyed"] - def __init__(self, idx, segment, synapseData): - """ - @param idx (int) Index of the synapse on the segment - @param segment (Object) Segment Object that the synapse is synapsed to + def __init__(self, segment, idx, presynapticCell, permanence): """ - self.idx = idx - self.segment = segment - self.data = synapseData + @param segment + (Object) Segment object that the synapse is synapsed to. + @param idx (int) + Index of the synapse on the segment. - def __eq__(self, other): - return ((self.idx, self.segment, self.data) == - (other.idx, other.segment, other.data)) - + @param presynapticCell (int) + The index of the presynaptic cell of the synapse. -class SynapseData(object): - """ Class containing other important synapse information """ - - __slots__ = ['presynapticCell', 'permanence', 'destroyed'] - - def __init__(self, presynapticCell, permanence): - """ - @param presynapticCell (int) The index of the presynaptic cell of the - synapse - @param permanence (float) permanence of the synapse from 0.0 to 1.0 + @param permanence (float) + Permanence of the synapse from 0.0 to 1.0. """ + self.segment = segment + self.idx = idx self.presynapticCell = presynapticCell self.permanence = permanence - self.destroyed = False # boolean destroyed flag so object can be reused + self._destroyed = False def __eq__(self, other): - return (self.segment == other.segment and - self.presynapticCell == other.presynapticCell and - abs(self.permanence - other.permanence) < EPSILON) - + """ Explicitly implement this for unit testing. Allow floating point + differences for synapse permanence. -class SegmentData(object): - """ Class containing other important segment information """ - - __slots__ = ['synapses', 'numDestroyedSynapses', 'destroyed', - 'lastUsedIteration', 'flatIdx'] - - def __init__(self, flatIdx): - """ - @param flatIdx (int) global index of the segment """ - self.synapses = [] - self.numDestroyedSynapses = 0 - self.destroyed = False - self.lastUsedIteration = -1 - self.flatIdx = flatIdx + return ((self.segment.cell, self.segment.idx, self.idx, + self.presynapticCell) == + (other.segment.cell, other.segment.idx, other.idx, + other.presynapticCell) and + abs(self.permanence - other.permanence) < EPSILON) + class CellData(object): - """ Class containing cell information """ + """ Class containing cell information. Internal to the Connections. """ - __slots__ = ['segments', 'numDestroyedSegments'] + __slots__ = ["_segments", "_numDestroyedSegments"] def __init__(self): - self.segments = [] # list of segments on the cell - self.numDestroyedSegments = 0 + self._segments = [] + self._numDestroyedSegments = 0 @@ -152,8 +147,6 @@ def __init__(self, self._synapsesForPresynapticCell = defaultdict(list) self._segmentForFlatIdx = [] - self._synapsesForSegment = defaultdict(list) - self._numSegments = 0 self._numSynapses = 0 self._nextFlatIdx = 0 @@ -165,15 +158,13 @@ def segmentsForCell(self, cell): @param cell (int) Cell index - @return (list) Segment objects representing segments on the given cell + @return (generator) + Segment objects representing segments on the given cell. """ - segmentsList = self._cells[cell].segments - - - return [Segment(cell, i, segmentsList[i]) - for i in xrange(len(segmentsList)) - if not segmentsList[i].destroyed] + return (segment + for segment in self._cells[cell]._segments + if not segment._destroyed) def synapsesForSegment(self, segment): @@ -181,38 +172,42 @@ def synapsesForSegment(self, segment): @param segment (int) Segment index - @return (list) Synapse objects representing synapses on the given segment + @return (generator) + Synapse objects representing synapses on the given segment. """ - segmentData = segment.data - if segmentData.destroyed: + if segment._destroyed: raise ValueError("Attempting to access destroyed segment's synapses") - return [synapse - for synapse in self._synapsesForSegment[segmentData.flatIdx] - if not synapse.data.destroyed] + return (synapse + for synapse in segment._synapses + if not synapse._destroyed) def dataForSynapse(self, synapse): """ Returns the data for a synapse. + This method exists to match the interface of the C++ Connections. This + allows tests and tools to inspect the connections using a common interface. + @param synapse (Object) Synapse object - @return (SynapseData) Synapse data + @return Synapse data """ - - return synapse.data + return synapse def dataForSegment(self, segment): """ Returns the data for a segment. - @param segment (Object) Segment object + This method exists to match the interface of the C++ Connections. This + allows tests and tools to inspect the connections using a common interface. - @return (SegmentData) Segment data - """ + @param synapse (Object) Segment object - return segment.data + @return segment data + """ + return segment def getSegment(self, cell, idx): @@ -226,54 +221,33 @@ def getSegment(self, cell, idx): """ - return Segment(cell, idx, self._cells[cell].segments[idx]) - - - def _leastRecentlyUsedSegment(self, cell): - """ Internal method for finding the least recently activated segment on a - cell + return self._cells[cell]._segments[idx] - @param cell (int) cell index to search for segments on - @return (Object) Segment object of the segment that was least recently - created/activated. - """ - segments = self._cells[cell].segments - minIdx = float("inf") - minIteration = float("inf") - - for i in xrange(len(segments)): - segment = segments[i] - if (not segment.destroyed and - segment.lastUsedIteration < minIteration): - minIdx = i - minIteration = segment.lastUsedIteration + def _minPermanenceSynapse(self, segment): + """ Find this segment's synapse with the smallest permanence. - return Segment(cell, minIdx, segments[minIdx]) + This method is NOT equivalent to a simple min() call. It uses an EPSILON to + account for floating point differences between C++ and Python. + @param segment (Object) Segment to query. - def _minPermanenceSynapse(self, segment): - """ Internal method for finding the synapse with the smallest permanence - on the given segment. + @return (Object) Synapse with the minimal permanence - @param segment (Object) Segment object to search for synapses on + Note: On ties it will choose the first occurrence of the minimum permanence. - @return (Object) Synapse object on the segment of the minimal permanence - - Note: On ties it will chose the first occurrence of the minimum permanence """ - synapses = self._synapsesForSegment[segment.data.flatIdx] - minIdx = float("inf") + minSynapse = None minPermanence = float("inf") - for i in xrange(len(synapses)): - synapseData = synapses[i].data - if (not synapseData.destroyed) and (synapseData.permanence - < minPermanence - EPSILON): - minIdx = i - minPermanence = synapseData.permanence + for synapse in self.synapsesForSegment(segment): + if synapse.permanence < minPermanence - EPSILON: + minSynapse = synapse + minPermanence = synapse.permanence + + assert minSynapse is not None - return synapses[minIdx] + return minSynapse def segmentForFlatIdx(self, flatIdx): @@ -313,32 +287,24 @@ def createSegment(self, cell): @return (int) New segment index """ while self.numSegments(cell) >= self.maxSegmentsPerCell: - self.destroySegment(self._leastRecentlyUsedSegment(cell)) + leastRecentlyUsed = min(self.segmentsForCell(cell), + key=lambda s: s._lastUsedIteration) + self.destroySegment(leastRecentlyUsed) cellData = self._cells[cell] - segment = Segment(cell, -1, None) # New segment with some default values - - if cellData.numDestroyedSegments > 0: - found = False - for i in xrange(len(cellData.segments)): - if cellData.segments[i].destroyed: - segment.idx = i - found = True - if not found: - raise AssertionError("Failed to find a destroyed segment.") - - cellData.segments[segment.idx].destroyed = False - cellData.numDestroyedSegments -= 1 + if cellData._numDestroyedSegments > 0: + segment = next(s for s in cellData._segments if s._destroyed) + segment._destroyed = False + cellData._numDestroyedSegments -= 1 else: - segment.idx = len(cellData.segments) - cellData.segments.append(SegmentData(self._nextFlatIdx)) + idx = len(cellData._segments) + segment = Segment(cell, idx, self._nextFlatIdx) + cellData._segments.append(segment) self._segmentForFlatIdx.append(segment) self._nextFlatIdx += 1 - segmentData = cellData.segments[segment.idx] - segmentData.lastUsedIteration = self._iteration - segment.data = segmentData + segment._lastUsedIteration = self._iteration self._numSegments += 1 return segment @@ -350,32 +316,16 @@ def destroySegment(self, segment): @param segment (Object) Segment object representing the segment to be destroyed """ - segmentData = segment.data - if not segmentData.destroyed: - for i in xrange(len(segmentData.synapses)): - synapse = Synapse(i, segment, segmentData.synapses[i]) - synapseData = synapse.data - - if not synapseData.destroyed: - cell = synapseData.presynapticCell - presynapticSynapses = self._synapsesForPresynapticCell[cell] - - for i in xrange(len(presynapticSynapses)): - if presynapticSynapses[i] == synapse: - del presynapticSynapses[i] - - if len(presynapticSynapses) == 0: - del self._synapsesForPresynapticCell[cell] - self._numSynapses -= 1 - break + assert not segment._destroyed - segmentData.synapses = [] - self._synapsesForSegment[segmentData.flatIdx] = [] - segmentData.numDestroyedSynapses = 0 - segmentData.destroyed = True - self._cells[segment.cell].numDestroyedSegments += 1 - self._numSegments -= 1 + for synapse in self.synapsesForSegment(segment): + self.destroySynapse(synapse) + segment._synapses = [] + segment._numDestroyedSynapses = 0 + segment._destroyed = True + self._numSegments -= 1 + self._cells[segment.cell]._numDestroyedSegments += 1 def createSynapse(self, segment, presynapticCell, permanence): @@ -391,37 +341,21 @@ def createSynapse(self, segment, presynapticCell, permanence): while self.numSynapses(segment) >= self.maxSynapsesPerSegment: self.destroySynapse(self._minPermanenceSynapse(segment)) - segmentData = segment.data - synapseIdx = -1 - found = False - if segmentData.numDestroyedSynapses > 0: - for i in xrange(len(segmentData.synapses)): - if segmentData.synapses[i].destroyed: - synapseIdx = i - found = True - break + if segment._numDestroyedSynapses > 0: + synapse = next(s for s in segment._synapses if s._destroyed) - if not found: - raise AssertionError("Failed to find a destroyed synapse.") + synapse._destroyed = False + segment._numDestroyedSynapses -= 1 - synapseData = segmentData.synapses[synapseIdx] - synapseData.destroyed = False - segmentData.numDestroyedSynapses -= 1 - - synapseData.presynapticCell = presynapticCell - synapseData.permanence = permanence - self._synapsesForSegment[segmentData.flatIdx][synapseIdx].data =\ - synapseData + synapse.presynapticCell = presynapticCell + synapse.permanence = permanence else: - synapseIdx = len(segmentData.synapses) - synapseData = SynapseData(presynapticCell, permanence) - segmentData.synapses.append(synapseData) + idx = len(segment._synapses) + synapse = Synapse(segment, idx, presynapticCell, permanence) + segment._synapses.append(synapse) - synapse = Synapse(synapseIdx, segment, synapseData) self._synapsesForPresynapticCell[presynapticCell].append(synapse) - if not found: - self._synapsesForSegment[segmentData.flatIdx].append(synapse) self._numSynapses += 1 return synapse @@ -432,38 +366,37 @@ def destroySynapse(self, synapse): @param synapse (Object) Synapse object to destroy """ - synapseData = synapse.data - if not synapseData.destroyed: - presynapticSynapses = \ - self._synapsesForPresynapticCell[synapseData.presynapticCell] + assert not synapse._destroyed + + synapse._destroyed = True + synapse.segment._numDestroyedSynapses += 1 + self._numSynapses -= 1 - for i in xrange(len(presynapticSynapses)): - if presynapticSynapses[i] == synapse: - del presynapticSynapses[i] + presynapticSynapses = \ + self._synapsesForPresynapticCell[synapse.presynapticCell] - if len(presynapticSynapses) == 0: - del self._synapsesForPresynapticCell[synapseData.presynapticCell] + i = next(i + for i, syn in enumerate(presynapticSynapses) + if syn is synapse) + del presynapticSynapses[i] - synapseData.destroyed = True - synapse.segment.data.numDestroyedSynapses += 1 - self._numSynapses -= 1 - break + if len(presynapticSynapses) == 0: + del self._synapsesForPresynapticCell[synapse.presynapticCell] def updateSynapsePermanence(self, synapse, permanence): """ Updates the permanence for a synapse. - @param synapse (Object) Synapse object to be updated @param permanence (float) New permanence """ - synapse.data.permanence = permanence + synapse.permanence = permanence def computeActivity(self, activePresynapticCells, connectedPermanence): """ Compute each segment's number of active synapses for a given input. In the returned lists, a segment's active synapse count is stored at index - `segment.data.flatIdx`. + `segment.flatIdx`. @param activePresynapticCells (iter) active cells @param connectedPermanence (float) permanence threshold for a synapse @@ -481,11 +414,9 @@ def computeActivity(self, activePresynapticCells, connectedPermanence): for cell in activePresynapticCells: for synapse in self._synapsesForPresynapticCell[cell]: - synapseData = synapse.data - segment = synapse.segment - flatIdx = segment.data.flatIdx + flatIdx = synapse.segment.flatIdx numActivePotentialSynapsesForSegment[flatIdx] += 1 - if synapseData.permanence > threshold: + if synapse.permanence > threshold: numActiveConnectedSynapsesForSegment[flatIdx] += 1 return (numActiveConnectedSynapsesForSegment, @@ -498,7 +429,7 @@ def recordSegmentActivity(self, segment): @param segment The segment that had some activity. """ - segment.data.lastUsedIteration = self._iteration + segment._lastUsedIteration = self._iteration def startNewIteration(self): @@ -518,7 +449,7 @@ def numSegments(self, cell=None): """ if cell is not None: cellData = self._cells[cell] - return len(cellData.segments) - cellData.numDestroyedSegments + return len(cellData._segments) - cellData._numDestroyedSegments return self._numSegments @@ -533,8 +464,7 @@ def numSynapses(self, segment=None): specified, or on a specified segment """ if segment is not None: - segmentData = self._cells[segment.cell].segments[segment.idx] - return len(segmentData.synapses) - segmentData.numDestroyedSynapses + return len(segment._synapses) - segment._numDestroyedSynapses return self._numSynapses @@ -546,26 +476,25 @@ def write(self, proto): protoCells = proto.init('cells', self.numCells) for i in xrange(self.numCells): - segments = self._cells[i].segments + segments = self._cells[i]._segments protoSegments = protoCells[i].init('segments', len(segments)) for j in xrange(len(segments)): - synapses = segments[j].synapses + synapses = segments[j]._synapses protoSynapses = protoSegments[j].init('synapses', len(synapses)) - protoSegments[j].destroyed = segments[j].destroyed - protoSegments[j].lastUsedIteration = segments[j].lastUsedIteration + protoSegments[j].destroyed = segments[j]._destroyed + protoSegments[j].lastUsedIteration = segments[j]._lastUsedIteration for k in xrange(len(synapses)): protoSynapses[k].presynapticCell = synapses[k].presynapticCell protoSynapses[k].permanence = synapses[k].permanence - protoSynapses[k].destroyed = synapses[k].destroyed + protoSynapses[k].destroyed = synapses[k]._destroyed proto.maxSegmentsPerCell = self.maxSegmentsPerCell proto.maxSynapsesPerSegment = self.maxSynapsesPerSegment proto.iteration = self._iteration - @classmethod def read(cls, proto): """ Reads deserialized data from proto object @@ -580,44 +509,40 @@ def read(cls, proto): proto.maxSegmentsPerCell, proto.maxSynapsesPerSegment) - for i in xrange(len(protoCells)): - protoCell = protoCells[i] + for cellIdx, protoCell in enumerate(protoCells): + protoCell = protoCells[cellIdx] protoSegments = protoCell.segments - connections._cells[i] = CellData() - segments = connections._cells[i].segments + connections._cells[cellIdx] = CellData() + segments = connections._cells[cellIdx]._segments - for j in xrange(len(protoSegments)): - segmentData = SegmentData(connections._nextFlatIdx) - segmentData.destroyed = protoSegments[j].destroyed - segmentData.lastUsedIteration = protoSegments[j].lastUsedIteration - connections._nextFlatIdx += 1 - segments.append(segmentData) + for segmentIdx, protoSegment in enumerate(protoSegments): + segment = Segment(cellIdx, segmentIdx, connections._nextFlatIdx) + segment._destroyed = protoSegment.destroyed + segment._lastUsedIteration = protoSegment.lastUsedIteration - segment = Segment(i, j, segmentData) + segments.append(segment) connections._segmentForFlatIdx.append(segment) + connections._nextFlatIdx += 1 - protoSynapses = protoSegments[j].synapses - synapses = segments[j].synapses - - for k in xrange(len(protoSynapses)): - presynapticCell = protoSynapses[k].presynapticCell - synapseData = SynapseData(presynapticCell, - protoSynapses[k].permanence) - synapseData.destroyed = protoSynapses[k].destroyed - synapses.append(synapseData) + synapses = segment._synapses + protoSynapses = protoSegment.synapses - synapse = Synapse(k, segment, synapseData) + for synapseIdx, protoSynapse in enumerate(protoSynapses): + presynapticCell = protoSynapse.presynapticCell + synapse = Synapse(segment, synapseIdx, presynapticCell, + protoSynapse.permanence) + synapse._destroyed = protoSynapse.destroyed + synapses.append(synapse) connections._synapsesForPresynapticCell[presynapticCell].append( synapse) - connections._synapsesForSegment[segmentData.flatIdx].append(synapse) - if synapseData.destroyed: - segments[j].numDestroyedSynapses += 1 + if synapse._destroyed: + segment._numDestroyedSynapses += 1 else: connections._numSynapses += 1 - if segmentData.destroyed: - connections._cells[i].numDestroyedSegments += 1 + if segment._destroyed: + connections._cells[cellIdx]._numDestroyedSegments += 1 else: connections._numSegments += 1 @@ -639,8 +564,8 @@ def __eq__(self, other): return False for i in xrange(self.numCells): - segments = self._cells[i].segments - otherSegments = other._cells[i].segments + segments = self._cells[i]._segments + otherSegments = other._cells[i]._segments if len(segments) != len(otherSegments): return False @@ -648,12 +573,12 @@ def __eq__(self, other): for j in xrange(len(segments)): segment = segments[j] otherSegment = otherSegments[j] - synapses = segment.synapses - otherSynapses = otherSegment.synapses + synapses = segment._synapses + otherSynapses = otherSegment._synapses - if segment.destroyed != otherSegment.destroyed: + if segment._destroyed != otherSegment._destroyed: return False - if segment.lastUsedIteration != otherSegment.lastUsedIteration: + if segment._lastUsedIteration != otherSegment._lastUsedIteration: return False if len(synapses) != len(otherSynapses): return False @@ -666,7 +591,7 @@ def __eq__(self, other): return False if (synapse.permanence - otherSynapse.permanence) > EPSILON : return False - if synapse.destroyed != otherSynapse.destroyed: + if synapse._destroyed != otherSynapse._destroyed: return False if (len(self._synapsesForPresynapticCell) != @@ -705,7 +630,6 @@ def __eq__(self, other): return True - def __ne__(self, other): """ Non-equality operator for Connections instances. Checks if two instances are not functionally identical diff --git a/src/nupic/research/temporal_memory.py b/src/nupic/research/temporal_memory.py index 6d7cd93043..f7454220f5 100644 --- a/src/nupic/research/temporal_memory.py +++ b/src/nupic/research/temporal_memory.py @@ -97,7 +97,13 @@ def __init__(self, Amount by which segments are punished for incorrect predictions. @param seed (int) - Seed for the random number generator + Seed for the random number generator. + + @param maxSegmentsPerCell + The maximum number of segments per cell. + + @param maxSynapsesPerSegment + The maximum number of synapses per segment. Notes: @@ -237,8 +243,8 @@ def activateCells(self, activeColumns, learn=True): if learn: TemporalMemory.punishPredictedColumn(self.connections, matchingSegmentsOnCol, - self.predictedSegmentDecrement, - prevActiveCells) + prevActiveCells, + self.predictedSegmentDecrement) def activateDendrites(self, learn=True): @@ -363,7 +369,7 @@ def activatePredictedColumn(connections, random, columnActiveSegments, TemporalMemory.adaptSegment(connections, segment, prevActiveCells, permanenceIncrement, permanenceDecrement) - active = numActivePotentialSynapsesForSegment[segment.data.flatIdx] + active = numActivePotentialSynapsesForSegment[segment.flatIdx] nGrowDesired = maxNewSynapseCount - active if nGrowDesired > 0: @@ -446,7 +452,7 @@ def burstColumn(connections, random, column, columnMatchingSegments, cells = xrange(start, start + cellsPerColumn) if columnMatchingSegments is not None: - numActive = lambda s: numActivePotentialSynapsesForSegment[s.data.flatIdx] + numActive = lambda s: numActivePotentialSynapsesForSegment[s.flatIdx] bestMatchingSegment = max(columnMatchingSegments, key=numActive) winnerCell = bestMatchingSegment.cell @@ -476,7 +482,7 @@ def burstColumn(connections, random, column, columnMatchingSegments, @staticmethod def punishPredictedColumn(connections, columnMatchingSegments, - predictedSegmentDecrement, prevActiveCells): + prevActiveCells, predictedSegmentDecrement): """Punishes the Segments that incorrectly predicted a column to be active. @param connections (Object) @@ -485,12 +491,12 @@ def punishPredictedColumn(connections, columnMatchingSegments, @param columnMatchingSegments (iter) Matching segments for this column. - @param predictedSegmentDecrement (float) - Amount by which segments are punished for incorrect predictions. - @param prevActiveCells (list) Active cells in `t-1`. + @param predictedSegmentDecrement (float) + Amount by which segments are punished for incorrect predictions. + Pseudocode: for each matching segment in the column weaken active synapses @@ -525,7 +531,7 @@ def leastUsedCell(random, cells, connections): leastUsedCells = [] minNumSegments = float("inf") for cell in cells: - numSegments = len(connections.segmentsForCell(cell)) + numSegments = connections.numSegments(cell) if numSegments < minNumSegments: minNumSegments = numSegments @@ -561,9 +567,8 @@ def growSynapses(connections, random, segment, nDesiredNewSynapes, eligibleEnd = len(candidates) - 1 for synapse in connections.synapsesForSegment(segment): - presynapticCell = connections.dataForSynapse(synapse).presynapticCell try: - index = candidates[:eligibleEnd + 1].index(presynapticCell) + index = candidates[:eligibleEnd + 1].index(synapse.presynapticCell) except ValueError: index = -1 if index != -1: @@ -595,10 +600,9 @@ def adaptSegment(connections, segment, prevActiveCells, permanenceIncrement, """ for synapse in connections.synapsesForSegment(segment): - synapseData = connections.dataForSynapse(synapse) - permanence = synapseData.permanence + permanence = synapse.permanence - if binSearch(prevActiveCells, synapseData.presynapticCell) != -1: + if binSearch(prevActiveCells, synapse.presynapticCell) != -1: permanence += permanenceIncrement else: permanence -= permanenceDecrement @@ -875,7 +879,7 @@ def write(self, proto): activeSegmentOverlaps[i].cell = segment.cell activeSegmentOverlaps[i].segment = segment.idx activeSegmentOverlaps[i].overlap = ( - self.numActiveConnectedSynapsesForSegment[segment.data.flatIdx] + self.numActiveConnectedSynapsesForSegment[segment.flatIdx] ) matchingSegmentOverlaps = \ @@ -884,7 +888,7 @@ def write(self, proto): matchingSegmentOverlaps[i].cell = segment.cell matchingSegmentOverlaps[i].segment = segment.idx matchingSegmentOverlaps[i].overlap = ( - self.numActivePotentialSynapsesForSegment[segment.data.flatIdx] + self.numActivePotentialSynapsesForSegment[segment.flatIdx] ) @@ -934,7 +938,7 @@ def read(cls, proto): tm.activeSegments.append(segment) overlap = protoSegmentOverlap.overlap - tm.numActiveConnectedSynapsesForSegment[segment.data.flatIdx] = overlap + tm.numActiveConnectedSynapsesForSegment[segment.flatIdx] = overlap for i in xrange(len(proto.matchingSegmentOverlaps)): protoSegmentOverlap = proto.matchingSegmentOverlaps[i] @@ -944,7 +948,7 @@ def read(cls, proto): tm.matchingSegments.append(segment) overlap = protoSegmentOverlap.overlap - tm.numActivePotentialSynapsesForSegment[segment.data.flatIdx] = overlap + tm.numActivePotentialSynapsesForSegment[segment.flatIdx] = overlap return tm diff --git a/tests/unit/nupic/research/connections_test.py b/tests/unit/nupic/research/connections_test.py index 2589cb82a0..2e4a1cf063 100755 --- a/tests/unit/nupic/research/connections_test.py +++ b/tests/unit/nupic/research/connections_test.py @@ -45,7 +45,8 @@ def testCreateSegment(self): self.assertEqual(segment2.idx, 1) self.assertEqual(segment2.cell, 10) - self.assertEqual(connections.segmentsForCell(10), [segment1, segment2]) + self.assertEqual([segment1, segment2], + list(connections.segmentsForCell(10))) def testCreateSegmentReuse(self): @@ -81,7 +82,7 @@ def testSynapseReuse(self): synapse1 = connections.createSynapse(segment, 50, .34) synapse2 = connections.createSynapse(segment, 51, .34) - synapses = connections.synapsesForSegment(segment) + synapses = list(connections.synapsesForSegment(segment)) self.assertEqual(synapses, [synapse1, synapse2]) #Add an additional synapse to force it over the limit of num synapses @@ -90,7 +91,7 @@ def testSynapseReuse(self): self.assertEqual(0, synapse3.idx) #ensure lower permanence synapse was removed - synapses = connections.synapsesForSegment(segment) + synapses = list(connections.synapsesForSegment(segment)) self.assertEqual(synapses, [synapse3, synapse2]) @@ -123,8 +124,8 @@ def testDestroySegment(self): (numActiveConnected, numActivePotential) = connections.computeActivity([80, 81, 82], 0.5) - self.assertEqual(0, numActiveConnected[segment2.data.flatIdx]) - self.assertEqual(0, numActivePotential[segment2.data.flatIdx]) + self.assertEqual(0, numActiveConnected[segment2.flatIdx]) + self.assertEqual(0, numActivePotential[segment2.flatIdx]) def testDestroySynapse(self): @@ -143,13 +144,13 @@ def testDestroySynapse(self): connections.destroySynapse(synapse2) self.assertEqual(2, connections.numSynapses()) - self.assertEqual(connections.synapsesForSegment(segment), [synapse1, - synapse3]) + self.assertEqual([synapse1, synapse3], + list(connections.synapsesForSegment(segment))) (numActiveConnected, numActivePotential) = connections.computeActivity([80, 81, 82], .5) - self.assertEqual(1, numActiveConnected[segment.data.flatIdx]) - self.assertEqual(2, numActivePotential[segment.data.flatIdx]) + self.assertEqual(1, numActiveConnected[segment.flatIdx]) + self.assertEqual(2, numActivePotential[segment.flatIdx]) def testPathsNotInvalidatedByOtherDestroys(self): @@ -170,19 +171,19 @@ def testPathsNotInvalidatedByOtherDestroys(self): synapse4 = connections.createSynapse(segment3, 204, .85) synapse5 = connections.createSynapse(segment3, 205, .85) - self.assertEqual(203, connections.dataForSynapse(synapse3).presynapticCell) + self.assertEqual(203, synapse3.presynapticCell) connections.destroySynapse(synapse1) - self.assertEqual(203, connections.dataForSynapse(synapse3).presynapticCell) + self.assertEqual(203, synapse3.presynapticCell) connections.destroySynapse(synapse5) - self.assertEqual(203, connections.dataForSynapse(synapse3).presynapticCell) + self.assertEqual(203, synapse3.presynapticCell) connections.destroySegment(segment1) - self.assertEqual(connections.synapsesForSegment(segment3), - [synapse2, synapse3, synapse4]) + self.assertEqual([synapse2, synapse3, synapse4], + list(connections.synapsesForSegment(segment3))) connections.destroySegment(segment5) - self.assertEqual(connections.synapsesForSegment(segment3), - [synapse2, synapse3, synapse4]) - self.assertEqual(203, connections.dataForSynapse(synapse3).presynapticCell) + self.assertEqual([synapse2, synapse3, synapse4], + list(connections.synapsesForSegment(segment3))) + self.assertEqual(203, synapse3.presynapticCell) def testDestroySegmentWithDestroyedSynapses(self): @@ -232,7 +233,7 @@ def testReuseSegmentWithDestroyedSynapses(self): reincarnated = connections.createSegment(11) self.assertEqual(0, connections.numSynapses(reincarnated)) - self.assertEqual(0, len(connections.synapsesForSegment(reincarnated))) + self.assertEqual(0, len(list(connections.synapsesForSegment(reincarnated)))) def testDestroySegmentsThenReachLimit(self): @@ -344,11 +345,11 @@ def testComputeActivity(self): (numActiveConnected, numActivePotential) = connections.computeActivity(inputVec, .5) - self.assertEqual(1, numActiveConnected[segment1a.data.flatIdx]) - self.assertEqual(2, numActivePotential[segment1a.data.flatIdx]) + self.assertEqual(1, numActiveConnected[segment1a.flatIdx]) + self.assertEqual(2, numActivePotential[segment1a.flatIdx]) - self.assertEqual(2, numActiveConnected[segment2a.data.flatIdx]) - self.assertEqual(3, numActivePotential[segment2a.data.flatIdx]) + self.assertEqual(2, numActiveConnected[segment2a.flatIdx]) + self.assertEqual(3, numActivePotential[segment2a.flatIdx]) @unittest.skipUnless( diff --git a/tests/unit/nupic/research/temporal_memory_test.py b/tests/unit/nupic/research/temporal_memory_test.py index 4f32294bee..7210a2fb5c 100755 --- a/tests/unit/nupic/research/temporal_memory_test.py +++ b/tests/unit/nupic/research/temporal_memory_test.py @@ -397,9 +397,9 @@ def testNewSegmentAddSynapsesToSubsetOfWinnerCells(self): winnerCells = tm.getWinnerCells() #[18] self.assertEqual(1, len(winnerCells)) - segments = tm.connections.segmentsForCell(winnerCells[0]) + segments = list(tm.connections.segmentsForCell(winnerCells[0])) self.assertEqual(1, len(segments)) - synapses = tm.connections.synapsesForSegment(segments[0]) + synapses = list(tm.connections.synapsesForSegment(segments[0])) self.assertEqual(2, len(synapses)) for synapse in synapses: @@ -435,7 +435,7 @@ def testNewSegmentAddSynapsesToAllWinnerCells(self): self.assertEqual(1, len(winnerCells)) segments = list(tm.connections.segmentsForCell(winnerCells[0])) self.assertEqual(1, len(segments)) - synapses = tm.connections.synapsesForSegment(segments[0]) + synapses = list(tm.connections.synapsesForSegment(segments[0])) self.assertEqual(3, len(synapses)) presynapticCells = [] @@ -473,7 +473,7 @@ def testMatchingSegmentAddSynapsesToSubsetOfWinnerCells(self): self.assertEqual(prevWinnerCells, tm.getWinnerCells()) tm.compute(activeColumns, True) - synapses = tm.connections.synapsesForSegment(matchingSegment) + synapses = list(tm.connections.synapsesForSegment(matchingSegment)) self.assertEqual(3, len(synapses)) synapses = synapses[1:] # only test the synapses added by compute @@ -511,7 +511,7 @@ def testMatchingSegmentAddSynapsesToAllWinnerCells(self): tm.compute(activeColumns) - synapses = tm.connections.synapsesForSegment(matchingSegment) + synapses = list(tm.connections.synapsesForSegment(matchingSegment)) self.assertEqual(2, len(synapses)) synapseData = tm.connections.dataForSynapse(synapses[1]) @@ -553,7 +553,7 @@ def testActiveSegmentGrowSynapsesAccordingToPotentialOverlap(self): self.assertEqual(prevWinnerCells, tm.getWinnerCells()) tm.compute(activeColumns, True) - synapses = tm.connections.synapsesForSegment(activeSegment) + synapses = list(tm.connections.synapsesForSegment(activeSegment)) self.assertEqual(4, len(synapses)) synapse = synapses[3]; @@ -593,7 +593,7 @@ def testDestroyWeakSynapseOnWrongPrediction(self): tm.compute(previousActiveColumns, True) tm.compute(activeColumns, True) - self.assertTrue(tm.connections.dataForSynapse(weakActiveSynapse).destroyed) + self.assertTrue(weakActiveSynapse._destroyed) def testDestroyWeakSynapseOnActiveReinforce(self): @@ -626,7 +626,7 @@ def testDestroyWeakSynapseOnActiveReinforce(self): tm.compute(previousActiveColumns, True) tm.compute(activeColumns, True) - self.assertTrue(tm.connections.dataForSynapse(weakInactSynapse).destroyed) + self.assertTrue(weakInactSynapse._destroyed) def testRecycleWeakestSynapseToMakeRoomForNewSynapse(self): @@ -660,7 +660,7 @@ def testRecycleWeakestSynapseToMakeRoomForNewSynapse(self): synapseData = tm.connections.dataForSynapse(weakestSynapse) self.assertNotEqual(0, synapseData.presynapticCell) - self.assertFalse(synapseData.destroyed) + self.assertFalse(synapseData._destroyed) self.assertAlmostEqual(.21, synapseData.permanence) @@ -688,26 +688,25 @@ def testRecycleLeastRecentlyActiveSegmentToMakeRoomForNewSegment(self): tm.compute(prevActiveColumns1) tm.compute(activeColumns) - self.assertEqual(1, len(tm.connections.segmentsForCell(9))) - oldestSegment = tm.connections.segmentsForCell(9)[0] + self.assertEqual(1, tm.connections.numSegments(9)) + oldestSegment = list(tm.connections.segmentsForCell(9))[0] tm.reset() tm.compute(prevActiveColumns2) tm.compute(activeColumns) - self.assertEqual(2, len(tm.connections.segmentsForCell(9))) + self.assertEqual(2, tm.connections.numSegments(9)) tm.reset() tm.compute(prevActiveColumns3) tm.compute(activeColumns) - self.assertEqual(2, len(tm.connections.segmentsForCell(9))) + self.assertEqual(2, tm.connections.numSegments(9)) - synapses = tm.connections.synapsesForSegment(oldestSegment) - self.assertEqual(3, len(synapses)) - presynapticCells = set() + self.assertEqual(3, tm.connections.numSynapses(oldestSegment)) - for synapseData in tm.connections.dataForSegment(oldestSegment).synapses: - presynapticCells.add(synapseData.presynapticCell) + presynapticCells = \ + set(synapse.presynapticCell + for synapse in tm.connections.synapsesForSegment(oldestSegment)) expected = set([6,7,8]) self.assertEqual(expected, presynapticCells) @@ -742,8 +741,8 @@ def testDestroySegmentsWithTooFewSynapsesToBeMatching(self): tm.compute(activeColumns, True) - self.assertTrue(tm.connections.dataForSegment(matchingSegment)) - self.assertEqual(0, len(tm.connections.segmentsForCell(expectedActiveCell))) + self.assertTrue(matchingSegment._destroyed) + self.assertEqual(0, tm.connections.numSegments(expectedActiveCell)) def testPunishMatchingSegmentsInInactiveColumns(self): @@ -829,14 +828,14 @@ def testAddSegmentToCellWithFewestSegments(self): self.assertEqual(activeCells, tm.getActiveCells()) self.assertEqual(3, tm.connections.numSegments()) - self.assertEqual(1, len(tm.connections.segmentsForCell(0))) - self.assertEqual(1, len(tm.connections.segmentsForCell(3))) - self.assertEqual(1, len(tm.connections.synapsesForSegment(segment1))) - self.assertEqual(1, len(tm.connections.synapsesForSegment(segment2))) + self.assertEqual(1, tm.connections.numSegments(0)) + self.assertEqual(1, tm.connections.numSegments(3)) + self.assertEqual(1, tm.connections.numSynapses(segment1)) + self.assertEqual(1, tm.connections.numSynapses(segment2)) - segments = tm.connections.segmentsForCell(1) + segments = list(tm.connections.segmentsForCell(1)) if len(segments) == 0: - segments2 = tm.connections.segmentsForCell(2) + segments2 = list(tm.connections.segmentsForCell(2)) self.assertFalse(len(segments2) == 0) grewOnCell2 = True segments.append(segments2[0]) @@ -844,7 +843,7 @@ def testAddSegmentToCellWithFewestSegments(self): grewOnCell1 = True self.assertEqual(1, len(segments)) - synapses = tm.connections.synapsesForSegment(segments[0]) + synapses = list(tm.connections.synapsesForSegment(segments[0])) self.assertEqual(4, len(synapses)) columnChecklist = set(prevActiveColumns)