def run(self):
    """Runs a single experiment task"""
    self.__logger.debug("run(): Starting task <%s>", self.__task['taskLabel'])

    # Set up the task

    # Create our main loop-control iterator
    if self.__cmdOptions.privateOptions['testMode']:
      numIters = 10
    else:
      numIters = self.__task['iterationCount']

    if numIters >= 0:
      iterTracker = iter(xrange(numIters))
    else:
      iterTracker = iter(itertools.count())

    # Initialize periodic activities
    periodic = PeriodicActivityMgr(
      requestedActivities=self._createPeriodicActivities())

    # Reset sequence states in the model, so it starts looking for a new
    # sequence
    # TODO: should this be done in OPFTaskDriver.setup(), instead?  Is it always
    #       desired in Nupic?
    self.__model.resetSequenceStates()

    # Have Task Driver perform its initial setup activities, including setup
    # callbacks
    self.__taskDriver.setup()

    # Run it!
    while True:
      # Check controlling iterator first
      try:
        next(iterTracker)
      except StopIteration:
        break

      # Read next input record
      try:
        inputRecord = self.__datasetReader.next()
      except StopIteration:
        break

      # Process input record
      result = self.__taskDriver.handleInputRecord(inputRecord=inputRecord)

      if InferenceElement.encodings in result.inferences:
        result.inferences.pop(InferenceElement.encodings)
      self.__predictionLogger.writeRecord(result)

      # Run periodic activities
      periodic.tick()

    # Dump the experiment metrics at the end of the task
    self._getAndEmitExperimentMetrics(final=True)

    # Have Task Driver perform its final activities
    self.__taskDriver.finalize()

    # Reset sequence states in the model, so it starts looking for a new
    # sequence
    # TODO: should this be done in OPFTaskDriver.setup(), instead?  Is it always
    #       desired in Nupic?
    self.__model.resetSequenceStates()

def
run
(
self
)
:
self
.
__logger
.
debug
(
"run(): Starting task <%s>"
,
self
.
__task
[
'taskLabel'
]
)
if
self
.
__cmdOptions
.
privateOptions
[
'testMode'
]
:
numIters
=
10
else
:
numIters
=
self
.
__task
[
'iterationCount'
]
if
numIters
>=
0
:
iterTracker
=
iter
(
xrange
(
numIters
)
)
else
:
iterTracker
=
iter
(
itertools
.
count
(
)
)
periodic
=
PeriodicActivityMgr
(
requestedActivities
=
self
.
_createPeriodicActivities
(
)
)
self
.
__model
.
resetSequenceStates
(
)
self
.
__taskDriver
.
setup
(
)
while
True
:
try
:
next
(
iterTracker
)
except
StopIteration
:
break
try
:
inputRecord
=
self
.
__datasetReader
.
next
(
)
except
StopIteration
:
break
result
=
self
.
__taskDriver
.
handleInputRecord
(
inputRecord
=
inputRecord
)
if
InferenceElement
.
encodings
in
result
.
inferences
:
result
.
inferences
.
pop
(
InferenceElement
.
encodings
)
self
.
__predictionLogger
.
writeRecord
(
result
)
periodic
.
tick
(
)
self
.
_getAndEmitExperimentMetrics
(
final
=
True
)
self
.
__taskDriver
.
finalize
(
)
self
.
__model
.
resetSequenceStates
(
)


def _createPeriodicActivities(self):
    """Creates and returns a list of activites for this TaskRunner instance

    Returns: a list of PeriodicActivityRequest elements
    """
    # Initialize periodic activities
    periodicActivities = []

    # Metrics reporting
    class MetricsReportCb(object):
      def __init__(self, taskRunner):
        self.__taskRunner = taskRunner
        return

      def __call__(self):
        self.__taskRunner._getAndEmitExperimentMetrics()

    reportMetrics = PeriodicActivityRequest(
      repeating=True,
      period=1000,
      cb=MetricsReportCb(self))

    periodicActivities.append(reportMetrics)

    # Iteration progress
    class IterationProgressCb(object):
      PROGRESS_UPDATE_PERIOD_TICKS = 1000

      def __init__(self, taskLabel, requestedIterationCount, logger):
        self.__taskLabel = taskLabel
        self.__requestedIterationCount = requestedIterationCount
        self.__logger = logger

        self.__numIterationsSoFar = 0

      def __call__(self):
        self.__numIterationsSoFar += self.PROGRESS_UPDATE_PERIOD_TICKS
        self.__logger.debug("%s: ITERATION PROGRESS: %s of %s" % (
                              self.__taskLabel,
                              self.__numIterationsSoFar,
                              self.__requestedIterationCount))

    iterationProgressCb = IterationProgressCb(
      taskLabel=self.__task['taskLabel'],
      requestedIterationCount=self.__task['iterationCount'],
      logger=self.__logger)
    iterationProgressReporter = PeriodicActivityRequest(
      repeating=True,
      period=IterationProgressCb.PROGRESS_UPDATE_PERIOD_TICKS,
      cb=iterationProgressCb)

    periodicActivities.append(iterationProgressReporter)

    return periodicActivities

def
_createPeriodicActivities
(
self
)
:
periodicActivities
=
[
]
class
MetricsReportCb
(
object
)
:
def
__init__
(
self
,
taskRunner
)
:
self
.
__taskRunner
=
taskRunner
return
def
__call__
(
self
)
:
self
.
__taskRunner
.
_getAndEmitExperimentMetrics
(
)
reportMetrics
=
PeriodicActivityRequest
(
repeating
=
True
,
period
=
1000
,
cb
=
MetricsReportCb
(
self
)
)
periodicActivities
.
append
(
reportMetrics
)
class
IterationProgressCb
(
object
)
:
PROGRESS_UPDATE_PERIOD_TICKS
=
1000
def
__init__
(
self
,
taskLabel
,
requestedIterationCount
,
logger
)
:
self
.
__taskLabel
=
taskLabel
self
.
__requestedIterationCount
=
requestedIterationCount
self
.
__logger
=
logger
self
.
__numIterationsSoFar
=
0
def
__call__
(
self
)
:
self
.
__numIterationsSoFar
+=
self
.
PROGRESS_UPDATE_PERIOD_TICKS
self
.
__logger
.
debug
(
"%s: ITERATION PROGRESS: %s of %s"
%
(
self
.
__taskLabel
,
self
.
__numIterationsSoFar
,
self
.
__requestedIterationCount
)
)
iterationProgressCb
=
IterationProgressCb
(
taskLabel
=
self
.
__task
[
'taskLabel'
]
,
requestedIterationCount
=
self
.
__task
[
'iterationCount'
]
,
logger
=
self
.
__logger
)
iterationProgressReporter
=
PeriodicActivityRequest
(
repeating
=
True
,
period
=
IterationProgressCb
.
PROGRESS_UPDATE_PERIOD_TICKS
,
cb
=
iterationProgressCb
)
periodicActivities
.
append
(
iterationProgressReporter
)
return
periodicActivities


def corruptVector(v1, noiseLevel, numActiveCols):
  """
  Corrupts a copy of a binary vector by inverting noiseLevel percent of its bits.

  @param v1      (array) binary vector whose copy will be corrupted
  @param noiseLevel  (float) amount of noise to be applied on the new vector
  @param numActiveCols (int)   number of sparse columns that represent an input

  @return v2 (array) corrupted binary vector
  """
  size = len(v1)
  v2 = np.zeros(size, dtype="uint32")
  bitsToSwap = int(noiseLevel * numActiveCols)
  # Copy the contents of v1 into v2
  for i in range(size):
    v2[i] = v1[i]
  for _ in range(bitsToSwap):
    i = random.randrange(size)
    if v2[i] == 1:
      v2[i] = 0
    else:
      v2[i] = 1
  return v2

def corruptVector ( v1 , noiseLevel , numActiveCols ) : size = len ( v1 ) v2 = np . zeros ( size , dtype = "uint32" ) bitsToSwap = int ( noiseLevel * numActiveCols ) for i in range ( size ) : v2 [ i ] = v1 [ i ] for _ in range ( bitsToSwap ) : i = random . randrange ( size ) if v2 [ i ] == 1 : v2 [ i ] = 0 else : v2 [ i ] = 1 return v2

Corrupts a copy of a binary vector by inverting noiseLevel percent of its bits .


def showPredictions():
  """
  Shows predictions of the TM when presented with the characters A, B, C, D, X, and
  Y without any contextual information, that is, not embedded within a sequence.
  """
  for k in range(6):
    tm.reset()
    print "--- " + "ABCDXY"[k] + " ---"
    tm.compute(set(seqT[k][:].nonzero()[0].tolist()), learn=False)
    activeColumnsIndices = [tm.columnForCell(i) for i in tm.getActiveCells()]
    predictedColumnIndices = [tm.columnForCell(i) for i in tm.getPredictiveCells()]
    currentColumns = [1 if i in activeColumnsIndices else 0 for i in range(tm.numberOfColumns())]
    predictedColumns = [1 if i in predictedColumnIndices else 0 for i in range(tm.numberOfColumns())]
    print("Active cols: " + str(np.nonzero(currentColumns)[0]))
    print("Predicted cols: " + str(np.nonzero(predictedColumns)[0]))
    print ""

def
showPredictions
(
)
:
for
k
in
range
(
6
)
:
tm
.
reset
(
)
print
"--- "
+
"ABCDXY"
[
k
]
+
" ---"
tm
.
compute
(
set
(
seqT
[
k
]
[
:
]
.
nonzero
(
)
[
0
]
.
tolist
(
)
)
,
learn
=
False
)
activeColumnsIndices
=
[
tm
.
columnForCell
(
i
)
for
i
in
tm
.
getActiveCells
(
)
]
predictedColumnIndices
=
[
tm
.
columnForCell
(
i
)
for
i
in
tm
.
getPredictiveCells
(
)
]
currentColumns
=
[
1
if
i
in
activeColumnsIndices
else
0
for
i
in
range
(
tm
.
numberOfColumns
(
)
)
]
predictedColumns
=
[
1
if
i
in
predictedColumnIndices
else
0
for
i
in
range
(
tm
.
numberOfColumns
(
)
)
]
print
(
"Active cols: "
+
str
(
np
.
nonzero
(
currentColumns
)
[
0
]
)
)
print
(
"Predicted cols: "
+
str
(
np
.
nonzero
(
predictedColumns
)
[
0
]
)
)
print
""

Shows predictions of the TM when presented with the characters A B C D X and Y without any contextual information that is not embedded within a sequence .


def trainTM(sequence, timeSteps, noiseLevel):
  """
  Trains the TM with given sequence for a given number of time steps and level of input
  corruption

  @param sequence   (array) array whose rows are the input characters
  @param timeSteps  (int)   number of time steps in which the TM will be presented with sequence
  @param noiseLevel (float) amount of noise to be applied on the characters in the sequence
  """
  currentColumns = np.zeros(tm.numberOfColumns(), dtype="uint32")
  predictedColumns = np.zeros(tm.numberOfColumns(), dtype="uint32")
  ts = 0
  for t in range(timeSteps):
    tm.reset()
    for k in range(4):
      v = corruptVector(sequence[k][:], noiseLevel, sparseCols)
      tm.compute(set(v[:].nonzero()[0].tolist()), learn=True)
      activeColumnsIndices = [tm.columnForCell(i) for i in tm.getActiveCells()]
      predictedColumnIndices = [tm.columnForCell(i) for i in tm.getPredictiveCells()]
      currentColumns = [1 if i in activeColumnsIndices else 0 for i in range(tm.numberOfColumns())]
      acc = accuracy(currentColumns, predictedColumns)
      x.append(ts)
      y.append(acc)
      ts += 1
      predictedColumns = [1 if i in predictedColumnIndices else 0 for i in range(tm.numberOfColumns())]

def trainTM ( sequence , timeSteps , noiseLevel ) : currentColumns = np . zeros ( tm . numberOfColumns ( ) , dtype = "uint32" ) predictedColumns = np . zeros ( tm . numberOfColumns ( ) , dtype = "uint32" ) ts = 0 for t in range ( timeSteps ) : tm . reset ( ) for k in range ( 4 ) : v = corruptVector ( sequence [ k ] [ : ] , noiseLevel , sparseCols ) tm . compute ( set ( v [ : ] . nonzero ( ) [ 0 ] . tolist ( ) ) , learn = True ) activeColumnsIndices = [ tm . columnForCell ( i ) for i in tm . getActiveCells ( ) ] predictedColumnIndices = [ tm . columnForCell ( i ) for i in tm . getPredictiveCells ( ) ] currentColumns = [ 1 if i in activeColumnsIndices else 0 for i in range ( tm . numberOfColumns ( ) ) ] acc = accuracy ( currentColumns , predictedColumns ) x . append ( ts ) y . append ( acc ) ts += 1 predictedColumns = [ 1 if i in predictedColumnIndices else 0 for i in range ( tm . numberOfColumns ( ) ) ]


