def __init__(self, searchParams, workerID=None, cjDAO=None, jobID=None,
               logLevel=None):
    """Instantiate the HyperseachV2 instance.

    Parameters:
    ----------------------------------------------------------------------
    searchParams:   a dict of the job's search parameters. The format is:

      persistentJobGUID:  REQUIRED.
                          Persistent, globally-unique identifier for this job
                          for use in constructing persistent model checkpoint
                          keys. MUST be compatible with S3 key-naming rules, but
                          MUST NOT contain forward slashes. This GUID is
                          expected to retain its global uniqueness across
                          clusters and cluster software updates (unlike the
                          record IDs in the Engine's jobs table, which recycle
                          upon table schema change and software update). In the
                          future, this may also be instrumental for checkpoint
                          garbage collection.

      permutationsPyFilename:
                          OPTIONAL - path to permutations.py file
      permutationsPyContents:
                          OPTIONAL - JSON encoded string with
                                      contents of permutations.py file
      descriptionPyContents:
                          OPTIONAL - JSON encoded string with
                                      contents of base description.py file
      description:        OPTIONAL - JSON description of the search
      createCheckpoints:  OPTIONAL - Whether to create checkpoints
      useTerminators      OPTIONAL - True of False (default config.xml). When set
                                     to False, the model and swarm terminators
                                     are disabled
      maxModels:          OPTIONAL - max # of models to generate
                                    NOTE: This is a deprecated location for this
                                    setting. Now, it should be specified through
                                    the maxModels variable within the permutations
                                    file, or maxModels in the JSON description
      dummyModel:         OPTIONAL - Either (True/False) or a dict of parameters
                                     for a dummy model. If this key is absent,
                                     a real model is trained.
                                     See utils.py/OPFDummyModel runner for the
                                     schema of the dummy parameters
      speculativeParticles OPTIONAL - True or False (default obtained from
                                     nupic.hypersearch.speculative.particles.default
                                     configuration property). See note below.

      NOTE: The caller must provide just ONE of the following to describe the
      hypersearch:
            1.) permutationsPyFilename
        OR  2.) permutationsPyContents & permutationsPyContents
        OR  3.) description

      The schema for the description element can be found at:
       "py/nupic/frameworks/opf/expGenerator/experimentDescriptionSchema.json"

      NOTE about speculativeParticles: If true (not 0), hypersearch workers will
      go ahead and create and run particles in subsequent sprints and
      generations before the current generation or sprint has been completed. If
      false, a worker will wait in a sleep loop until the current generation or
      sprint has finished before choosing the next particle position or going
      into the next sprint. When true, the best model can be found faster, but
      results are less repeatable due to the randomness of when each worker
      completes each particle. This property can be overridden via the
      speculativeParticles element of the Hypersearch job params.


    workerID:   our unique Hypersearch worker ID

    cjDAO:      ClientJobsDB Data Access Object
    jobID:      job ID for this hypersearch job
    logLevel:   override logging level to this value, if not None
    """

    # Instantiate our logger
    self.logger = logging.getLogger(".".join( ['com.numenta',
                        self.__class__.__module__, self.__class__.__name__]))

    # Override log level?
    if logLevel is not None:
      self.logger.setLevel(logLevel)

    # This is how to check the logging level
    #if self.logger.getEffectiveLevel() <= logging.DEBUG:
    #  print "at debug level"

    # Init random seed
    random.seed(42)

    # Save the search info
    self._searchParams = searchParams
    self._workerID = workerID
    self._cjDAO = cjDAO
    self._jobID = jobID

    # Log search params
    self.logger.info("searchParams: \n%s" % (pprint.pformat(
        clippedObj(searchParams))))

    self._createCheckpoints = self._searchParams.get('createCheckpoints',
                                                     False)
    self._maxModels = self._searchParams.get('maxModels', None)
    if self._maxModels == -1:
      self._maxModels = None
    self._predictionCacheMaxRecords = self._searchParams.get('predictionCacheMaxRecords', None)

    # Speculative particles?
    self._speculativeParticles = self._searchParams.get('speculativeParticles',
        bool(int(Configuration.get(
                        'nupic.hypersearch.speculative.particles.default'))))
    self._speculativeWaitSecondsMax = float(Configuration.get(
                    'nupic.hypersearch.speculative.particles.sleepSecondsMax'))

    # Maximum Field Branching
    self._maxBranching= int(Configuration.get(
                             'nupic.hypersearch.max.field.branching'))

    # Minimum Field Contribution
    self._minFieldContribution= float(Configuration.get(
                             'nupic.hypersearch.min.field.contribution'))

    # This gets set if we detect that the job got cancelled
    self._jobCancelled = False

    # Use terminators (typically set by permutations_runner.py)
    if 'useTerminators' in self._searchParams:
      useTerminators = self._searchParams['useTerminators']
      useTerminators = str(int(useTerminators))

      Configuration.set('nupic.hypersearch.enableModelTermination', useTerminators)
      Configuration.set('nupic.hypersearch.enableModelMaturity', useTerminators)
      Configuration.set('nupic.hypersearch.enableSwarmTermination', useTerminators)

    # Special test mode?
    if 'NTA_TEST_exitAfterNModels' in os.environ:
      self._maxModels = int(os.environ['NTA_TEST_exitAfterNModels'])

    self._dummyModel = self._searchParams.get('dummyModel', None)

    # Holder for temporary directory, if any, that needs to be cleaned up
    # in our close() method.
    self._tempDir = None
    try:
      # Get the permutations info. This can be either:
      #  1.) JSON encoded search description (this will be used to generate a
      #       permutations.py and description.py files using ExpGenerator)
      #  2.) path to a pre-generated permutations.py file. The description.py is
      #       assumed to be in the same directory
      #  3.) contents of the permutations.py and descrption.py files.
      if 'description' in self._searchParams:
        if ('permutationsPyFilename' in self._searchParams or
            'permutationsPyContents' in self._searchParams or
            'descriptionPyContents' in self._searchParams):
          raise RuntimeError(
              "Either 'description', 'permutationsPyFilename' or"
              "'permutationsPyContents' & 'permutationsPyContents' should be "
              "specified, but not two or more of these at once.")

        # Calculate training period for anomaly models
        searchParamObj = self._searchParams
        anomalyParams = searchParamObj['description'].get('anomalyParams',
          dict())

        # This is used in case searchParamObj['description']['anomalyParams']
        # is set to None.
        if anomalyParams is None:
          anomalyParams = dict()

        if (('autoDetectWaitRecords' not in anomalyParams) or
            (anomalyParams['autoDetectWaitRecords'] is None)):
          streamDef = self._getStreamDef(searchParamObj['description'])

          from nupic.data.stream_reader import StreamReader

          try:
            streamReader = StreamReader(streamDef, isBlocking=False,
                                           maxTimeout=0, eofOnTimeout=True)
            anomalyParams['autoDetectWaitRecords'] = \
              streamReader.getDataRowCount()
          except Exception:
            anomalyParams['autoDetectWaitRecords'] = None
          self._searchParams['description']['anomalyParams'] = anomalyParams


        # Call the experiment generator to generate the permutations and base
        # description file.
        outDir = self._tempDir = tempfile.mkdtemp()
        expGenerator([
            '--description=%s' % (
                json.dumps(self._searchParams['description'])),
            '--version=v2',
            '--outDir=%s' % (outDir)])

        # Get the name of the permutations script.
        permutationsScript = os.path.join(outDir, 'permutations.py')

      elif 'permutationsPyFilename' in self._searchParams:
        if ('description' in self._searchParams or
            'permutationsPyContents' in self._searchParams or
            'descriptionPyContents' in self._searchParams):
          raise RuntimeError(
              "Either 'description', 'permutationsPyFilename' or "
              "'permutationsPyContents' & 'permutationsPyContents' should be "
              "specified, but not two or more of these at once.")
        permutationsScript = self._searchParams['permutationsPyFilename']

      elif 'permutationsPyContents' in self._searchParams:
        if ('description' in self._searchParams or
            'permutationsPyFilename' in self._searchParams):
          raise RuntimeError(
              "Either 'description', 'permutationsPyFilename' or"
              "'permutationsPyContents' & 'permutationsPyContents' should be "
              "specified, but not two or more of these at once.")

        assert ('descriptionPyContents' in self._searchParams)
        # Generate the permutations.py and description.py files
        outDir = self._tempDir = tempfile.mkdtemp()
        permutationsScript = os.path.join(outDir, 'permutations.py')
        fd = open(permutationsScript, 'w')
        fd.write(self._searchParams['permutationsPyContents'])
        fd.close()
        fd = open(os.path.join(outDir, 'description.py'), 'w')
        fd.write(self._searchParams['descriptionPyContents'])
        fd.close()

      else:
        raise RuntimeError ("Either 'description' or 'permutationsScript' must be"
                            "specified")

      # Get the base path of the experiment and read in the base description
      self._basePath = os.path.dirname(permutationsScript)
      self._baseDescription = open(os.path.join(self._basePath,
                                               'description.py')).read()
      self._baseDescriptionHash = hashlib.md5(self._baseDescription).digest()

      # Read the model config to figure out the inference type
      modelDescription, _ = helpers.loadExperiment(self._basePath)

      # Read info from permutations file. This sets up the following member
      # variables:
      #   _predictedField
      #   _permutations
      #   _flattenedPermutations
      #   _encoderNames
      #   _reportKeys
      #   _filterFunc
      #   _optimizeKey
      #   _maximize
      #   _dummyModelParamsFunc
      self._readPermutationsFile(permutationsScript, modelDescription)

      # Fill in and save the base description and permutations file contents
      #  if they haven't already been filled in by another worker
      if self._cjDAO is not None:
        updated = self._cjDAO.jobSetFieldIfEqual(jobID=self._jobID,
                                                 fieldName='genBaseDescription',
                                                 curValue=None,
                                                 newValue = self._baseDescription)
        if updated:
          permContents = open(permutationsScript).read()
          self._cjDAO.jobSetFieldIfEqual(jobID=self._jobID,
                                         fieldName='genPermutations',
                                         curValue=None,
                                         newValue = permContents)

      # if user provided an artificialMetric, force use of the dummy model
      if self._dummyModelParamsFunc is not None:
        if self._dummyModel is None:
          self._dummyModel = dict()

      # If at DEBUG log level, print out permutations info to the log
      if self.logger.getEffectiveLevel() <= logging.DEBUG:
        msg = StringIO.StringIO()
        print >> msg, "Permutations file specifications: "
        info = dict()
        for key in ['_predictedField', '_permutations',
                    '_flattenedPermutations', '_encoderNames',
                    '_reportKeys', '_optimizeKey', '_maximize']:
          info[key] = getattr(self, key)
        print >> msg, pprint.pformat(info)
        self.logger.debug(msg.getvalue())
        msg.close()

      # Instantiate our database to hold the results we received so far
      self._resultsDB = ResultsDB(self)

      # Instantiate the Swarm Terminator
      self._swarmTerminator = SwarmTerminator()

      # Initial hypersearch state
      self._hsState = None

      # The Max # of attempts we will make to create a unique model before
      #  giving up.
      self._maxUniqueModelAttempts = int(Configuration.get(
                                      'nupic.hypersearch.maxUniqueModelAttempts'))

      # The max amount of time allowed before a model is considered orphaned.
      self._modelOrphanIntervalSecs = float(Configuration.get(
                                      'nupic.hypersearch.modelOrphanIntervalSecs'))

      # The max percent of models that can complete with errors
      self._maxPctErrModels = float(Configuration.get(
                                      'nupic.hypersearch.maxPctErrModels'))

    except:
      # Clean up our temporary directory, if any
      if self._tempDir is not None:
        shutil.rmtree(self._tempDir)
        self._tempDir = None

      raise

    return
