Skip to content
This repository has been archived by the owner on Sep 1, 2023. It is now read-only.

Python column segment walk #3197

Merged
merged 32 commits into from
Jul 18, 2016
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3908315
initial implementation
andrewmalta13 Jun 27, 2016
2e99d31
skip serialization test
andrewmalta13 Jun 28, 2016
af063d3
change to column generator
andrewmalta13 Jun 28, 2016
3b8bda5
passes unit tests, tutorial_temporal_memory, and extensive tests
andrewmalta13 Jun 28, 2016
c2fc03d
removes debugging prints and skips serialization test
andrewmalta13 Jun 28, 2016
ca9d304
removes debugging comments
andrewmalta13 Jun 28, 2016
44b6906
removes debug comments from connections
andrewmalta13 Jun 28, 2016
384b870
cleans up sloppy computeActivity
andrewmalta13 Jun 28, 2016
2efc991
Merge branch 'master' of https://github.com/numenta/nupic into python…
andrewmalta13 Jun 30, 2016
a9dff1b
addresses some implementation bugs
andrewmalta13 Jul 5, 2016
f3faf02
incorporates binary search into the algorithm where applicable
andrewmalta13 Jul 5, 2016
d7f631a
misc changes to connections
andrewmalta13 Jul 5, 2016
88d26e8
removes some unneccesary validation checks
andrewmalta13 Jul 5, 2016
29fcbb4
updates documentation and style
andrewmalta13 Jul 5, 2016
25d4e73
removes pylint warnings I introduced
andrewmalta13 Jul 5, 2016
283180b
fixes pylint warnings in temporal memory unit tests
andrewmalta13 Jul 5, 2016
87fa098
updates connections tests
andrewmalta13 Jul 5, 2016
7e9faf1
updated docstrings
andrewmalta13 Jul 6, 2016
d02c6fb
removes testing file
andrewmalta13 Jul 6, 2016
2696941
addresses some comments
andrewmalta13 Jul 7, 2016
b140f5e
addresses more comments
andrewmalta13 Jul 7, 2016
42e09fc
reverts generating cell in else change
andrewmalta13 Jul 8, 2016
4e80a26
addresses some more feedback
andrewmalta13 Jul 8, 2016
c89e2db
fixes spacing style
andrewmalta13 Jul 8, 2016
68d376b
uses arrays instead of dicts in computeActivity
andrewmalta13 Jul 8, 2016
7a443a6
updates docstrings
andrewmalta13 Jul 8, 2016
9aa84d5
addresses comments and updates style to pass pylint
andrewmalta13 Jul 11, 2016
b5cd93f
replaces segmentCMP with lambda and updates docstrings
andrewmalta13 Jul 13, 2016
6ebafaa
Merge branch 'master' of https://github.com/numenta/nupic into python…
andrewmalta13 Jul 13, 2016
010cd7a
fixes some pylint warnings
andrewmalta13 Jul 13, 2016
92cbaaa
adds pseudocode to core functions
andrewmalta13 Jul 18, 2016
f3a1a54
Merge branch 'master' of https://github.com/numenta/nupic into python…
andrewmalta13 Jul 18, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
112 changes: 80 additions & 32 deletions src/nupic/research/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
# http://numenta.org/licenses/
# ----------------------------------------------------------------------

from collections import defaultdict, namedtuple
from collections import defaultdict