def closenessScores(self, expValues, actValues, **kwargs):
    """
    Does a bitwise compare of the two bitmaps and returns a fractonal
    value between 0 and 1 of how similar they are.

    - ``1`` => identical
    - ``0`` => no overlaping bits

    ``kwargs`` will have the keyword "fractional", which is assumed by this
    encoder.
    """
    ratio = 1.0
    esum = int(expValues.sum())
    asum = int(actValues.sum())
    if asum > esum:
      diff = asum - esum
      if diff < esum:
        ratio = 1 - diff/float(esum)
      else:
        ratio = 1/float(diff)

    olap = expValues & actValues
    osum = int(olap.sum())
    if esum == 0:
      r = 0.0
    else:
      r = osum/float(esum)
    r = r * ratio

    return numpy.array([r])

def closenessScores ( self , expValues , actValues , ** kwargs ) : ratio = 1.0 esum = int ( expValues . sum ( ) ) asum = int ( actValues . sum ( ) ) if asum > esum : diff = asum - esum if diff < esum : ratio = 1 - diff / float ( esum ) else : ratio = 1 / float ( diff ) olap = expValues & actValues osum = int ( olap . sum ( ) ) if esum == 0 : r = 0.0 else : r = osum / float ( esum ) r = r * ratio return numpy . array ( [ r ] )

Does a bitwise compare of the two bitmaps and returns a fractonal value between 0 and 1 of how similar they are .


def getCallerInfo(depth=2):
  """Utility function to get information about function callers

  The information is the tuple (function/method name, filename, class)
  The class will be None if the caller is just a function and not an object
  method.

  :param depth: (int) how far back in the callstack to go to extract the caller
         info

  """
  f = sys._getframe(depth)
  method_name = f.f_code.co_name
  filename = f.f_code.co_filename

  arg_class = None
  args = inspect.getargvalues(f)
  if len(args[0]) > 0:
    arg_name = args[0][0] # potentially the 'self' arg if its a method
    arg_class = args[3][arg_name].__class__.__name__
  return (method_name, filename, arg_class)

def getCallerInfo ( depth = 2 ) : f = sys . _getframe ( depth ) method_name = f . f_code . co_name filename = f . f_code . co_filename arg_class = None args = inspect . getargvalues ( f ) if len ( args [ 0 ] ) > 0 : arg_name = args [ 0 ] [ 0 ] arg_class = args [ 3 ] [ arg_name ] . __class__ . __name__ return ( method_name , filename , arg_class )


def title(s=None, additional='', stream=sys.stdout):
  """Utility function to display nice titles

  It automatically extracts the name of the function/method it is called from
  and you can add additional text. title() will then print the name
  of the function/method and the additional text surrounded by tow lines
  of dashes. If you don't want the name of the function, you can provide
  alternative text (regardless of the additional text)

  :param s: (string) text to display, uses the function name and arguments by
         default
  :param additional: (string) extra text to display (not needed if s is not
         None)
  :param stream: (stream) the stream to print to. Ny default goes to standard
         output

  Examples:

  .. code-block:: python

    def foo():
      title()

  will display:

  .. code-block:: text

    ---
    foo
    ---

  .. code-block:: python

    def foo():
      title(additional='(), this is cool!!!')

  will display:

  .. code-block:: text

    ----------------------
    foo(), this is cool!!!
    ----------------------

  .. code-block:: python

    def foo():
      title('No function name here!')

  will display:

  .. code-block:: text

    ----------------------
    No function name here!
    ----------------------

  """
  if s is None:
    callable_name, file_name, class_name = getCallerInfo(2)
    s = callable_name
    if class_name is not None:
      s = class_name + '.' + callable_name
  lines = (s + additional).split('\n')
  length = max(len(line) for line in lines)
  print >> stream, '-' * length
  print >> stream, s + additional
  print >> stream, '-' * length

def title ( s = None , additional = '' , stream = sys . stdout ) : if s is None : callable_name , file_name , class_name = getCallerInfo ( 2 ) s = callable_name if class_name is not None : s = class_name + '.' + callable_name lines = ( s + additional ) . split ( '\n' ) length = max ( len ( line ) for line in lines ) print >> stream , '-' * length print >> stream , s + additional print >> stream , '-' * length


def getArgumentDescriptions(f):
  """
  Get the arguments, default values, and argument descriptions for a function.

  Parses the argument descriptions out of the function docstring, using a
  format something lke this:

  ::

    [junk]
    argument_name:     description...
      description...
      description...
    [junk]
    [more arguments]

  It will find an argument as long as the exact argument name starts the line.
  It will then strip a trailing colon, if present, then strip the rest of the
  line and use it to start the description. It will then strip and append any
  subsequent lines with a greater indent level than the original argument name.

  :param f: (function) to inspect
  :returns: (list of tuples) (``argName``, ``argDescription``, ``defaultValue``)
    If an argument has no default value, the tuple is only two elements long (as
    ``None`` cannot be used, since it could be a default value itself).
  """

  # Get the argument names and default values
  argspec = inspect.getargspec(f)

  # Scan through the docstring to extract documentation for each argument as
  # follows:
  #   Check the first word of the line, stripping a colon if one is present.
  #   If it matches an argument name:
  #    Take the rest of the line, stripping leading whitespeace
  #    Take each subsequent line if its indentation level is greater than the
  #      initial indentation level
  #    Once the indentation level is back to the original level, look for
  #      another argument
  docstring = f.__doc__
  descriptions = {}
  if docstring:
    lines = docstring.split('\n')
    i = 0
    while i < len(lines):
      stripped = lines[i].lstrip()
      if not stripped:
        i += 1
        continue
      # Indentation level is index of the first character
      indentLevel = lines[i].index(stripped[0])
      # Get the first word and remove the colon, if present
      firstWord = stripped.split()[0]
      if firstWord.endswith(':'):
        firstWord = firstWord[:-1]
      if firstWord in argspec.args:
        # Found an argument
        argName = firstWord
        restOfLine = stripped[len(firstWord)+1:].strip()
        argLines = [restOfLine]
        # Take the next lines as long as they are indented more
        i += 1
        while i < len(lines):
          stripped = lines[i].lstrip()
          if not stripped:
            # Empty line - stop
            break
          if lines[i].index(stripped[0]) <= indentLevel:
            # No longer indented far enough - stop
            break
          # This line counts too
          argLines.append(lines[i].strip())
          i += 1
        # Store this description
        descriptions[argName] = ' '.join(argLines)
      else:
        # Not an argument
        i += 1

  # Build the list of (argName, description, defaultValue)
  args = []
  if argspec.defaults:
    defaultCount = len(argspec.defaults)
  else:
    defaultCount = 0
  nonDefaultArgCount = len(argspec.args) - defaultCount
  for i, argName in enumerate(argspec.args):
    if i >= nonDefaultArgCount:
      defaultValue = argspec.defaults[i - nonDefaultArgCount]
      args.append((argName, descriptions.get(argName, ""), defaultValue))
    else:
      args.append((argName, descriptions.get(argName, "")))

  return args

def
getArgumentDescriptions
(
f
)
:
argspec
=
inspect
.
getargspec
(
f
)
docstring
=
f
.
__doc__
descriptions
=
{
}
if
docstring
:
lines
=
docstring
.
split
(
'\n'
)
i
=
0
while
i
<
len
(
lines
)
:
stripped
=
lines
[
i
]
.
lstrip
(
)
if
not
stripped
:
i
+=
1
continue
indentLevel
=
lines
[
i
]
.
index
(
stripped
[
0
]
)
firstWord
=
stripped
.
split
(
)
[
0
]
if
firstWord
.
endswith
(
':'
)
:
firstWord
=
firstWord
[
:
1
]
if
firstWord
in
argspec
.
args
:
argName
=
firstWord
restOfLine
=
stripped
[
len
(
firstWord
)
+
1
:
]
.
strip
(
)
argLines
=
[
restOfLine
]
i
+=
1
while
i
<
len
(
lines
)
:
stripped
=
lines
[
i
]
.
lstrip
(
)
if
not
stripped
:
break
if
lines
[
i
]
.
index
(
stripped
[
0
]
)
<=
indentLevel
:
break
argLines
.
append
(
lines
[
i
]
.
strip
(
)
)
i
+=
1
descriptions
[
argName
]
=
' '
.
join
(
argLines
)
else
:
i
+=
1
args
=
[
]
if
argspec
.
defaults
:
defaultCount
=
len
(
argspec
.
defaults
)
else
:
defaultCount
=
0
nonDefaultArgCount
=
len
(
argspec
.
args
)
defaultCount
for
i
,
argName
in
enumerate
(
argspec
.
args
)
:
if
i
>=
nonDefaultArgCount
:
defaultValue
=
argspec
.
defaults
[
i
nonDefaultArgCount
]
args
.
append
(
(
argName
,
descriptions
.
get
(
argName
,
""
)
,
defaultValue
)
)
else
:
args
.
append
(
(
argName
,
descriptions
.
get
(
argName
,
""
)
)
)
return
args

Get the arguments default values and argument descriptions for a function .


def _genLoggingFilePath():
  """ Generate a filepath for the calling app """
  appName = os.path.splitext(os.path.basename(sys.argv[0]))[0] or 'UnknownApp'
  appLogDir = os.path.abspath(os.path.join(
    os.environ['NTA_LOG_DIR'],
    'numenta-logs-%s' % (os.environ['USER'],),
    appName))
  appLogFileName = '%s-%s-%s.log' % (
    appName, long(time.mktime(time.gmtime())), os.getpid())
  return os.path.join(appLogDir, appLogFileName)

def _genLoggingFilePath ( ) : appName = os . path . splitext ( os . path . basename ( sys . argv [ 0 ] ) ) [ 0 ] or 'UnknownApp' appLogDir = os . path . abspath ( os . path . join ( os . environ [ 'NTA_LOG_DIR' ] , 'numenta-logs-%s' % ( os . environ [ 'USER' ] , ) , appName ) ) appLogFileName = '%s-%s-%s.log' % ( appName , long ( time . mktime ( time . gmtime ( ) ) ) , os . getpid ( ) ) return os . path . join ( appLogDir , appLogFileName )


def aggregationToMonthsSeconds(interval):
  """
  Return the number of months and seconds from an aggregation dict that
  represents a date and time.

  Interval is a dict that contain one or more of the following keys: 'years',
  'months', 'weeks', 'days', 'hours', 'minutes', seconds', 'milliseconds',
  'microseconds'.

  For example:

  ::

    aggregationMicroseconds({'years': 1, 'hours': 4, 'microseconds':42}) ==
        {'months':12, 'seconds':14400.000042}

  :param interval: (dict) The aggregation interval representing a date and time
  :returns: (dict) number of months and seconds in the interval:
            ``{months': XX, 'seconds': XX}``. The seconds is
            a floating point that can represent resolutions down to a
            microsecond.

  """

  seconds = interval.get('microseconds', 0) * 0.000001
  seconds += interval.get('milliseconds', 0) * 0.001
  seconds += interval.get('seconds', 0)
  seconds += interval.get('minutes', 0) * 60
  seconds += interval.get('hours', 0) * 60 * 60
  seconds += interval.get('days', 0) * 24 * 60 * 60
  seconds += interval.get('weeks', 0) * 7 * 24 * 60 * 60

  months = interval.get('months', 0)
  months += 12 * interval.get('years', 0)

  return {'months': months, 'seconds': seconds}

def aggregationToMonthsSeconds ( interval ) : seconds = interval . get ( 'microseconds' , 0 ) * 0.000001 seconds += interval . get ( 'milliseconds' , 0 ) * 0.001 seconds += interval . get ( 'seconds' , 0 ) seconds += interval . get ( 'minutes' , 0 ) * 60 seconds += interval . get ( 'hours' , 0 ) * 60 * 60 seconds += interval . get ( 'days' , 0 ) * 24 * 60 * 60 seconds += interval . get ( 'weeks' , 0 ) * 7 * 24 * 60 * 60 months = interval . get ( 'months' , 0 ) months += 12 * interval . get ( 'years' , 0 ) return { 'months' : months , 'seconds' : seconds }