def __init__ ( self , searchParams , workerID = None , cjDAO = None , jobID = None , logLevel = None ) : self . logger = logging . getLogger ( "." . join ( [ 'com.numenta' , self . __class__ . __module__ , self . __class__ . __name__ ] ) ) if logLevel is not None : self . logger . setLevel ( logLevel ) random . seed ( 42 ) self . _searchParams = searchParams self . _workerID = workerID self . _cjDAO = cjDAO self . _jobID = jobID self . logger . info ( "searchParams: \n%s" % ( pprint . pformat ( clippedObj ( searchParams ) ) ) ) self . _createCheckpoints = self . _searchParams . get ( 'createCheckpoints' , False ) self . _maxModels = self . _searchParams . get ( 'maxModels' , None ) if self . _maxModels == - 1 : self . _maxModels = None self . _predictionCacheMaxRecords = self . _searchParams . get ( 'predictionCacheMaxRecords' , None ) self . _speculativeParticles = self . _searchParams . get ( 'speculativeParticles' , bool ( int ( Configuration . get ( 'nupic.hypersearch.speculative.particles.default' ) ) ) ) self . _speculativeWaitSecondsMax = float ( Configuration . get ( 'nupic.hypersearch.speculative.particles.sleepSecondsMax' ) ) self . _maxBranching = int ( Configuration . get ( 'nupic.hypersearch.max.field.branching' ) ) self . _minFieldContribution = float ( Configuration . get ( 'nupic.hypersearch.min.field.contribution' ) ) self . _jobCancelled = False if 'useTerminators' in self . _searchParams : useTerminators = self . _searchParams [ 'useTerminators' ] useTerminators = str ( int ( useTerminators ) ) Configuration . set ( 'nupic.hypersearch.enableModelTermination' , useTerminators ) Configuration . set ( 'nupic.hypersearch.enableModelMaturity' , useTerminators ) Configuration . set ( 'nupic.hypersearch.enableSwarmTermination' , useTerminators ) if 'NTA_TEST_exitAfterNModels' in os . environ : self . _maxModels = int ( os . environ [ 'NTA_TEST_exitAfterNModels' ] ) self . _dummyModel = self . _searchParams . get ( 'dummyModel' , None ) self . _tempDir = None try : if 'description' in self . _searchParams : if ( 'permutationsPyFilename' in self . _searchParams or 'permutationsPyContents' in self . _searchParams or 'descriptionPyContents' in self . _searchParams ) : raise RuntimeError ( "Either 'description', 'permutationsPyFilename' or" "'permutationsPyContents' & 'permutationsPyContents' should be " "specified, but not two or more of these at once." ) searchParamObj = self . _searchParams anomalyParams = searchParamObj [ 'description' ] . get ( 'anomalyParams' , dict ( ) ) if anomalyParams is None : anomalyParams = dict ( ) if ( ( 'autoDetectWaitRecords' not in anomalyParams ) or ( anomalyParams [ 'autoDetectWaitRecords' ] is None ) ) : streamDef = self . _getStreamDef ( searchParamObj [ 'description' ] ) from nupic . data . stream_reader import StreamReader try : streamReader = StreamReader ( streamDef , isBlocking = False , maxTimeout = 0 , eofOnTimeout = True ) anomalyParams [ 'autoDetectWaitRecords' ] = streamReader . getDataRowCount ( ) except Exception : anomalyParams [ 'autoDetectWaitRecords' ] = None self . _searchParams [ 'description' ] [ 'anomalyParams' ] = anomalyParams outDir = self . _tempDir = tempfile . mkdtemp ( ) expGenerator ( [ '--description=%s' % ( json . dumps ( self . _searchParams [ 'description' ] ) ) , '--version=v2' , '--outDir=%s' % ( outDir ) ] ) permutationsScript = os . path . join ( outDir , 'permutations.py' ) elif 'permutationsPyFilename' in self . _searchParams : if ( 'description' in self . _searchParams or 'permutationsPyContents' in self . _searchParams or 'descriptionPyContents' in self . _searchParams ) : raise RuntimeError ( "Either 'description', 'permutationsPyFilename' or " "'permutationsPyContents' & 'permutationsPyContents' should be " "specified, but not two or more of these at once." ) permutationsScript = self . _searchParams [ 'permutationsPyFilename' ] elif 'permutationsPyContents' in self . _searchParams : if ( 'description' in self . _searchParams or 'permutationsPyFilename' in self . _searchParams ) : raise RuntimeError ( "Either 'description', 'permutationsPyFilename' or" "'permutationsPyContents' & 'permutationsPyContents' should be " "specified, but not two or more of these at once." ) assert ( 'descriptionPyContents' in self . _searchParams ) outDir = self . _tempDir = tempfile . mkdtemp ( ) permutationsScript = os . path . join ( outDir , 'permutations.py' ) fd = open ( permutationsScript , 'w' ) fd . write ( self . _searchParams [ 'permutationsPyContents' ] ) fd . close ( ) fd = open ( os . path . join ( outDir , 'description.py' ) , 'w' ) fd . write ( self . _searchParams [ 'descriptionPyContents' ] ) fd . close ( ) else : raise RuntimeError ( "Either 'description' or 'permutationsScript' must be" "specified" ) self . _basePath = os . path . dirname ( permutationsScript ) self . _baseDescription = open ( os . path . join ( self . _basePath , 'description.py' ) ) . read ( ) self . _baseDescriptionHash = hashlib . md5 ( self . _baseDescription ) . digest ( ) modelDescription , _ = helpers . loadExperiment ( self . _basePath ) self . _readPermutationsFile ( permutationsScript , modelDescription ) if self . _cjDAO is not None : updated = self . _cjDAO . jobSetFieldIfEqual ( jobID = self . _jobID , fieldName = 'genBaseDescription' , curValue = None , newValue = self . _baseDescription ) if updated : permContents = open ( permutationsScript ) . read ( ) self . _cjDAO . jobSetFieldIfEqual ( jobID = self . _jobID , fieldName = 'genPermutations' , curValue = None , newValue = permContents ) if self . _dummyModelParamsFunc is not None : if self . _dummyModel is None : self . _dummyModel = dict ( ) if self . logger . getEffectiveLevel ( ) <= logging . DEBUG : msg = StringIO . StringIO ( ) print >> msg , "Permutations file specifications: " info = dict ( ) for key in [ '_predictedField' , '_permutations' , '_flattenedPermutations' , '_encoderNames' , '_reportKeys' , '_optimizeKey' , '_maximize' ] : info [ key ] = getattr ( self , key ) print >> msg , pprint . pformat ( info ) self . logger . debug ( msg . getvalue ( ) ) msg . close ( ) self . _resultsDB = ResultsDB ( self ) self . _swarmTerminator = SwarmTerminator ( ) self . _hsState = None self . _maxUniqueModelAttempts = int ( Configuration . get ( 'nupic.hypersearch.maxUniqueModelAttempts' ) ) self . _modelOrphanIntervalSecs = float ( Configuration . get ( 'nupic.hypersearch.modelOrphanIntervalSecs' ) ) self . _maxPctErrModels = float ( Configuration . get ( 'nupic.hypersearch.maxPctErrModels' ) ) except : if self . _tempDir is not None : shutil . rmtree ( self . _tempDir ) self . _tempDir = None raise return
Instantiate the HyperseachV2 instance.

    Parameters:
    ----------------------------------------------------------------------
    searchParams:   a dict of the job's search parameters. The format is:

      persistentJobGUID:  REQUIRED.
                          Persistent, globally-unique identifier for this job
                          for use in constructing persistent model checkpoint
                          keys. MUST be compatible with S3 key-naming rules, but
                          MUST NOT contain forward slashes. This GUID is
                          expected to retain its global uniqueness across
                          clusters and cluster software updates (unlike the
                          record IDs in the Engine's jobs table, which recycle
                          upon table schema change and software update). In the
                          future, this may also be instrumental for checkpoint
                          garbage collection.

      permutationsPyFilename:
                          OPTIONAL - path to permutations.py file
      permutationsPyContents:
                          OPTIONAL - JSON encoded string with
                                      contents of permutations.py file
      descriptionPyContents:
                          OPTIONAL - JSON encoded string with
                                      contents of base description.py file
      description:        OPTIONAL - JSON description of the search
      createCheckpoints:  OPTIONAL - Whether to create checkpoints
      useTerminators      OPTIONAL - True of False (default config.xml). When set
                                     to False, the model and swarm terminators
                                     are disabled
      maxModels:          OPTIONAL - max # of models to generate
                                    NOTE: This is a deprecated location for this
                                    setting. Now, it should be specified through
                                    the maxModels variable within the permutations
                                    file, or maxModels in the JSON description
      dummyModel:         OPTIONAL - Either (True/False) or a dict of parameters
                                     for a dummy model. If this key is absent,
                                     a real model is trained.
                                     See utils.py/OPFDummyModel runner for the
                                     schema of the dummy parameters
      speculativeParticles OPTIONAL - True or False (default obtained from
                                     nupic.hypersearch.speculative.particles.default
                                     configuration property). See note below.

      NOTE: The caller must provide just ONE of the following to describe the
      hypersearch:
            1.) permutationsPyFilename
        OR  2.) permutationsPyContents & permutationsPyContents
        OR  3.) description

      The schema for the description element can be found at:
       "py/nupic/frameworks/opf/expGenerator/experimentDescriptionSchema.json"

      NOTE about speculativeParticles: If true (not 0), hypersearch workers will
      go ahead and create and run particles in subsequent sprints and
      generations before the current generation or sprint has been completed. If
      false, a worker will wait in a sleep loop until the current generation or
      sprint has finished before choosing the next particle position or going
      into the next sprint. When true, the best model can be found faster, but
      results are less repeatable due to the randomness of when each worker
      completes each particle. This property can be overridden via the
      speculativeParticles element of the Hypersearch job params.


    workerID:   our unique Hypersearch worker ID

    cjDAO:      ClientJobsDB Data Access Object
    jobID:      job ID for this hypersearch job
    logLevel:   override logging level to this value, if not None