Skip to content

Commit b1f35fe

Browse files
authored
Merge pull request #3654 from mrcslws/connections-is-a-data-structure
Move segment/synapse cleanup out of Connections
2 parents 778788d + 4f370b0 commit b1f35fe

8 files changed

Lines changed: 324 additions & 352 deletions

File tree

requirements.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ coverage==3.7.1
44
mock==1.0.1
55
ordereddict==1.1
66
psutil==1.0.1
7-
pytest==2.5.1
8-
pytest-cov==1.6
9-
pytest-xdist==1.8
7+
pytest==3.0.7
8+
pytest-cov==2.5.0
9+
pytest-xdist==1.16.0
1010
python-dateutil==2.1
1111
PyYAML==3.10
1212
unittest2==0.5.1
@@ -18,5 +18,5 @@ prettytable==0.7.2
1818

1919
# When updating nupic.bindings, also update any shared dependencies to keep
2020
# versions in sync.
21-
nupic.bindings==0.6.1
22-
numpy==1.11.2
21+
nupic.bindings==0.6.3
22+
numpy==1.12.1

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def findRequirements():
149149
extras_require = {
150150
# Default requirement based on system type
151151
":platform_system=='Linux' or platform_system=='Darwin'":
152-
["pycapnp==0.5.8"],
152+
["pycapnp==0.5.12"],
153153

154154
# Superseded by platform_system-conditional requirement, but keeping
155155
# empty extra for compatibility as recommended by setuptools doc.

src/nupic/algorithms/connections.py

Lines changed: 5 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030
class Segment(object):
3131
""" Class containing minimal information to identify a unique segment """
3232

33-
__slots__ = ["cell", "flatIdx", "_synapses", "_lastUsedIteration", "_ordinal"]
33+
__slots__ = ["cell", "flatIdx", "_synapses", "_ordinal"]
3434

35-
def __init__(self, cell, flatIdx, lastUsedIteration, ordinal):
35+
def __init__(self, cell, flatIdx, ordinal):
3636
"""
3737
@param cell (int)
3838
Index of the cell that this segment is on.
@@ -48,7 +48,6 @@ def __init__(self, cell, flatIdx, lastUsedIteration, ordinal):
4848
self.cell = cell
4949
self.flatIdx = flatIdx
5050
self._synapses = set()
51-
self._lastUsedIteration = lastUsedIteration
5251
self._ordinal = ordinal
5352

5453

@@ -60,7 +59,6 @@ def __eq__(self, other):
6059
"""
6160

6261
return (self.cell == other.cell and
63-
self._lastUsedIteration == other._lastUsedIteration and
6462
(sorted(self._synapses, key=lambda x: x._ordinal) ==
6563
sorted(other._synapses, key=lambda x: x._ordinal)))
6664

@@ -134,18 +132,11 @@ class Connections(object):
134132
""" Class to hold data representing the connectivity of a
135133
collection of cells. """
136134

137-
def __init__(self,
138-
numCells,
139-
maxSegmentsPerCell=255,
140-
maxSynapsesPerSegment=255):
135+
def __init__(self, numCells):
141136
""" @param numCells (int) Number of cells in collection """
142137

143138
# Save member variables
144139
self.numCells = numCells
145-
assert maxSegmentsPerCell > 0
146-
assert maxSynapsesPerSegment > 0
147-
self.maxSegmentsPerCell = maxSegmentsPerCell
148-
self.maxSynapsesPerSegment = maxSynapsesPerSegment
149140

150141
self._cells = [CellData() for _ in xrange(numCells)]
151142
self._synapsesForPresynapticCell = defaultdict(set)
@@ -154,7 +145,6 @@ def __init__(self,
154145
self._numSynapses = 0
155146
self._freeFlatIdxs = []
156147
self._nextFlatIdx = 0
157-
self._iteration = 0
158148

159149
# Whenever creating a new Synapse or Segment, give it a unique ordinal.
160150
# These can be used to sort synapses or segments by age.
@@ -226,57 +216,6 @@ def getSegment(self, cell, idx):
226216
return self._cells[cell]._segments[idx]
227217

228218

229-
def _leastRecentlyUsedSegment(self, cell):
230-
""" Find this cell's segment that was least recently used.
231-
232-
Implement this explicitly to make sure that tie-breaking is consistent.
233-
When there's a tie, choose the oldest segment.
234-
235-
@param cell (int) Cell to query.
236-
237-
@return (Object) Least recently used segment.
238-
239-
"""
240-
minSegment = None
241-
minIteration = float("inf")
242-
243-
for segment in self.segmentsForCell(cell):
244-
if segment._lastUsedIteration < minIteration:
245-
minSegment = segment
246-
minIteration = segment._lastUsedIteration
247-
248-
assert minSegment is not None
249-
250-
return minSegment
251-
252-
253-
def _minPermanenceSynapse(self, segment):
254-
""" Find this segment's synapse with the smallest permanence.
255-
256-
This method is NOT equivalent to a simple min() call. It uses an EPSILON to
257-
account for floating point differences between C++ and Python.
258-
259-
@param segment (Object) Segment to query.
260-
261-
@return (Object) Synapse with the minimal permanence
262-
263-
Note: On ties it will choose the first occurrence of the minimum permanence.
264-
265-
"""
266-
minSynapse = None
267-
minPermanence = float("inf")
268-
269-
for synapse in sorted(self.synapsesForSegment(segment),
270-
key=lambda s: s._ordinal):
271-
if synapse.permanence < minPermanence - EPSILON:
272-
minSynapse = synapse
273-
minPermanence = synapse.permanence
274-
275-
assert minSynapse is not None
276-
277-
return minSynapse
278-
279-
280219
def segmentForFlatIdx(self, flatIdx):
281220
""" Get the segment with the specified flatIdx.
282221
@@ -313,9 +252,6 @@ def createSegment(self, cell):
313252
314253
@return (int) New segment index
315254
"""
316-
while self.numSegments(cell) >= self.maxSegmentsPerCell:
317-
self.destroySegment(self._leastRecentlyUsedSegment(cell))
318-
319255
cellData = self._cells[cell]
320256

321257
if len(self._freeFlatIdxs) > 0:
@@ -328,7 +264,7 @@ def createSegment(self, cell):
328264
ordinal = self._nextSegmentOrdinal
329265
self._nextSegmentOrdinal += 1
330266

331-
segment = Segment(cell, flatIdx, self._iteration, ordinal)
267+
segment = Segment(cell, flatIdx, ordinal)
332268
cellData._segments.append(segment)
333269
self._segmentForFlatIdx[flatIdx] = segment
334270

@@ -366,10 +302,6 @@ def createSynapse(self, segment, presynapticCell, permanence):
366302
367303
@return (Object) created Synapse object
368304
"""
369-
370-
while self.numSynapses(segment) >= self.maxSynapsesPerSegment:
371-
self.destroySynapse(self._minPermanenceSynapse(segment))
372-
373305
idx = len(segment._synapses)
374306
synapse = Synapse(segment, presynapticCell, permanence,
375307
self._nextSynapseOrdinal)
@@ -444,22 +376,6 @@ def computeActivity(self, activePresynapticCells, connectedPermanence):
444376
numActivePotentialSynapsesForSegment)
445377

446378

447-
def recordSegmentActivity(self, segment):
448-
""" Record the fact that a segment had some activity. This information is
449-
used during segment cleanup.
450-
451-
@param segment The segment that had some activity.
452-
"""
453-
segment._lastUsedIteration = self._iteration
454-
455-
456-
def startNewIteration(self):
457-
""" Mark the passage of time. This information is used during segment
458-
cleanup.
459-
"""
460-
self._iteration += 1
461-
462-
463379
def numSegments(self, cell=None):
464380
""" Returns the number of segments.
465381
@@ -515,17 +431,10 @@ def write(self, proto):
515431
for j, segment in enumerate(segments):
516432
synapses = segment._synapses
517433
protoSynapses = protoSegments[j].init('synapses', len(synapses))
518-
protoSegments[j].destroyed = False
519-
protoSegments[j].lastUsedIteration = segment._lastUsedIteration
520434

521435
for k, synapse in enumerate(sorted(synapses, key=lambda s: s._ordinal)):
522436
protoSynapses[k].presynapticCell = synapse.presynapticCell
523437
protoSynapses[k].permanence = synapse.permanence
524-
protoSynapses[k].destroyed = False
525-
526-
proto.maxSegmentsPerCell = self.maxSegmentsPerCell
527-
proto.maxSynapsesPerSegment = self.maxSynapsesPerSegment
528-
proto.iteration = self._iteration
529438

530439

531440
@classmethod
@@ -538,9 +447,7 @@ def read(cls, proto):
538447
"""
539448
#pylint: disable=W0212
540449
protoCells = proto.cells
541-
connections = cls(len(protoCells),
542-
proto.maxSegmentsPerCell,
543-
proto.maxSynapsesPerSegment)
450+
connections = cls(len(protoCells))
544451

545452
for cellIdx, protoCell in enumerate(protoCells):
546453
protoCell = protoCells[cellIdx]
@@ -549,11 +456,7 @@ def read(cls, proto):
549456
segments = connections._cells[cellIdx]._segments
550457

551458
for segmentIdx, protoSegment in enumerate(protoSegments):
552-
if protoSegment.destroyed:
553-
continue
554-
555459
segment = Segment(cellIdx, connections._nextFlatIdx,
556-
protoSegment.lastUsedIteration,
557460
connections._nextSegmentOrdinal)
558461

559462
segments.append(segment)
@@ -565,9 +468,6 @@ def read(cls, proto):
565468
protoSynapses = protoSegment.synapses
566469

567470
for synapseIdx, protoSynapse in enumerate(protoSynapses):
568-
if protoSynapse.destroyed:
569-
continue
570-
571471
presynapticCell = protoSynapse.presynapticCell
572472
synapse = Synapse(segment, presynapticCell, protoSynapse.permanence,
573473
ordinal=connections._nextSynapseOrdinal)
@@ -577,7 +477,6 @@ def read(cls, proto):
577477

578478
connections._numSynapses += 1
579479

580-
connections._iteration = proto.iteration
581480
#pylint: enable=W0212
582481
return connections
583482

@@ -589,11 +488,6 @@ def __eq__(self, other):
589488
@param other (Connections) Connections instance to compare to
590489
"""
591490
#pylint: disable=W0212
592-
if self.maxSegmentsPerCell != other.maxSegmentsPerCell:
593-
return False
594-
if self.maxSynapsesPerSegment != other.maxSynapsesPerSegment:
595-
return False
596-
597491
for i in xrange(self.numCells):
598492
segments = self._cells[i]._segments
599493
otherSegments = other._cells[i]._segments
@@ -607,8 +501,6 @@ def __eq__(self, other):
607501
synapses = segment._synapses
608502
otherSynapses = otherSegment._synapses
609503

610-
if segment._lastUsedIteration != otherSegment._lastUsedIteration:
611-
return False
612504
if len(synapses) != len(otherSynapses):
613505
return False
614506

@@ -644,8 +536,6 @@ def __eq__(self, other):
644536

645537
if self._numSynapses != other._numSynapses:
646538
return False
647-
if self._iteration != other._iteration:
648-
return False
649539

650540
#pylint: enable=W0212
651541
return True

0 commit comments

Comments
 (0)