Return the number of months and seconds from an aggregation dict that represents a date and time .


def aggregationDivide(dividend, divisor):
  """
  Return the result from dividing two dicts that represent date and time.

  Both dividend and divisor are dicts that contain one or more of the following
  keys: 'years', 'months', 'weeks', 'days', 'hours', 'minutes', seconds',
  'milliseconds', 'microseconds'.

  For example:

  ::

    aggregationDivide({'hours': 4}, {'minutes': 15}) == 16

  :param dividend: (dict) The numerator, as a dict representing a date and time
  :param divisor: (dict) the denominator, as a dict representing a date and time
  :returns: (float) number of times divisor goes into dividend

  """

  # Convert each into microseconds
  dividendMonthSec = aggregationToMonthsSeconds(dividend)
  divisorMonthSec = aggregationToMonthsSeconds(divisor)

  # It is a usage error to mix both months and seconds in the same operation
  if (dividendMonthSec['months'] != 0 and divisorMonthSec['seconds'] != 0) \
    or (dividendMonthSec['seconds'] != 0 and divisorMonthSec['months'] != 0):
    raise RuntimeError("Aggregation dicts with months/years can only be "
      "inter-operated with other aggregation dicts that contain "
      "months/years")

  if dividendMonthSec['months'] > 0:
    return float(dividendMonthSec['months']) / divisor['months']

  else:
    return float(dividendMonthSec['seconds']) / divisorMonthSec['seconds']

Return the result from dividing two dicts that represent date and time .


def validateOpfJsonValue(value, opfJsonSchemaFilename):
  """
  Validate a python object against an OPF json schema file

  :param value: target python object to validate (typically a dictionary)
  :param opfJsonSchemaFilename: (string) OPF json schema filename containing the
         json schema object. (e.g., opfTaskControlSchema.json)
  :raises: jsonhelpers.ValidationError when value fails json validation
  """

  # Create a path by joining the filename with our local json schema root
  jsonSchemaPath = os.path.join(os.path.dirname(__file__),
                                "jsonschema",
                                opfJsonSchemaFilename)

  # Validate
  jsonhelpers.validate(value, schemaPath=jsonSchemaPath)

  return

def validateOpfJsonValue ( value , opfJsonSchemaFilename ) : jsonSchemaPath = os . path . join ( os . path . dirname ( __file__ ) , "jsonschema" , opfJsonSchemaFilename ) jsonhelpers . validate ( value , schemaPath = jsonSchemaPath ) return


def initLogger(obj):
  """
  Helper function to create a logger object for the current object with
  the standard Numenta prefix.

  :param obj: (object) to add a logger to
  """
  if inspect.isclass(obj):
    myClass = obj
  else:
    myClass = obj.__class__
  logger = logging.getLogger(".".join(
    ['com.numenta', myClass.__module__, myClass.__name__]))
  return logger

def initLogger ( obj ) : if inspect . isclass ( obj ) : myClass = obj else : myClass = obj . __class__ logger = logging . getLogger ( "." . join ( [ 'com.numenta' , myClass . __module__ , myClass . __name__ ] ) ) return logger

Helper function to create a logger object for the current object with the standard Numenta prefix .


def matchPatterns(patterns, keys):
  """
  Returns a subset of the keys that match any of the given patterns

  :param patterns: (list) regular expressions to match
  :param keys: (list) keys to search for matches
  """
  results = []
  if patterns:
    for pattern in patterns:
      prog = re.compile(pattern)
      for key in keys:
        if prog.match(key):
          results.append(key)
  else:
    return None

  return results

def matchPatterns ( patterns , keys ) : results = [ ] if patterns : for pattern in patterns : prog = re . compile ( pattern ) for key in keys : if prog . match ( key ) : results . append ( key ) else : return None return results


def _getScaledValue(self, inpt):
    """
    Convert the input, which is in normal space, into log space
    """
    if inpt == SENTINEL_VALUE_FOR_MISSING_DATA:
      return None
    else:
      val = inpt
      if val < self.minval:
        val = self.minval
      elif val > self.maxval:
        val = self.maxval

      scaledVal = math.log10(val)
      return scaledVal

def _getScaledValue ( self , inpt ) : if inpt == SENTINEL_VALUE_FOR_MISSING_DATA : return None else : val = inpt if val < self . minval : val = self . minval elif val > self . maxval : val = self . maxval scaledVal = math . log10 ( val ) return scaledVal

Convert the input which is in normal space into log space


def export(self):
    """
    Exports a network as a networkx MultiDiGraph intermediate representation
    suitable for visualization.

    :return: networkx MultiDiGraph
    """
    graph = nx.MultiDiGraph()

    # Add regions to graph as nodes, annotated by name
    regions = self.network.getRegions()

    for idx in xrange(regions.getCount()):
      regionPair = regions.getByIndex(idx)
      regionName = regionPair[0]
      graph.add_node(regionName, label=regionName)

    # Add links between regions to graph as edges, annotate by input-output
    # name pairs
    for linkName, link in self.network.getLinks():
      graph.add_edge(link.getSrcRegionName(),
                     link.getDestRegionName(),
                     src=link.getSrcOutputName(),
                     dest=link.getDestInputName())

    return graph

def export ( self ) : graph = nx . MultiDiGraph ( ) regions = self . network . getRegions ( ) for idx in xrange ( regions . getCount ( ) ) : regionPair = regions . getByIndex ( idx ) regionName = regionPair [ 0 ] graph . add_node ( regionName , label = regionName ) for linkName , link in self . network . getLinks ( ) : graph . add_edge ( link . getSrcRegionName ( ) , link . getDestRegionName ( ) , src = link . getSrcOutputName ( ) , dest = link . getDestInputName ( ) ) return graph

Exports a network as a networkx MultiDiGraph intermediate representation suitable for visualization .


def bitsToString(arr):
  """Returns a string representing a numpy array of 0's and 1's"""
  s = array('c','.'*len(arr))
  for i in xrange(len(arr)):
    if arr[i] == 1:
      s[i]='*'
  return s

def bitsToString ( arr ) : s = array ( 'c' , '.' * len ( arr ) ) for i in xrange ( len ( arr ) ) : if arr [ i ] == 1 : s [ i ] = '*' return s

Returns a string representing a numpy array of 0 s and 1 s


def percentOverlap(x1, x2, size):
  """
  Computes the percentage of overlap between vectors x1 and x2.

  @param x1   (array) binary vector
  @param x2   (array) binary vector
  @param size (int)   length of binary vectors

  @return percentOverlap (float) percentage overlap between x1 and x2
  """
  nonZeroX1 = np.count_nonzero(x1)
  nonZeroX2 = np.count_nonzero(x2)
  minX1X2 = min(nonZeroX1, nonZeroX2)
  percentOverlap = 0
  if minX1X2 > 0:
    percentOverlap = float(np.dot(x1, x2))/float(minX1X2)
  return percentOverlap

def percentOverlap ( x1 , x2 , size ) : nonZeroX1 = np . count_nonzero ( x1 ) nonZeroX2 = np . count_nonzero ( x2 ) minX1X2 = min ( nonZeroX1 , nonZeroX2 ) percentOverlap = 0 if minX1X2 > 0 : percentOverlap = float ( np . dot ( x1 , x2 ) ) / float ( minX1X2 ) return percentOverlap

Computes the percentage of overlap between vectors x1 and x2 .


def resetVector(x1, x2):
  """
  Copies the contents of vector x1 into vector x2.

  @param x1 (array) binary vector to be copied
  @param x2 (array) binary vector where x1 is copied
  """
  size = len(x1)
  for i in range(size):
    x2[i] = x1[i]

def resetVector ( x1 , x2 ) : size = len ( x1 ) for i in range ( size ) : x2 [ i ] = x1 [ i ]

Copies the contents of vector x1 into vector x2 .


def runCPU():
  """Poll CPU usage, make predictions, and plot the results. Runs forever."""
  # Create the model for predicting CPU usage.
  model = ModelFactory.create(model_params.MODEL_PARAMS)
  model.enableInference({'predictedField': 'cpu'})
  # The shifter will align prediction and actual values.
  shifter = InferenceShifter()
  # Keep the last WINDOW predicted and actual values for plotting.
  actHistory = deque([0.0] * WINDOW, maxlen=60)
  predHistory = deque([0.0] * WINDOW, maxlen=60)

  # Initialize the plot lines that we will update with each new record.
  actline, = plt.plot(range(WINDOW), actHistory)
  predline, = plt.plot(range(WINDOW), predHistory)
  # Set the y-axis range.
  actline.axes.set_ylim(0, 100)
  predline.axes.set_ylim(0, 100)

  while True:
    s = time.time()

    # Get the CPU usage.
    cpu = psutil.cpu_percent()

    # Run the input through the model and shift the resulting prediction.
    modelInput = {'cpu': cpu}
    result = shifter.shift(model.run(modelInput))

    # Update the trailing predicted and actual value deques.
    inference = result.inferences['multiStepBestPredictions'][5]
    if inference is not None:
      actHistory.append(result.rawInput['cpu'])
      predHistory.append(inference)

    # Redraw the chart with the new data.
    actline.set_ydata(actHistory)  # update the data
    predline.set_ydata(predHistory)  # update the data
    plt.draw()
    plt.legend( ('actual','predicted') )

    # Make sure we wait a total of 2 seconds per iteration.
    try:
      plt.pause(SECONDS_PER_STEP)
    except:
      pass

def runCPU ( ) : model = ModelFactory . create ( model_params . MODEL_PARAMS ) model . enableInference ( { 'predictedField' : 'cpu' } ) shifter = InferenceShifter ( ) actHistory = deque ( [ 0.0 ] * WINDOW , maxlen = 60 ) predHistory = deque ( [ 0.0 ] * WINDOW , maxlen = 60 ) actline , = plt . plot ( range ( WINDOW ) , actHistory ) predline , = plt . plot ( range ( WINDOW ) , predHistory ) actline . axes . set_ylim ( 0 , 100 ) predline . axes . set_ylim ( 0 , 100 ) while True : s = time . time ( ) cpu = psutil . cpu_percent ( ) modelInput = { 'cpu' : cpu } result = shifter . shift ( model . run ( modelInput ) ) inference = result . inferences [ 'multiStepBestPredictions' ] [ 5 ] if inference is not None : actHistory . append ( result . rawInput [ 'cpu' ] ) predHistory . append ( inference ) actline . set_ydata ( actHistory ) predline . set_ydata ( predHistory ) plt . draw ( ) plt . legend ( ( 'actual' , 'predicted' ) ) try : plt . pause ( SECONDS_PER_STEP ) except : pass

Poll CPU usage make predictions and plot the results . Runs forever .


def _extractCallingMethodArgs():
  """
  Returns args dictionary from the calling method
  """
  import inspect
  import copy

  callingFrame = inspect.stack()[1][0]

  argNames, _, _, frameLocalVarDict = inspect.getargvalues(callingFrame)

  argNames.remove("self")

  args = copy.copy(frameLocalVarDict)

  for varName in frameLocalVarDict:
    if varName not in argNames:
      args.pop(varName)

  return args

def _extractCallingMethodArgs ( ) : import inspect import copy callingFrame = inspect . stack ( ) [ 1 ] [ 0 ] argNames , _ , _ , frameLocalVarDict = inspect . getargvalues ( callingFrame ) argNames . remove ( "self" ) args = copy . copy ( frameLocalVarDict ) for varName in frameLocalVarDict : if varName not in argNames : args . pop ( varName ) return args


def _getEphemeralMembers(self):
    """
    List of our member variables that we don't need to be saved
    """
    e = BacktrackingTM._getEphemeralMembers(self)
    if self.makeCells4Ephemeral:
      e.extend(['cells4'])
    return e

def _getEphemeralMembers ( self ) : e = BacktrackingTM . _getEphemeralMembers ( self ) if self . makeCells4Ephemeral : e . extend ( [ 'cells4' ] ) return e

List of our member variables that we don t need to be saved