Expand Down Expand Up @@ -74,6 +74,19 @@ def __init__(self,
self._nextSynapseIdx = 0


def segmentCmp(self, a, b):
"""
A simple comparison function for segments to sort them
by the cell they are on.

@param a (int) segment 1
@param b (int) segment 2

@return (int) comparison integer between the two cells
"""
return self._segments[a] - self._segments[b]


def cellForSegment(self, segment):
"""
Returns the cell that a segment belongs to.
Expand All @@ -85,6 +98,18 @@ def cellForSegment(self, segment):
return self._segments[segment]


def columnForSegment(self, segment, cellsPerColumn):
"""
Returns the column that a segment's presynapticCell belongs to

@param segment (int) Segment index
@param cellsPerColumn (int) Number of cells in a column in the tm

@return (int)
"""
return self._segments[segment] / cellsPerColumn


def segmentsForCell(self, cell):
"""
Returns the segments that belong to a cell.
Expand All @@ -109,7 +134,6 @@ def dataForSynapse(self, synapse):

@return (SynapseData) Synapse data
"""
self._validateSynapse(synapse)

return self._synapses[synapse]

Expand Down Expand Up @@ -192,7 +216,6 @@ def createSynapse(self, segment, presynapticCell, permanence):
@return (int) Synapse index
"""
self._validateSegment(segment)
self._validatePermanence(permanence)

# Add data
synapse = self._nextSynapseIdx
Expand Down Expand Up @@ -231,7 +254,6 @@ def updateSynapsePermanence(self, synapse, permanence):
@param synapse (int) Synapse index
@param permanence (float) New permanence
"""
self._validatePermanence(permanence)

data = self._synapses[synapse]
newData = SynapseData(data.segment,
Expand All @@ -243,6 +265,52 @@ def updateSynapsePermanence(self, synapse, permanence):
self._synapsesForPresynapticCell[newData.presynapticCell][synapse] = newData


def computeActivity(self, activeInput, activePermanenceThreshold,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the style guide: "Separate methods inside classes by two blank lines."

activeSynapseThreshold, matchingPermananceThreshold,
matchingSynapseThreshold):
"""
Computes active and matching segments given the current active input.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can start doc strings on the first line:
https://www.python.org/dev/peps/pep-0257/


@param activeInput (set) currently active cells
@param activePermanenceThreshold (float) permanence threshold for a synapse to be considered active
@param activeSynapseThreshold (int) number of synapses needed for a segment to be considered active
@param matchingPermananceThreshold (float) permanence threshold for a synapse to be considered matching
@param matchingSynapseThreshold (int) number of synapses needed for a segment to be considered matching

@return (tuple) Contains:
`activeSegments` (list),
`matchingSegments` (list),

Notes:
activeSegments and matchingSegments are sorted by the cell they are on.
"""

numActiveSynapsesForSegment = [0] * self._nextSegmentIdx
numMatchingSynapsesForSegment = [0] * self._nextSegmentIdx

for cell in activeInput:
for synapseData in self.synapsesForPresynapticCell(cell).values():
segment = synapseData.segment
permanence = synapseData.permanence
if permanence >= matchingPermananceThreshold:
numMatchingSynapsesForSegment[segment] += 1
if synapseData.permanence >= activePermanenceThreshold:
numActiveSynapsesForSegment[segment] += 1

activeSegments = []
matchingSegments = []
for i in xrange(self._nextSegmentIdx):
if numActiveSynapsesForSegment[i] >= activeSynapseThreshold:
activeSegments.append(i)

for i in xrange(self._nextSegmentIdx):
if numMatchingSynapsesForSegment[i] >= matchingSynapseThreshold:
matchingSegments.append(i)

return (sorted(activeSegments, cmp=self.segmentCmp),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using lambda functions is probably easier here since it's such a simple comparison and used only in these two places:

segmentCmp = lambda a, b: self._segments[a] - self._segments[b]
return (sorted(activeSegments, cmp=segmentCmp),
        sorted(activeSegments, cmp=segmentCmp))

sorted(matchingSegments, cmp=self.segmentCmp))


def numSegments(self):
"""
Returns the number of segments.
Expand Down Expand Up @@ -281,6 +349,7 @@ def write(self, proto):
protoSynapse.permanence = synapseData.permanence



@classmethod
def read(cls, proto):
"""
Expand All @@ -304,9 +373,9 @@ def read(cls, proto):

for k in xrange(len(protoSynapses)):
protoSynapse = protoSynapses[k]
synapse = connections.createSynapse(segment,
int(protoSynapse.presynapticCell),
protoSynapse.permanence)
connections.createSynapse(segment,
int(protoSynapse.presynapticCell),
protoSynapse.permanence)

return connections

Expand All @@ -331,16 +400,16 @@ def __eq__(self, other):
otherSegmentSet = set()
for segment in other.segmentsForCell(cell):
otherSynapseSet = other._synapseSetForSynapses(
other.synapsesForSegment(segment))
other.synapsesForSegment(segment))
otherSegmentSet.add(frozenset(otherSynapseSet))

if segmentSet != otherSegmentSet: return False

synapseSet = self._synapseSetForSynapses(
self.synapsesForPresynapticCell(cell))
self.synapsesForPresynapticCell(cell))

otherSynapseSet = other._synapseSetForSynapses(
other.synapsesForPresynapticCell(cell))
other.synapsesForPresynapticCell(cell))

if synapseSet != otherSynapseSet: return False

Expand Down Expand Up @@ -373,7 +442,7 @@ def _synapseSetForSynapses(self, synapses):
for synapse in synapses:
synapseData = self.dataForSynapse(synapse)
synapseSet.add((synapseData.presynapticCell,
round(synapseData.permanence, 7)))
round(synapseData.permanence, 7)))

return synapseSet

Expand All @@ -396,24 +465,3 @@ def _validateSegment(self, segment):
"""
if not segment in self._segments:
raise IndexError("Invalid segment")


def _validateSynapse(self, synapse):
"""
Raises an error if synapse index is invalid.

@param synapse (int) Synapse index
"""
if not synapse in self._synapses:
raise IndexError("Invalid synapse")


@staticmethod
def _validatePermanence(permanence):
"""
Raises an error if permanence is invalid.

@param permanence (float) Permanence
"""
if permanence < 0 or permanence > 1:
raise ValueError("Invalid permanence")