#!/usr/bin/env python
# ----------------------------------------------------------------------
# Numenta Platform for Intelligent Computing (NuPIC)
# Copyright (C) 2014, Numenta, Inc.  Unless you have an agreement
# with Numenta, Inc., for a separate license for this software code, the
# following terms and conditions apply:
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see http://www.gnu.org/licenses.
#
# http://numenta.org/licenses/
# ----------------------------------------------------------------------

import unittest

from sensorimotor.one_d_world import OneDWorld
from sensorimotor.one_d_universe import OneDUniverse
from sensorimotor.random_one_d_agent import RandomOneDAgent

from sensorimotor.sensorimotor_experiment_runner import (
  SensorimotorExperimentRunner
)



class TemporalPoolerMonitorMixinTest(unittest.TestCase):

  VERBOSITY = 1


  def setUp(self):
    # Initialize the universe, worlds, and agents
    nElements = 5
    wEncoders = 7
    universe = OneDUniverse(debugSensor=True,
                            debugMotor=True,
                            nSensor=nElements*wEncoders, wSensor=wEncoders,
                            nMotor=wEncoders*7, wMotor=wEncoders)
    self.agents = [
      RandomOneDAgent(OneDWorld(universe, range(nElements)), 4,
                      possibleMotorValues=(-1,1), seed=23),
      RandomOneDAgent(OneDWorld(universe, list(reversed(range(nElements)))), 4,
                      possibleMotorValues=(-1,1), seed=23)
    ]

    self.experimentRunner = SensorimotorExperimentRunner(
      tmOverrides={
        "columnDimensions": [nElements*wEncoders],
        "minThreshold": wEncoders*2,
        "maxNewSynapseCount": wEncoders*2,
        "activationThreshold": wEncoders*2
      },
      tpOverrides={
        "columnDimensions": [512],
        "numActiveColumnsPerInhArea": 20
      }
    )


  def testGetConfusionMetrics(self):
    # Train
    sequences = self.experimentRunner.generateSequences(40, self.agents)
    self.experimentRunner.feedLayers(sequences, tmLearn=True, tpLearn=True,
                                     verbosity=self.VERBOSITY)

    self._printInformation()

    self.assertEqual(
      self.experimentRunner.tp.mmGetMetricStabilityConfusion().min, 0)
    self.assertEqual(
      self.experimentRunner.tp.mmGetMetricStabilityConfusion().max, 40)
    self.assertTrue(
      self.experimentRunner.tp.mmGetMetricStabilityConfusion().mean > 0)

    self.assertTrue(
      self.experimentRunner.tp.mmGetMetricDistinctnessConfusion().min > 20)
    self.assertTrue(
      self.experimentRunner.tp.mmGetMetricDistinctnessConfusion().max > 20)
    self.assertTrue(
      self.experimentRunner.tp.mmGetMetricDistinctnessConfusion().mean > 20)

    # Test
    sequences = self.experimentRunner.generateSequences(10, self.agents)
    self.experimentRunner.feedLayers(sequences, tmLearn=False, tpLearn=False,
                                     verbosity=self.VERBOSITY)

    self._printInformation()

    self.assertEqual(
      self.experimentRunner.tp.mmGetMetricStabilityConfusion().sum, 0)

    self.assertTrue(
      self.experimentRunner.tp.mmGetMetricDistinctnessConfusion().sum < 12)


  def _printInformation(self):
    if self.VERBOSITY > 1:
      print "Stability"
      print "============"
      print
      print self.experimentRunner.tp.mmPrettyPrintDataStabilityConfusion()
      print
      print "Distinctness"
      print "============"
      print
      print self.experimentRunner.tp.mmPrettyPrintDataDistinctnessConfusion()
      print
      print "Metrics"
      print "============"
      print
      print self.experimentRunner.tp.mmPrettyPrintMetrics(
        self.experimentRunner.tp.mmGetDefaultMetrics())


if __name__ == "__main__":
  unittest.main()

@@ -1432,27 +1432,48 @@
 s = 
-5
+4
 %0A    
-wEncoders = 7
+nWorlds = 3%0A    n = 512%0A    w = 20
 %0A   
@@ -1518,36 +1518,8 @@
 rue,
-%0A                           
  deb
@@ -1569,34 +1569,16 @@
 Sensor=n
-Elements*wEncoders
 , wSenso
@@ -1580,24 +1580,16 @@
 Sensor=w
-Encoders
 ,%0A      
@@ -1621,19 +1621,9 @@
 tor=
-wEncoders*7
+n
 , wM
@@ -1628,24 +1628,16 @@
 wMotor=w
-Encoders
 )%0A    se
@@ -1649,23 +1649,16 @@
 ents = %5B
-%0A      
 RandomOn
@@ -1669,191 +1669,171 @@
 ent(
-OneDWorld(universe, range(nElements)), 4,%0A                      possibleMotorValues=(-1,1), seed=23),%0A      RandomOneDAgent(OneDWorld(universe, list(reversed(range(nElements)))), 4
+%0A                     OneDWorld(%0A                       universe,%0A                       range(nElements * world, nElements * (world+1))),%0A                     0
 ,%0A
- 
     
@@ -1880,22 +1880,67 @@
 ,1),
- seed=23)%0A    
+%0A                     seed=23) for world in xrange(nWorlds)
 %5D%0A%0A 
@@ -2050,26 +2050,8 @@
 : %5Bn
-Elements*wEncoders
 %5D,%0A 
@@ -2070,32 +2070,24 @@
 hreshold%22: w
-Encoders
 *2,%0A        
@@ -2109,24 +2109,16 @@
 ount%22: w
-Encoders
 *2,%0A    
@@ -2149,17 +2149,29 @@
 %22: w
-Encoders*
+*2,%0A        %22seed%22: 4
 2%0A  
@@ -2226,19 +2226,17 @@
 ions%22: %5B
-512
+n
 %5D,%0A     
@@ -2268,18 +2268,37 @@
 hArea%22: 
+w,%0A        %22seed%22: 4
 2
-0
 %0A      %7D
@@ -2411,17 +2411,17 @@
 quences(
-4
+3
 0, self.
@@ -2971,17 +2971,17 @@
 n().min 
-%3E
+%3C
  20)%0A   
@@ -3070,18 +3070,18 @@
 ).max %3E 
-20
+15
 )%0A    se
@@ -3168,17 +3168,17 @@
 .mean %3E 
-2
+1
 0)%0A%0A    

Improve temporal pooler monitor mixin test