def _copyAllocatedStates(self):
    """If state is allocated in CPP, copy over the data into our numpy arrays."""

    # Get learn states if we need to print them out
    if self.verbosity > 1 or self.retrieveLearningStates:
      (activeT, activeT1, predT, predT1) = self.cells4.getLearnStates()
      self.lrnActiveState['t-1'] = activeT1.reshape((self.numberOfCols, self.cellsPerColumn))
      self.lrnActiveState['t'] = activeT.reshape((self.numberOfCols, self.cellsPerColumn))
      self.lrnPredictedState['t-1'] = predT1.reshape((self.numberOfCols, self.cellsPerColumn))
      self.lrnPredictedState['t'] = predT.reshape((self.numberOfCols, self.cellsPerColumn))

    if self.allocateStatesInCPP:
      assert False
      (activeT, activeT1, predT, predT1, colConfidenceT, colConfidenceT1, confidenceT,
       confidenceT1) = self.cells4.getStates()
      self.cellConfidence['t'] = confidenceT.reshape((self.numberOfCols, self.cellsPerColumn))
      self.cellConfidence['t-1'] = confidenceT1.reshape((self.numberOfCols, self.cellsPerColumn))
      self.colConfidence['t'] = colConfidenceT.reshape(self.numberOfCols)
      self.colConfidence['t-1'] = colConfidenceT1.reshape(self.numberOfCols)
      self.infActiveState['t-1'] = activeT1.reshape((self.numberOfCols, self.cellsPerColumn))
      self.infActiveState['t'] = activeT.reshape((self.numberOfCols, self.cellsPerColumn))
      self.infPredictedState['t-1'] = predT1.reshape((self.numberOfCols, self.cellsPerColumn))
      self.infPredictedState['t'] = predT.reshape((self.numberOfCols, self.cellsPerColumn))

def _copyAllocatedStates ( self ) : if self . verbosity > 1 or self . retrieveLearningStates : ( activeT , activeT1 , predT , predT1 ) = self . cells4 . getLearnStates ( ) self . lrnActiveState [ 't-1' ] = activeT1 . reshape ( ( self . numberOfCols , self . cellsPerColumn ) ) self . lrnActiveState [ 't' ] = activeT . reshape ( ( self . numberOfCols , self . cellsPerColumn ) ) self . lrnPredictedState [ 't-1' ] = predT1 . reshape ( ( self . numberOfCols , self . cellsPerColumn ) ) self . lrnPredictedState [ 't' ] = predT . reshape ( ( self . numberOfCols , self . cellsPerColumn ) ) if self . allocateStatesInCPP : assert False ( activeT , activeT1 , predT , predT1 , colConfidenceT , colConfidenceT1 , confidenceT , confidenceT1 ) = self . cells4 . getStates ( ) self . cellConfidence [ 't' ] = confidenceT . reshape ( ( self . numberOfCols , self . cellsPerColumn ) ) self . cellConfidence [ 't-1' ] = confidenceT1 . reshape ( ( self . numberOfCols , self . cellsPerColumn ) ) self . colConfidence [ 't' ] = colConfidenceT . reshape ( self . numberOfCols ) self . colConfidence [ 't-1' ] = colConfidenceT1 . reshape ( self . numberOfCols ) self . infActiveState [ 't-1' ] = activeT1 . reshape ( ( self . numberOfCols , self . cellsPerColumn ) ) self . infActiveState [ 't' ] = activeT . reshape ( ( self . numberOfCols , self . cellsPerColumn ) ) self . infPredictedState [ 't-1' ] = predT1 . reshape ( ( self . numberOfCols , self . cellsPerColumn ) ) self . infPredictedState [ 't' ] = predT . reshape ( ( self . numberOfCols , self . cellsPerColumn ) )

If state is allocated in CPP copy over the data into our numpy arrays .


def _setStatePointers(self):
    """If we are having CPP use numpy-allocated buffers, set these buffer
    pointers. This is a relatively fast operation and, for safety, should be
    done before every call to the cells4 compute methods.  This protects us
    in situations where code can cause Python or numpy to create copies."""
    if not self.allocateStatesInCPP:
      self.cells4.setStatePointers(
          self.infActiveState["t"], self.infActiveState["t-1"],
          self.infPredictedState["t"], self.infPredictedState["t-1"],
          self.colConfidence["t"], self.colConfidence["t-1"],
          self.cellConfidence["t"], self.cellConfidence["t-1"])

def _setStatePointers ( self ) : if not self . allocateStatesInCPP : self . cells4 . setStatePointers ( self . infActiveState [ "t" ] , self . infActiveState [ "t-1" ] , self . infPredictedState [ "t" ] , self . infPredictedState [ "t-1" ] , self . colConfidence [ "t" ] , self . colConfidence [ "t-1" ] , self . cellConfidence [ "t" ] , self . cellConfidence [ "t-1" ] )

If we are having CPP use numpy - allocated buffers set these buffer pointers . This is a relatively fast operation and for safety should be done before every call to the cells4 compute methods . This protects us in situations where code can cause Python or numpy to create copies .


def _slowIsSegmentActive(self, seg, timeStep):
    """
    A segment is active if it has >= activationThreshold connected
    synapses that are active due to infActiveState.

    """

    numSyn = seg.size()
    numActiveSyns = 0
    for synIdx in xrange(numSyn):
      if seg.getPermanence(synIdx) < self.connectedPerm:
        continue
      sc, si = self.getColCellIdx(seg.getSrcCellIdx(synIdx))
      if self.infActiveState[timeStep][sc, si]:
        numActiveSyns += 1
        if numActiveSyns >= self.activationThreshold:
          return True

    return numActiveSyns >= self.activationThreshold

def _slowIsSegmentActive ( self , seg , timeStep ) : numSyn = seg . size ( ) numActiveSyns = 0 for synIdx in xrange ( numSyn ) : if seg . getPermanence ( synIdx ) < self . connectedPerm : continue sc , si = self . getColCellIdx ( seg . getSrcCellIdx ( synIdx ) ) if self . infActiveState [ timeStep ] [ sc , si ] : numActiveSyns += 1 if numActiveSyns >= self . activationThreshold : return True return numActiveSyns >= self . activationThreshold

A segment is active if it has > = activationThreshold connected synapses that are active due to infActiveState .


def mapBucketIndexToNonZeroBits(self, index):
    """
    Given a bucket index, return the list of non-zero bits. If the bucket
    index does not exist, it is created. If the index falls outside our range
    we clip it.

    :param index The bucket index to get non-zero bits for.
    @returns numpy array of indices of non-zero bits for specified index.
    """
    if index < 0:
      index = 0

    if index >= self._maxBuckets:
      index = self._maxBuckets-1

    if not self.bucketMap.has_key(index):
      if self.verbosity >= 2:
        print "Adding additional buckets to handle index=", index
      self._createBucket(index)
    return self.bucketMap[index]

Given a bucket index return the list of non - zero bits . If the bucket index does not exist it is created . If the index falls outside our range we clip it .


def _createBucket(self, index):
    """
    Create the given bucket index. Recursively create as many in-between
    bucket indices as necessary.
    """
    if index < self.minIndex:
      if index == self.minIndex - 1:
        # Create a new representation that has exactly w-1 overlapping bits
        # as the min representation
        self.bucketMap[index] = self._newRepresentation(self.minIndex,
                                                        index)
        self.minIndex = index
      else:
        # Recursively create all the indices above and then this index
        self._createBucket(index+1)
        self._createBucket(index)
    else:
      if index == self.maxIndex + 1:
        # Create a new representation that has exactly w-1 overlapping bits
        # as the max representation
        self.bucketMap[index] = self._newRepresentation(self.maxIndex,
                                                        index)
        self.maxIndex = index
      else:
        # Recursively create all the indices below and then this index
        self._createBucket(index-1)
        self._createBucket(index)

def _createBucket ( self , index ) : if index < self . minIndex : if index == self . minIndex - 1 : self . bucketMap [ index ] = self . _newRepresentation ( self . minIndex , index ) self . minIndex = index else : self . _createBucket ( index + 1 ) self . _createBucket ( index ) else : if index == self . maxIndex + 1 : self . bucketMap [ index ] = self . _newRepresentation ( self . maxIndex , index ) self . maxIndex = index else : self . _createBucket ( index - 1 ) self . _createBucket ( index )

Create the given bucket index . Recursively create as many in - between bucket indices as necessary .


def _newRepresentation(self, index, newIndex):
    """
    Return a new representation for newIndex that overlaps with the
    representation at index by exactly w-1 bits
    """
    newRepresentation = self.bucketMap[index].copy()

    # Choose the bit we will replace in this representation. We need to shift
    # this bit deterministically. If this is always chosen randomly then there
    # is a 1 in w chance of the same bit being replaced in neighboring
    # representations, which is fairly high
    ri = newIndex % self.w

    # Now we choose a bit such that the overlap rules are satisfied.
    newBit = self.random.getUInt32(self.n)
    newRepresentation[ri] = newBit
    while newBit in self.bucketMap[index] or \
          not self._newRepresentationOK(newRepresentation, newIndex):
      self.numTries += 1
      newBit = self.random.getUInt32(self.n)
      newRepresentation[ri] = newBit

    return newRepresentation

def _newRepresentation ( self , index , newIndex ) : newRepresentation = self . bucketMap [ index ] . copy ( ) ri = newIndex % self . w newBit = self . random . getUInt32 ( self . n ) newRepresentation [ ri ] = newBit while newBit in self . bucketMap [ index ] or not self . _newRepresentationOK ( newRepresentation , newIndex ) : self . numTries += 1 newBit = self . random . getUInt32 ( self . n ) newRepresentation [ ri ] = newBit return newRepresentation

Return a new representation for newIndex that overlaps with the representation at index by exactly w - 1 bits


def _newRepresentationOK(self, newRep, newIndex):
    """
    Return True if this new candidate representation satisfies all our overlap
    rules. Since we know that neighboring representations differ by at most
    one bit, we compute running overlaps.
    """
    if newRep.size != self.w:
      return False
    if (newIndex < self.minIndex-1) or (newIndex > self.maxIndex+1):
      raise ValueError("newIndex must be within one of existing indices")

    # A binary representation of newRep. We will use this to test containment
    newRepBinary = numpy.array([False]*self.n)
    newRepBinary[newRep] = True

    # Midpoint
    midIdx = self._maxBuckets/2

    # Start by checking the overlap at minIndex
    runningOverlap = self._countOverlap(self.bucketMap[self.minIndex], newRep)
    if not self._overlapOK(self.minIndex, newIndex, overlap=runningOverlap):
      return False

    # Compute running overlaps all the way to the midpoint
    for i in range(self.minIndex+1, midIdx+1):
      # This is the bit that is going to change
      newBit = (i-1)%self.w

      # Update our running overlap
      if newRepBinary[self.bucketMap[i-1][newBit]]:
        runningOverlap -= 1
      if newRepBinary[self.bucketMap[i][newBit]]:
        runningOverlap += 1

      # Verify our rules
      if not self._overlapOK(i, newIndex, overlap=runningOverlap):
        return False

    # At this point, runningOverlap contains the overlap for midIdx
    # Compute running overlaps all the way to maxIndex
    for i in range(midIdx+1, self.maxIndex+1):
      # This is the bit that is going to change
      newBit = i%self.w

      # Update our running overlap
      if newRepBinary[self.bucketMap[i-1][newBit]]:
        runningOverlap -= 1
      if newRepBinary[self.bucketMap[i][newBit]]:
        runningOverlap += 1

      # Verify our rules
      if not self._overlapOK(i, newIndex, overlap=runningOverlap):
        return False

    return True

Return True if this new candidate representation satisfies all our overlap rules . Since we know that neighboring representations differ by at most one bit we compute running overlaps .


def _countOverlapIndices(self, i, j):
    """
    Return the overlap between bucket indices i and j
    """
    if self.bucketMap.has_key(i) and self.bucketMap.has_key(j):
      iRep = self.bucketMap[i]
      jRep = self.bucketMap[j]
      return self._countOverlap(iRep, jRep)
    else:
      raise ValueError("Either i or j don't exist")

def
_countOverlapIndices
(
self
,
i
,
j
)
:
if
self
.
bucketMap
.
has_key
(
i
)
and
self
.
bucketMap
.
has_key
(
j
)
:
iRep
=
self
.
bucketMap
[
i
]
jRep
=
self
.
bucketMap
[
j
]
return
self
.
_countOverlap
(
iRep
,
jRep
)
else
:
raise
ValueError
(
"Either i or j don't exist"
)


def _countOverlap(rep1, rep2):
    """
    Return the overlap between two representations. rep1 and rep2 are lists of
    non-zero indices.
    """
    overlap = 0
    for e in rep1:
      if e in rep2:
        overlap += 1
    return overlap

def _countOverlap ( rep1 , rep2 ) : overlap = 0 for e in rep1 : if e in rep2 : overlap += 1 return overlap

Return the overlap between two representations . rep1 and rep2 are lists of non - zero indices .


def _overlapOK(self, i, j, overlap=None):
    """
    Return True if the given overlap between bucket indices i and j are
    acceptable. If overlap is not specified, calculate it from the bucketMap
    """
    if overlap is None:
      overlap = self._countOverlapIndices(i, j)
    if abs(i-j) < self.w:
      if overlap == (self.w - abs(i-j)):
        return True
      else:
        return False
    else:
      if overlap <= self._maxOverlap:
        return True
      else:
        return False

def _overlapOK ( self , i , j , overlap = None ) : if overlap is None : overlap = self . _countOverlapIndices ( i , j ) if abs ( i - j ) < self . w : if overlap == ( self . w - abs ( i - j ) ) : return True else : return False else : if overlap <= self . _maxOverlap : return True else : return False

Return True if the given overlap between bucket indices i and j are acceptable . If overlap is not specified calculate it from the bucketMap


def _initializeBucketMap(self, maxBuckets, offset):
    """
    Initialize the bucket map assuming the given number of maxBuckets.
    """
    # The first bucket index will be _maxBuckets / 2 and bucket indices will be
    # allowed to grow lower or higher as long as they don't become negative.
    # _maxBuckets is required because the current SDR Classifier assumes bucket
    # indices must be non-negative. This normally does not need to be changed
    # but if altered, should be set to an even number.
    self._maxBuckets = maxBuckets
    self.minIndex = self._maxBuckets / 2
    self.maxIndex = self._maxBuckets / 2

    # The scalar offset used to map scalar values to bucket indices. The middle
    # bucket will correspond to numbers in the range
    # [offset-resolution/2, offset+resolution/2).
    # The bucket index for a number x will be:
    #     maxBuckets/2 + int( round( (x-offset)/resolution ) )
    self._offset = offset

    # This dictionary maps a bucket index into its bit representation
    # We initialize the class with a single bucket with index 0
    self.bucketMap = {}

    def _permutation(n):
      r = numpy.arange(n, dtype=numpy.uint32)
      self.random.shuffle(r)
      return r

    self.bucketMap[self.minIndex] = _permutation(self.n)[0:self.w]

    # How often we need to retry when generating valid encodings
    self.numTries = 0

def _initializeBucketMap ( self , maxBuckets , offset ) : self . _maxBuckets = maxBuckets self . minIndex = self . _maxBuckets / 2 self . maxIndex = self . _maxBuckets / 2 self . _offset = offset self . bucketMap = { } def _permutation ( n ) : r = numpy . arange ( n , dtype = numpy . uint32 ) self . random . shuffle ( r ) return r self . bucketMap [ self . minIndex ] = _permutation ( self . n ) [ 0 : self . w ] self . numTries = 0

Initialize the bucket map assuming the given number of maxBuckets .


def create(*args, **kwargs):
    """
    Create a SDR classifier factory.
    The implementation of the SDR Classifier can be specified with
    the "implementation" keyword argument.

    The SDRClassifierFactory uses the implementation as specified in
     `Default NuPIC Configuration <default-config.html>`_.
    """
    impl = kwargs.pop('implementation', None)
    if impl is None:
      impl = Configuration.get('nupic.opf.sdrClassifier.implementation')
    if impl == 'py':
      return SDRClassifier(*args, **kwargs)
    elif impl == 'cpp':
      return FastSDRClassifier(*args, **kwargs)
    elif impl == 'diff':
      return SDRClassifierDiff(*args, **kwargs)
    else:
      raise ValueError('Invalid classifier implementation (%r). Value must be '
                       '"py", "cpp" or "diff".' % impl)

Create a SDR classifier factory . The implementation of the SDR Classifier can be specified with the implementation keyword argument .


def mmGetMetricFromTrace(self, trace):
    """
    Convenience method to compute a metric over an indices trace, excluding
    resets.

    @param (IndicesTrace) Trace of indices

    @return (Metric) Metric over trace excluding resets
    """
    return Metric.createFromTrace(trace.makeCountsTrace(),
                                  excludeResets=self.mmGetTraceResets())

def mmGetMetricFromTrace ( self , trace ) : return Metric . createFromTrace ( trace . makeCountsTrace ( ) , excludeResets = self . mmGetTraceResets ( ) )

Convenience method to compute a metric over an indices trace excluding resets .


def mmGetMetricSequencesPredictedActiveCellsPerColumn(self):
    """
    Metric for number of predicted => active cells per column for each sequence

    @return (Metric) metric
    """
    self._mmComputeTransitionTraces()

    numCellsPerColumn = []

    for predictedActiveCells in (
        self._mmData["predictedActiveCellsForSequence"].values()):
      cellsForColumn = self.mapCellsToColumns(predictedActiveCells)
      numCellsPerColumn += [len(x) for x in cellsForColumn.values()]

    return Metric(self,
                  "# predicted => active cells per column for each sequence",
                  numCellsPerColumn)

Metric for number of predicted = > active cells per column for each sequence


def mmGetMetricSequencesPredictedActiveCellsShared(self):
    """
    Metric for number of sequences each predicted => active cell appears in

    Note: This metric is flawed when it comes to high-order sequences.

    @return (Metric) metric
    """
    self._mmComputeTransitionTraces()

    numSequencesForCell = defaultdict(lambda: 0)

    for predictedActiveCells in (
          self._mmData["predictedActiveCellsForSequence"].values()):
      for cell in predictedActiveCells:
        numSequencesForCell[cell] += 1

    return Metric(self,
                  "# sequences each predicted => active cells appears in",
                  numSequencesForCell.values())

Metric for number of sequences each predicted = > active cell appears in


def mmPrettyPrintConnections(self):
    """
    Pretty print the connections in the temporal memory.

    TODO: Use PrettyTable.

    @return (string) Pretty-printed text
    """
    text = ""

    text += ("Segments: (format => "
             "(#) [(source cell=permanence ...),       ...]\n")
    text += "------------------------------------\n"

    columns = range(self.numberOfColumns())

    for column in columns:
      cells = self.cellsForColumn(column)

      for cell in cells:
        segmentDict = dict()

        for seg in self.connections.segmentsForCell(cell):
          synapseList = []

          for synapse in self.connections.synapsesForSegment(seg):
            synapseData = self.connections.dataForSynapse(synapse)
            synapseList.append(
                (synapseData.presynapticCell, synapseData.permanence))

          synapseList.sort()
          synapseStringList = ["{0:3}={1:.2f}".format(sourceCell, permanence) for
                               sourceCell, permanence in synapseList]
          segmentDict[seg] = "({0})".format(" ".join(synapseStringList))

        text += ("Column {0:3} / Cell {1:3}:\t({2}) {3}\n".format(
          column, cell,
          len(segmentDict.values()),
          "[{0}]".format(",       ".join(segmentDict.values()))))

      if column < len(columns) - 1:  # not last
        text += "\n"

    text += "------------------------------------\n"

    return text

Pretty print the connections in the temporal memory .


def mmPrettyPrintSequenceCellRepresentations(self, sortby="Column"):
    """
    Pretty print the cell representations for sequences in the history.

    @param sortby (string) Column of table to sort by

    @return (string) Pretty-printed text
    """
    self._mmComputeTransitionTraces()
    table = PrettyTable(["Pattern", "Column", "predicted=>active cells"])

    for sequenceLabel, predictedActiveCells in (
          self._mmData["predictedActiveCellsForSequence"].iteritems()):
      cellsForColumn = self.mapCellsToColumns(predictedActiveCells)
      for column, cells in cellsForColumn.iteritems():
        table.add_row([sequenceLabel, column, list(cells)])

    return table.get_string(sortby=sortby).encode("utf-8")

Pretty print the cell representations for sequences in the history .


def createTemporalAnomaly(recordParams, spatialParams=_SP_PARAMS,
                          temporalParams=_TM_PARAMS,
                          verbosity=_VERBOSITY):

  """Generates a Network with connected RecordSensor, SP, TM.

  This function takes care of generating regions and the canonical links.
  The network has a sensor region reading data from a specified input and
  passing the encoded representation to an SPRegion.
  The SPRegion output is passed to a TMRegion.

  Note: this function returns a network that needs to be initialized. This
  allows the user to extend the network by adding further regions and
  connections.

  :param recordParams: a dict with parameters for creating RecordSensor region.
  :param spatialParams: a dict with parameters for creating SPRegion.
  :param temporalParams: a dict with parameters for creating TMRegion.
  :param verbosity: an integer representing how chatty the network will be.
  """
  inputFilePath = recordParams["inputFilePath"]
  scalarEncoderArgs = recordParams["scalarEncoderArgs"]
  dateEncoderArgs = recordParams["dateEncoderArgs"]

  scalarEncoder = ScalarEncoder(**scalarEncoderArgs)
  dateEncoder = DateEncoder(**dateEncoderArgs)

  encoder = MultiEncoder()
  encoder.addEncoder(scalarEncoderArgs["name"], scalarEncoder)
  encoder.addEncoder(dateEncoderArgs["name"], dateEncoder)

  network = Network()

  network.addRegion("sensor", "py.RecordSensor",
                    json.dumps({"verbosity": verbosity}))

  sensor = network.regions["sensor"].getSelf()
  sensor.encoder = encoder
  sensor.dataSource = FileRecordStream(streamID=inputFilePath)

  # Create the spatial pooler region
  spatialParams["inputWidth"] = sensor.encoder.getWidth()
  network.addRegion("spatialPoolerRegion", "py.SPRegion",
                    json.dumps(spatialParams))

  # Link the SP region to the sensor input
  network.link("sensor", "spatialPoolerRegion", "UniformLink", "")
  network.link("sensor", "spatialPoolerRegion", "UniformLink", "",
               srcOutput="resetOut", destInput="resetIn")
  network.link("spatialPoolerRegion", "sensor", "UniformLink", "",
               srcOutput="spatialTopDownOut", destInput="spatialTopDownIn")
  network.link("spatialPoolerRegion", "sensor", "UniformLink", "",
               srcOutput="temporalTopDownOut", destInput="temporalTopDownIn")

  # Add the TPRegion on top of the SPRegion
  network.addRegion("temporalPoolerRegion", "py.TMRegion",
                    json.dumps(temporalParams))

  network.link("spatialPoolerRegion", "temporalPoolerRegion", "UniformLink", "")
  network.link("temporalPoolerRegion", "spatialPoolerRegion", "UniformLink", "",
               srcOutput="topDownOut", destInput="topDownIn")

  spatialPoolerRegion = network.regions["spatialPoolerRegion"]

  # Make sure learning is enabled
  spatialPoolerRegion.setParameter("learningMode", True)
  # We want temporal anomalies so disable anomalyMode in the SP. This mode is
  # used for computing anomalies in a non-temporal model.
  spatialPoolerRegion.setParameter("anomalyMode", False)

  temporalPoolerRegion = network.regions["temporalPoolerRegion"]

  # Enable topDownMode to get the predicted columns output
  temporalPoolerRegion.setParameter("topDownMode", True)
  # Make sure learning is enabled (this is the default)
  temporalPoolerRegion.setParameter("learningMode", True)
  # Enable inference mode so we get predictions
  temporalPoolerRegion.setParameter("inferenceMode", True)
  # Enable anomalyMode to compute the anomaly score.
  temporalPoolerRegion.setParameter("anomalyMode", True)

  return network

def createTemporalAnomaly ( recordParams , spatialParams = _SP_PARAMS , temporalParams = _TM_PARAMS , verbosity = _VERBOSITY ) : inputFilePath = recordParams [ "inputFilePath" ] scalarEncoderArgs = recordParams [ "scalarEncoderArgs" ] dateEncoderArgs = recordParams [ "dateEncoderArgs" ] scalarEncoder = ScalarEncoder ( ** scalarEncoderArgs ) dateEncoder = DateEncoder ( ** dateEncoderArgs ) encoder = MultiEncoder ( ) encoder . addEncoder ( scalarEncoderArgs [ "name" ] , scalarEncoder ) encoder . addEncoder ( dateEncoderArgs [ "name" ] , dateEncoder ) network = Network ( ) network . addRegion ( "sensor" , "py.RecordSensor" , json . dumps ( { "verbosity" : verbosity } ) ) sensor = network . regions [ "sensor" ] . getSelf ( ) sensor . encoder = encoder sensor . dataSource = FileRecordStream ( streamID = inputFilePath ) spatialParams [ "inputWidth" ] = sensor . encoder . getWidth ( ) network . addRegion ( "spatialPoolerRegion" , "py.SPRegion" , json . dumps ( spatialParams ) ) network . link ( "sensor" , "spatialPoolerRegion" , "UniformLink" , "" ) network . link ( "sensor" , "spatialPoolerRegion" , "UniformLink" , "" , srcOutput = "resetOut" , destInput = "resetIn" ) network . link ( "spatialPoolerRegion" , "sensor" , "UniformLink" , "" , srcOutput = "spatialTopDownOut" , destInput = "spatialTopDownIn" ) network . link ( "spatialPoolerRegion" , "sensor" , "UniformLink" , "" , srcOutput = "temporalTopDownOut" , destInput = "temporalTopDownIn" ) network . addRegion ( "temporalPoolerRegion" , "py.TMRegion" , json . dumps ( temporalParams ) ) network . link ( "spatialPoolerRegion" , "temporalPoolerRegion" , "UniformLink" , "" ) network . link ( "temporalPoolerRegion" , "spatialPoolerRegion" , "UniformLink" , "" , srcOutput = "topDownOut" , destInput = "topDownIn" ) spatialPoolerRegion = network . regions [ "spatialPoolerRegion" ] spatialPoolerRegion . setParameter ( "learningMode" , True ) spatialPoolerRegion . setParameter ( "anomalyMode" , False ) temporalPoolerRegion = network . regions [ "temporalPoolerRegion" ] temporalPoolerRegion . setParameter ( "topDownMode" , True ) temporalPoolerRegion . setParameter ( "learningMode" , True ) temporalPoolerRegion . setParameter ( "inferenceMode" , True ) temporalPoolerRegion . setParameter ( "anomalyMode" , True ) return network

Generates a Network with connected RecordSensor SP TM .


def add(reader, writer, column, start, stop, value):
  """Adds a value over a range of rows.

  Args:
    reader: A FileRecordStream object with input data.
    writer: A FileRecordStream object to write output data to.
    column: The column of data to modify.
    start: The first row in the range to modify.
    end: The last row in the range to modify.
    value: The value to add.
  """
  for i, row in enumerate(reader):
    if i >= start and i <= stop:
      row[column] = type(value)(row[column]) + value
    writer.appendRecord(row)

def add ( reader , writer , column , start , stop , value ) : for i , row in enumerate ( reader ) : if i >= start and i <= stop : row [ column ] = type ( value ) ( row [ column ] ) + value writer . appendRecord ( row )


def scale(reader, writer, column, start, stop, multiple):
  """Multiplies a value over a range of rows.

  Args:
    reader: A FileRecordStream object with input data.
    writer: A FileRecordStream  object to write output data to.
    column: The column of data to modify.
    start: The first row in the range to modify.
    end: The last row in the range to modify.
    multiple: The value to scale/multiply by.
  """
  for i, row in enumerate(reader):
    if i >= start and i <= stop:
      row[column] = type(multiple)(row[column]) * multiple
    writer.appendRecord(row)

def scale ( reader , writer , column , start , stop , multiple ) : for i , row in enumerate ( reader ) : if i >= start and i <= stop : row [ column ] = type ( multiple ) ( row [ column ] ) * multiple writer . appendRecord ( row )

Multiplies a value over a range of rows .


def copy(reader, writer, start, stop, insertLocation=None, tsCol=None):
  """Copies a range of values to a new location in the data set.

  Args:
    reader: A FileRecordStream object with input data.
    writer: A FileRecordStream object to write output data to.
    start: The first row in the range to copy.
    stop: The last row in the range to copy.
    insertLocation: The location to insert the copied range. If not specified,
        the range is inserted immediately following itself.
  """
  assert stop >= start
  startRows = []
  copyRows = []
  ts = None
  inc = None
  if tsCol is None:
    tsCol = reader.getTimestampFieldIdx()
  for i, row in enumerate(reader):
    # Get the first timestamp and the increment.
    if ts is None:
      ts = row[tsCol]
    elif inc is None:
      inc = row[tsCol] - ts
    # Keep a list of all rows and a list of rows to copy.
    if i >= start and i <= stop:
      copyRows.append(row)
    startRows.append(row)
  # Insert the copied rows.
  if insertLocation is None:
    insertLocation = stop + 1
  startRows[insertLocation:insertLocation] = copyRows
  # Update the timestamps.
  for row in startRows:
    row[tsCol] = ts
    writer.appendRecord(row)
    ts += inc

def copy ( reader , writer , start , stop , insertLocation = None , tsCol = None ) : assert stop >= start startRows = [ ] copyRows = [ ] ts = None inc = None if tsCol is None : tsCol = reader . getTimestampFieldIdx ( ) for i , row in enumerate ( reader ) : if ts is None : ts = row [ tsCol ] elif inc is None : inc = row [ tsCol ] - ts if i >= start and i <= stop : copyRows . append ( row ) startRows . append ( row ) if insertLocation is None : insertLocation = stop + 1 startRows [ insertLocation : insertLocation ] = copyRows for row in startRows : row [ tsCol ] = ts writer . appendRecord ( row ) ts += inc

Copies a range of values to a new location in the data set .


def sample(reader, writer, n, start=None, stop=None, tsCol=None,
           writeSampleOnly=True):
  """Samples n rows.

  Args:
    reader: A FileRecordStream object with input data.
    writer: A FileRecordStream object to write output data to.
    n: The number of elements to sample.
    start: The first row in the range to sample from.
    stop: The last row in the range to sample from.
    tsCol: If specified, the timestamp column to update.
    writeSampleOnly: If False, the rows before start are written before the
        sample and the rows after stop are written after the sample.
  """
  rows = list(reader)
  if tsCol is not None:
    ts = rows[0][tsCol]
    inc = rows[1][tsCol] - ts
  if start is None:
    start = 0
  if stop is None:
    stop = len(rows) - 1
  initialN = stop - start + 1
  # Select random rows in the sample range to delete until the desired number
  # of rows are left.
  numDeletes =  initialN - n
  for i in xrange(numDeletes):
    delIndex = random.randint(start, stop - i)
    del rows[delIndex]
  # Remove outside rows if specified.
  if writeSampleOnly:
    rows = rows[start:start + n]
  # Rewrite columns if tsCol is given.
  if tsCol is not None:
    ts = rows[0][tsCol]
  # Write resulting rows.
  for row in rows:
    if tsCol is not None:
      row[tsCol] = ts
      ts += inc
    writer.appendRecord(row)

def sample ( reader , writer , n , start = None , stop = None , tsCol = None , writeSampleOnly = True ) : rows = list ( reader ) if tsCol is not None : ts = rows [ 0 ] [ tsCol ] inc = rows [ 1 ] [ tsCol ] - ts if start is None : start = 0 if stop is None : stop = len ( rows ) - 1 initialN = stop - start + 1 numDeletes = initialN - n for i in xrange ( numDeletes ) : delIndex = random . randint ( start , stop - i ) del rows [ delIndex ] if writeSampleOnly : rows = rows [ start : start + n ] if tsCol is not None : ts = rows [ 0 ] [ tsCol ] for row in rows : if tsCol is not None : row [ tsCol ] = ts ts += inc writer . appendRecord ( row )


def _getFirstOnBit(self, input):
    """ Return the bit offset of the first bit to be set in the encoder output.
    For periodic encoders, this can be a negative number when the encoded output
    wraps around. """

    if input == SENTINEL_VALUE_FOR_MISSING_DATA:
      return [None]

    else:
      if input < self.minval:
        # Don't clip periodic inputs. Out-of-range input is always an error
        if self.clipInput and not self.periodic:
          if self.verbosity > 0:
            print "Clipped input %s=%.2f to minval %.2f" % (self.name, input,
                                                            self.minval)
          input = self.minval
        else:
          raise Exception('input (%s) less than range (%s - %s)' %
                          (str(input), str(self.minval), str(self.maxval)))

      if self.periodic:
        # Don't clip periodic inputs. Out-of-range input is always an error
        if input >= self.maxval:
          raise Exception('input (%s) greater than periodic range (%s - %s)' %
                          (str(input), str(self.minval), str(self.maxval)))
      else:
        if input > self.maxval:
          if self.clipInput:
            if self.verbosity > 0:
              print "Clipped input %s=%.2f to maxval %.2f" % (self.name, input,
                                                              self.maxval)
            input = self.maxval
          else:
            raise Exception('input (%s) greater than range (%s - %s)' %
                            (str(input), str(self.minval), str(self.maxval)))

      if self.periodic:
        centerbin = int((input - self.minval) * self.nInternal / self.range) \
                      + self.padding
      else:
        centerbin = int(((input - self.minval) + self.resolution/2) \
                          / self.resolution ) + self.padding

      # We use the first bit to be set in the encoded output as the bucket index
      minbin = centerbin - self.halfwidth
      return [minbin]

Return the bit offset of the first bit to be set in the encoder output . For periodic encoders this can be a negative number when the encoded output wraps around .


def _generateRangeDescription(self, ranges):
    """generate description from a text description of the ranges"""
    desc = ""
    numRanges = len(ranges)
    for i in xrange(numRanges):
      if ranges[i][0] != ranges[i][1]:
        desc += "%.2f-%.2f" % (ranges[i][0], ranges[i][1])
      else:
        desc += "%.2f" % (ranges[i][0])
      if i < numRanges - 1:
        desc += ", "
    return desc

def
_generateRangeDescription
(
self
,
ranges
)
:
desc
=
""
numRanges
=
len
(
ranges
)
for
i
in
xrange
(
numRanges
)
:
if
ranges
[
i
]
[
0
]
!=
ranges
[
i
]
[
1
]
:
desc
+=
"%.2f-%.2f"
%
(
ranges
[
i
]
[
0
]
,
ranges
[
i
]
[
1
]
)
else
:
desc
+=
"%.2f"
%
(
ranges
[
i
]
[
0
]
)
if
i
<
numRanges
1
:
desc
+=
", "
return
desc


def reset(self,):
    """
    Reset the state of all cells.

    This is normally used between sequences while training. All internal states
    are reset to 0.
    """
    if self.verbosity >= 3:
      print "\n==== RESET ====="

    self.lrnActiveState['t-1'].fill(0)
    self.lrnActiveState['t'].fill(0)
    self.lrnPredictedState['t-1'].fill(0)
    self.lrnPredictedState['t'].fill(0)

    self.infActiveState['t-1'].fill(0)
    self.infActiveState['t'].fill(0)
    self.infPredictedState['t-1'].fill(0)
    self.infPredictedState['t'].fill(0)

    self.cellConfidence['t-1'].fill(0)
    self.cellConfidence['t'].fill(0)

    # Flush the segment update queue
    self.segmentUpdates = {}

    self._internalStats['nInfersSinceReset'] = 0

    #To be removed
    self._internalStats['curPredictionScore'] = 0
    #New prediction score
    self._internalStats['curPredictionScore2']   = 0
    self._internalStats['curFalseNegativeScore'] = 0
    self._internalStats['curFalsePositiveScore'] = 0

    self._internalStats['curMissing'] = 0
    self._internalStats['curExtra'] = 0

    # When a reset occurs, set prevSequenceSignature to the signature of the
    # just-completed sequence and start accumulating histogram for the next
    # sequence.
    self._internalStats['prevSequenceSignature'] = None
    if self.collectSequenceStats:
      if self._internalStats['confHistogram'].sum() > 0:
        sig = self._internalStats['confHistogram'].copy()
        sig.reshape(self.numberOfCols * self.cellsPerColumn)
        self._internalStats['prevSequenceSignature'] = sig
      self._internalStats['confHistogram'].fill(0)

    self.resetCalled = True

    # Clear out input history
    self._prevInfPatterns = []
    self._prevLrnPatterns = []

def
reset
(
self
,
)
:
if
self
.
verbosity
>=
3
:
print
"\n==== RESET ====="
self
.
lrnActiveState
[
't-1'
]
.
fill
(
0
)
self
.
lrnActiveState
[
't'
]
.
fill
(
0
)
self
.
lrnPredictedState
[
't-1'
]
.
fill
(
0
)
self
.
lrnPredictedState
[
't'
]
.
fill
(
0
)
self
.
infActiveState
[
't-1'
]
.
fill
(
0
)
self
.
infActiveState
[
't'
]
.
fill
(
0
)
self
.
infPredictedState
[
't-1'
]
.
fill
(
0
)
self
.
infPredictedState
[
't'
]
.
fill
(
0
)
self
.
cellConfidence
[
't-1'
]
.
fill
(
0
)
self
.
cellConfidence
[
't'
]
.
fill
(
0
)
self
.
segmentUpdates
=
{
}
self
.
_internalStats
[
'nInfersSinceReset'
]
=
0
self
.
_internalStats
[
'curPredictionScore'
]
=
0
self
.
_internalStats
[
'curPredictionScore2'
]
=
0
self
.
_internalStats
[
'curFalseNegativeScore'
]
=
0
self
.
_internalStats
[
'curFalsePositiveScore'
]
=
0
self
.
_internalStats
[
'curMissing'
]
=
0
self
.
_internalStats
[
'curExtra'
]
=
0
self
.
_internalStats
[
'prevSequenceSignature'
]
=
if
self
.
collectSequenceStats
:
if
self
.
_internalStats
[
'confHistogram'
]
.
sum
(
)
>
0
:
sig
=
self
.
_internalStats
[
'confHistogram'
]
.
copy
(
)
sig
.
reshape
(
self
.
numberOfCols
*
self
.
cellsPerColumn
)
self
.
_internalStats
[
'prevSequenceSignature'
]
=
sig
self
.
_internalStats
[
'confHistogram'
]
.
fill
(
0
)
self
.
resetCalled
=
True
self
.
_prevInfPatterns
=
[
]
self
.
_prevLrnPatterns
=
[
]


def _updateStatsInferEnd(self, stats, bottomUpNZ, predictedState,
                           colConfidence):
    """
    Called at the end of learning and inference, this routine will update
    a number of stats in our _internalStats dictionary, including our computed
    prediction score.

    :param stats            internal stats dictionary
    :param bottomUpNZ       list of the active bottom-up inputs
    :param predictedState   The columns we predicted on the last time step (should
                            match the current bottomUpNZ in the best case)
    :param colConfidence    Column confidences we determined on the last time step
    """
    # Return if not collecting stats
    if not self.collectStats:
      return
    stats['nInfersSinceReset'] += 1

    # Compute the prediction score, how well the prediction from the last
    # time step predicted the current bottom-up input
    (numExtra2, numMissing2, confidences2) = self._checkPrediction(
        patternNZs=[bottomUpNZ], output=predictedState,
        colConfidence=colConfidence)
    predictionScore, positivePredictionScore, negativePredictionScore = (
        confidences2[0])

    # Store the stats that don't depend on burn-in
    stats['curPredictionScore2'] = float(predictionScore)
    stats['curFalseNegativeScore'] = 1.0 - float(positivePredictionScore)
    stats['curFalsePositiveScore'] = float(negativePredictionScore)

    stats['curMissing'] = numMissing2
    stats['curExtra'] = numExtra2

    # If we are passed the burn-in period, update the accumulated stats
    # Here's what various burn-in values mean:
    #   0: try to predict the first element of each sequence and all subsequent
    #   1: try to predict the second element of each sequence and all subsequent
    #   etc.
    if stats['nInfersSinceReset'] <= self.burnIn:
      return

    # Burn-in related stats
    stats['nPredictions'] += 1
    numExpected = max(1.0, float(len(bottomUpNZ)))

    stats['totalMissing'] += numMissing2
    stats['totalExtra'] += numExtra2
    stats['pctExtraTotal'] += 100.0 * numExtra2 / numExpected
    stats['pctMissingTotal'] += 100.0 * numMissing2 / numExpected
    stats['predictionScoreTotal2'] += float(predictionScore)
    stats['falseNegativeScoreTotal'] += 1.0 - float(positivePredictionScore)
    stats['falsePositiveScoreTotal'] += float(negativePredictionScore)

    if self.collectSequenceStats:
      # Collect cell confidences for every cell that correctly predicted current
      # bottom up input. Normalize confidence across each column
      cc = self.cellConfidence['t-1'] * self.infActiveState['t']
      sconf = cc.sum(axis=1)
      for c in range(self.numberOfCols):
        if sconf[c] > 0:
          cc[c, :] /= sconf[c]

      # Update cell confidence histogram: add column-normalized confidence
      # scores to the histogram
      self._internalStats['confHistogram'] += cc

def _updateStatsInferEnd ( self , stats , bottomUpNZ , predictedState , colConfidence ) : if not self . collectStats : return stats [ 'nInfersSinceReset' ] += 1 ( numExtra2 , numMissing2 , confidences2 ) = self . _checkPrediction ( patternNZs = [ bottomUpNZ ] , output = predictedState , colConfidence = colConfidence ) predictionScore , positivePredictionScore , negativePredictionScore = ( confidences2 [ 0 ] ) stats [ 'curPredictionScore2' ] = float ( predictionScore ) stats [ 'curFalseNegativeScore' ] = 1.0 - float ( positivePredictionScore ) stats [ 'curFalsePositiveScore' ] = float ( negativePredictionScore ) stats [ 'curMissing' ] = numMissing2 stats [ 'curExtra' ] = numExtra2 if stats [ 'nInfersSinceReset' ] <= self . burnIn : return stats [ 'nPredictions' ] += 1 numExpected = max ( 1.0 , float ( len ( bottomUpNZ ) ) ) stats [ 'totalMissing' ] += numMissing2 stats [ 'totalExtra' ] += numExtra2 stats [ 'pctExtraTotal' ] += 100.0 * numExtra2 / numExpected stats [ 'pctMissingTotal' ] += 100.0 * numMissing2 / numExpected stats [ 'predictionScoreTotal2' ] += float ( predictionScore ) stats [ 'falseNegativeScoreTotal' ] += 1.0 - float ( positivePredictionScore ) stats [ 'falsePositiveScoreTotal' ] += float ( negativePredictionScore ) if self . collectSequenceStats : cc = self . cellConfidence [ 't-1' ] * self . infActiveState [ 't' ] sconf = cc . sum ( axis = 1 ) for c in range ( self . numberOfCols ) : if sconf [ c ] > 0 : cc [ c , : ] /= sconf [ c ] self . _internalStats [ 'confHistogram' ] += cc

Called at the end of learning and inference this routine will update a number of stats in our _internalStats dictionary including our computed prediction score .


def printState(self, aState):
    """
    Print an integer array that is the same shape as activeState.

    :param aState: TODO: document
    """
    def formatRow(var, i):
      s = ''
      for c in range(self.numberOfCols):
        if c > 0 and c % 10 == 0:
          s += ' '
        s += str(var[c, i])
      s += ' '
      return s

    for i in xrange(self.cellsPerColumn):
      print formatRow(aState, i)

def
printState
(
self
,
aState
)
:
def
formatRow
(
var
,
i
)
:
s
=
''
for
c
in
range
(
self
.
numberOfCols
)
:
if
c
>
0
and
c
%
10
==
0
:
s
+=
' '
s
+=
str
(
var
[
c
,
i
]
)
s
+=
' '
return
s
for
i
in
xrange
(
self
.
cellsPerColumn
)
:
print
formatRow
(
aState
,
i
)

Print an integer array that is the same shape as activeState .


def printConfidence(self, aState, maxCols = 20):
    """
    Print a floating point array that is the same shape as activeState.

    :param aState: TODO: document
    :param maxCols: TODO: document
    """
    def formatFPRow(var, i):
      s = ''
      for c in range(min(maxCols, self.numberOfCols)):
        if c > 0 and c % 10 == 0:
          s += '   '
        s += ' %5.3f' % var[c, i]
      s += ' '
      return s

    for i in xrange(self.cellsPerColumn):
      print formatFPRow(aState, i)

def
printConfidence
(
self
,
aState
,
maxCols
=
20
)
:
def
formatFPRow
(
var
,
i
)
:
s
=
''
for
c
in
range
(
min
(
maxCols
,
self
.
numberOfCols
)
)
:
if
c
>
0
and
c
%
10
==
0
:
s
+=
'   '
s
+=
' %5.3f'
%
var
[
c
,
i
]
s
+=
' '
return
s
for
i
in
xrange
(
self
.
cellsPerColumn
)
:
print
formatFPRow
(
aState
,
i
)

Print a floating point array that is the same shape as activeState .


def printColConfidence(self, aState, maxCols = 20):
    """
    Print up to maxCols number from a flat floating point array.

    :param aState: TODO: document
    :param maxCols: TODO: document
    """
    def formatFPRow(var):
      s = ''
      for c in range(min(maxCols, self.numberOfCols)):
        if c > 0 and c % 10 == 0:
          s += '   '
        s += ' %5.3f' % var[c]
      s += ' '
      return s

    print formatFPRow(aState)

def
printColConfidence
(
self
,
aState
,
maxCols
=
20
)
:
def
formatFPRow
(
var
)
:
s
=
''
for
c
in
range
(
min
(
maxCols
,
self
.
numberOfCols
)
)
:
if
c
>
0
and
c
%
10
==
0
:
s
+=
'   '
s
+=
' %5.3f'
%
var
[
c
]
s
+=
' '
return
s
print
formatFPRow
(
aState
)

Print up to maxCols number from a flat floating point array .


def printParameters(self):
    """
    Print the parameter settings for the TM.
    """
    print "numberOfCols=", self.numberOfCols
    print "cellsPerColumn=", self.cellsPerColumn
    print "minThreshold=", self.minThreshold
    print "newSynapseCount=", self.newSynapseCount
    print "activationThreshold=", self.activationThreshold
    print
    print "initialPerm=", self.initialPerm
    print "connectedPerm=", self.connectedPerm
    print "permanenceInc=", self.permanenceInc
    print "permanenceDec=", self.permanenceDec
    print "permanenceMax=", self.permanenceMax
    print "globalDecay=", self.globalDecay
    print
    print "doPooling=", self.doPooling
    print "segUpdateValidDuration=", self.segUpdateValidDuration
    print "pamLength=", self.pamLength

def printParameters ( self ) : print "numberOfCols=" , self . numberOfCols print "cellsPerColumn=" , self . cellsPerColumn print "minThreshold=" , self . minThreshold print "newSynapseCount=" , self . newSynapseCount print "activationThreshold=" , self . activationThreshold print print "initialPerm=" , self . initialPerm print "connectedPerm=" , self . connectedPerm print "permanenceInc=" , self . permanenceInc print "permanenceDec=" , self . permanenceDec print "permanenceMax=" , self . permanenceMax print "globalDecay=" , self . globalDecay print print "doPooling=" , self . doPooling print "segUpdateValidDuration=" , self . segUpdateValidDuration print "pamLength=" , self . pamLength

Print the parameter settings for the TM .


def printComputeEnd(self, output, learn=False):
    """
    Called at the end of inference to print out various diagnostic
    information based on the current verbosity level.

    :param output: TODO: document
    :param learn: TODO: document
    """
    if self.verbosity >= 3:
      print "----- computeEnd summary: "
      print "learn:", learn
      print "numBurstingCols: %s, " % (
          self.infActiveState['t'].min(axis=1).sum()),
      print "curPredScore2: %s, " % (
          self._internalStats['curPredictionScore2']),
      print "curFalsePosScore: %s, " % (
          self._internalStats['curFalsePositiveScore']),
      print "1-curFalseNegScore: %s, " % (
          1 - self._internalStats['curFalseNegativeScore'])
      print "numSegments: ", self.getNumSegments(),
      print "avgLearnedSeqLength: ", self.avgLearnedSeqLength

      print "----- infActiveState (%d on) ------" % (
          self.infActiveState['t'].sum())
      self.printActiveIndices(self.infActiveState['t'])
      if self.verbosity >= 6:
        self.printState(self.infActiveState['t'])

      print "----- infPredictedState (%d on)-----" % (
          self.infPredictedState['t'].sum())
      self.printActiveIndices(self.infPredictedState['t'])
      if self.verbosity >= 6:
        self.printState(self.infPredictedState['t'])

      print "----- lrnActiveState (%d on) ------" % (
          self.lrnActiveState['t'].sum())
      self.printActiveIndices(self.lrnActiveState['t'])
      if self.verbosity >= 6:
        self.printState(self.lrnActiveState['t'])

      print "----- lrnPredictedState (%d on)-----" % (
          self.lrnPredictedState['t'].sum())
      self.printActiveIndices(self.lrnPredictedState['t'])
      if self.verbosity >= 6:
        self.printState(self.lrnPredictedState['t'])

      print "----- cellConfidence -----"
      self.printActiveIndices(self.cellConfidence['t'], andValues=True)
      if self.verbosity >= 6:
        self.printConfidence(self.cellConfidence['t'])

      print "----- colConfidence -----"
      self.printActiveIndices(self.colConfidence['t'], andValues=True)

      print "----- cellConfidence[t-1] for currently active cells -----"
      cc = self.cellConfidence['t-1'] * self.infActiveState['t']
      self.printActiveIndices(cc, andValues=True)

      if self.verbosity == 4:
        print "Cells, predicted segments only:"
        self.printCells(predictedOnly=True)
      elif self.verbosity >= 5:
        print "Cells, all segments:"
        self.printCells(predictedOnly=False)
      print

    elif self.verbosity >= 1:
      print "TM: learn:", learn
      print "TM: active outputs(%d):" % len(output.nonzero()[0]),
      self.printActiveIndices(output.reshape(self.numberOfCols,
                                             self.cellsPerColumn))

Called at the end of inference to print out various diagnostic information based on the current verbosity level .


def _updateAvgLearnedSeqLength(self, prevSeqLength):
    """Update our moving average of learned sequence length."""
    if self.lrnIterationIdx < 100:
      alpha = 0.5
    else:
      alpha = 0.1

    self.avgLearnedSeqLength = ((1.0 - alpha) * self.avgLearnedSeqLength +
                                (alpha * prevSeqLength))

def _updateAvgLearnedSeqLength ( self , prevSeqLength ) : if self . lrnIterationIdx < 100 : alpha = 0.5 else : alpha = 0.1 self . avgLearnedSeqLength = ( ( 1.0 - alpha ) * self . avgLearnedSeqLength + ( alpha * prevSeqLength ) )

Update our moving average of learned sequence length .


def _inferPhase1(self, activeColumns, useStartCells):
    """
    Update the inference active state from the last set of predictions
    and the current bottom-up.

    This looks at:
        - ``infPredictedState['t-1']``
    This modifies:
        - ``infActiveState['t']``

    :param activeColumns: (list) active bottom-ups
    :param useStartCells: (bool) If true, ignore previous predictions and simply
           turn on the start cells in the active columns
    :returns: (bool) True if the current input was sufficiently predicted, OR if
           we started over on startCells. False indicates that the current input
           was NOT predicted, and we are now bursting on most columns.
    """
    # Init to zeros to start
    self.infActiveState['t'].fill(0)

    # Phase 1 - turn on predicted cells in each column receiving bottom-up
    # If we are following a reset, activate only the start cell in each
    # column that has bottom-up
    numPredictedColumns = 0
    if useStartCells:
      for c in activeColumns:
        self.infActiveState['t'][c, 0] = 1

    # else, turn on any predicted cells in each column. If there are none, then
    # turn on all cells (burst the column)
    else:
      for c in activeColumns:
        predictingCells = numpy.where(self.infPredictedState['t-1'][c] == 1)[0]
        numPredictingCells = len(predictingCells)

        if numPredictingCells > 0:
          self.infActiveState['t'][c, predictingCells] = 1
          numPredictedColumns += 1

        else:
          self.infActiveState['t'][c, :] = 1 # whole column bursts

    # Did we predict this input well enough?
    if useStartCells or numPredictedColumns >= 0.50 * len(activeColumns):
      return True
    else:
      return False

def _inferPhase1 ( self , activeColumns , useStartCells ) : self . infActiveState [ 't' ] . fill ( 0 ) numPredictedColumns = 0 if useStartCells : for c in activeColumns : self . infActiveState [ 't' ] [ c , 0 ] = 1 else : for c in activeColumns : predictingCells = numpy . where ( self . infPredictedState [ 't-1' ] [ c ] == 1 ) [ 0 ] numPredictingCells = len ( predictingCells ) if numPredictingCells > 0 : self . infActiveState [ 't' ] [ c , predictingCells ] = 1 numPredictedColumns += 1 else : self . infActiveState [ 't' ] [ c , : ] = 1 if useStartCells or numPredictedColumns >= 0.50 * len ( activeColumns ) : return True else : return False

Update the inference active state from the last set of predictions and the current bottom - up .


def _inferPhase2(self):
    """
    Phase 2 for the inference state. The computes the predicted state, then
    checks to insure that the predicted state is not over-saturated, i.e.
    look too close like a burst. This indicates that there were so many
    separate paths learned from the current input columns to the predicted
    input columns that bursting on the current input columns is most likely
    generated mix and match errors on cells in the predicted columns. If
    we detect this situation, we instead turn on only the start cells in the
    current active columns and re-generate the predicted state from those.

    This looks at:
        - `` infActiveState['t']``

    This modifies:
        - `` infPredictedState['t']``
        - `` colConfidence['t']``
        - `` cellConfidence['t']``

    :returns: (bool) True if we have a decent guess as to the next input.
              Returning False from here indicates to the caller that we have
              reached the end of a learned sequence.
    """
    # Init to zeros to start
    self.infPredictedState['t'].fill(0)
    self.cellConfidence['t'].fill(0)
    self.colConfidence['t'].fill(0)

    # Phase 2 - Compute new predicted state and update cell and column
    #   confidences
    for c in xrange(self.numberOfCols):

      # For each cell in the column
      for i in xrange(self.cellsPerColumn):

        # For each segment in the cell
        for s in self.cells[c][i]:

          # See if it has the min number of active synapses
          numActiveSyns = self._getSegmentActivityLevel(
              s, self.infActiveState['t'], connectedSynapsesOnly=False)
          if numActiveSyns < self.activationThreshold:
            continue

          # Incorporate the confidence into the owner cell and column
          if self.verbosity >= 6:
            print "incorporating DC from cell[%d,%d]:   " % (c, i),
            s.debugPrint()
          dc = s.dutyCycle()
          self.cellConfidence['t'][c, i] += dc
          self.colConfidence['t'][c] += dc

          # If we reach threshold on the connected synapses, predict it
          # If not active, skip over it
          if self._isSegmentActive(s, self.infActiveState['t']):
            self.infPredictedState['t'][c, i] = 1

    # Normalize column and cell confidences
    sumConfidences = self.colConfidence['t'].sum()
    if sumConfidences > 0:
      self.colConfidence['t'] /= sumConfidences
      self.cellConfidence['t'] /= sumConfidences

    # Are we predicting the required minimum number of columns?
    numPredictedCols = self.infPredictedState['t'].max(axis=1).sum()
    if numPredictedCols >= 0.5 * self.avgInputDensity:
      return True
    else:
      return False

def
_inferPhase2
(
self
)
:
self
.
infPredictedState
[
't'
]
.
fill
(
0
)
self
.
cellConfidence
[
't'
]
.
fill
(
0
)
self
.
colConfidence
[
't'
]
.
fill
(
0
)
for
c
in
xrange
(
self
.
numberOfCols
)
:
for
i
in
xrange
(
self
.
cellsPerColumn
)
:
for
s
in
self
.
cells
[
c
]
[
i
]
:
numActiveSyns
=
self
.
_getSegmentActivityLevel
(
s
,
self
.
infActiveState
[
't'
]
,
connectedSynapsesOnly
=
False
)
if
numActiveSyns
<
self
.
activationThreshold
:
continue
if
self
.
verbosity
>=
6
:
print
"incorporating DC from cell[%d,%d]:   "
%
(
c
,
i
)
,
s
.
debugPrint
(
)
dc
=
s
.
dutyCycle
(
)
self
.
cellConfidence
[
't'
]
[
c
,
i
]
+=
dc
self
.
colConfidence
[
't'
]
[
c
]
+=
dc
if
self
.
_isSegmentActive
(
s
,
self
.
infActiveState
[
't'
]
)
:
self
.
infPredictedState
[
't'
]
[
c
,
i
]
=
1
sumConfidences
=
self
.
colConfidence
[
't'
]
.
sum
(
)
if
sumConfidences
>
0
:
self
.
colConfidence
[
't'
]
/=
sumConfidences
self
.
cellConfidence
[
't'
]
/=
sumConfidences
numPredictedCols
=
self
.
infPredictedState
[
't'
]
.
max
(
axis
=
1
)
.
sum
(
)
if
numPredictedCols
>=
0.5
*
self
.
avgInputDensity
:
return
True
else
:
return
False

Phase 2 for the inference state . The computes the predicted state then checks to insure that the predicted state is not over - saturated i . e . look too close like a burst . This indicates that there were so many separate paths learned from the current input columns to the predicted input columns that bursting on the current input columns is most likely generated mix and match errors on cells in the predicted columns . If we detect this situation we instead turn on only the start cells in the current active columns and re - generate the predicted state from those .


def _learnBacktrackFrom(self, startOffset, readOnly=True):
    """
    A utility method called from learnBacktrack. This will backtrack
    starting from the given startOffset in our prevLrnPatterns queue.

    It returns True if the backtrack was successful and we managed to get
    predictions all the way up to the current time step.

    If readOnly, then no segments are updated or modified, otherwise, all
    segment updates that belong to the given path are applied.

    This updates/modifies:

        - lrnActiveState['t']

    This trashes:

        - lrnPredictedState['t']
        - lrnPredictedState['t-1']
        - lrnActiveState['t-1']

    :param startOffset: Start offset within the prevLrnPatterns input history
    :param readOnly:
    :return: True if we managed to lock on to a sequence that started
                       earlier.
                       If False, we lost predictions somewhere along the way
                       leading up to the current time.
    """
    # How much input history have we accumulated?
    # The current input is always at the end of self._prevInfPatterns (at
    # index -1), but it is also evaluated as a potential starting point by
    # turning on it's start cells and seeing if it generates sufficient
    # predictions going forward.
    numPrevPatterns = len(self._prevLrnPatterns)

    # This is an easy to use label for the current time step
    currentTimeStepsOffset = numPrevPatterns - 1

    # Clear out any old segment updates. learnPhase2() adds to the segment
    # updates if we're not readOnly
    if not readOnly:
      self.segmentUpdates = {}

    # Status message
    if self.verbosity >= 3:
      if readOnly:
        print (
            "Trying to lock-on using startCell state from %d steps ago:" % (
                numPrevPatterns - 1 - startOffset),
            self._prevLrnPatterns[startOffset])
      else:
        print (
            "Locking on using startCell state from %d steps ago:" % (
                numPrevPatterns - 1 - startOffset),
            self._prevLrnPatterns[startOffset])

    # Play through up to the current time step
    inSequence = True
    for offset in range(startOffset, numPrevPatterns):

      # Copy predicted and active states into t-1
      self.lrnPredictedState['t-1'][:, :] = self.lrnPredictedState['t'][:, :]
      self.lrnActiveState['t-1'][:, :] = self.lrnActiveState['t'][:, :]

      # Get the input pattern
      inputColumns = self._prevLrnPatterns[offset]

      # Apply segment updates from the last set of predictions
      if not readOnly:
        self._processSegmentUpdates(inputColumns)

      # Phase 1:
      # Compute activeState[t] given bottom-up and predictedState[t-1]
      if offset == startOffset:
        self.lrnActiveState['t'].fill(0)
        for c in inputColumns:
          self.lrnActiveState['t'][c, 0] = 1
        inSequence = True
      else:
        # Uses lrnActiveState['t-1'] and lrnPredictedState['t-1']
        # computes lrnActiveState['t']
        inSequence = self._learnPhase1(inputColumns, readOnly=readOnly)

      # Break out immediately if we fell out of sequence or reached the current
      # time step
      if not inSequence or offset == currentTimeStepsOffset:
        break

      # Phase 2:
      # Computes predictedState['t'] given activeState['t'] and also queues
      # up active segments into self.segmentUpdates, unless this is readOnly
      if self.verbosity >= 3:
        print "  backtrack: computing predictions from ", inputColumns
      self._learnPhase2(readOnly=readOnly)

    # Return whether or not this starting point was valid
    return inSequence

A utility method called from learnBacktrack . This will backtrack starting from the given startOffset in our prevLrnPatterns queue .