def testInit(self, compute, configurationGet): anomalyParams = { 'autoDetectWaitRecords': 100, 'autoDetectThreshold': 101, 'anomalyCacheRecords': 102, 'anomalyVectorType': 'tpc' } conf = { 'nupic.model.temporalAnomaly.wait_records': 160, 'nupic.model.temporalAnomaly.auto_detect_threshold': 2.0, 'nupic.model.temporalAnomaly.window_length': 1111, 'nupic.model.temporalAnomaly.anomaly_vector': 'tpc', } configurationGet.side_effect = conf.get helper = CLAModelClassifierHelper(Mock(spec=CLAModel), anomalyParams) self.assertEqual(helper._autoDetectWaitRecords, anomalyParams['autoDetectWaitRecords']) self.assertEqual(helper._autoDetectThreshold, anomalyParams['autoDetectThreshold']) self.assertEqual(helper._history_length, anomalyParams['anomalyCacheRecords']) self.assertEqual(helper._vectorType, anomalyParams['anomalyVectorType']) helper = CLAModelClassifierHelper(Mock(spec=CLAModel), None) self.assertEqual(helper._autoDetectWaitRecords, conf['nupic.model.temporalAnomaly.wait_records']) self.assertEqual( helper._autoDetectThreshold, conf['nupic.model.temporalAnomaly.auto_detect_threshold']) self.assertEqual(helper._history_length, conf['nupic.model.temporalAnomaly.window_length']) self.assertEqual(helper._vectorType, conf['nupic.model.temporalAnomaly.anomaly_vector'])
def testConfiguration(self, configurationGet): conf = { 'nupic.model.temporalAnomaly.wait_records': 160, 'nupic.model.temporalAnomaly.auto_detect_threshold': 2.0, 'nupic.model.temporalAnomaly.window_length': 1111, 'nupic.model.temporalAnomaly.anomaly_vector': 'tpc' } configurationGet.side_effect = conf.get helper = CLAModelClassifierHelper(Mock(spec=CLAModel)) self.assertEqual(helper._autoDetectWaitRecords, conf['nupic.model.temporalAnomaly.wait_records']) self.assertTrue(helper._autoDetectThreshold, conf['nupic.model.temporalAnomaly.auto_detect_threshold']) self.assertTrue(helper._history_length, conf['nupic.model.temporalAnomaly.window_length']) self.assertTrue(helper._vectorType, conf['nupic.model.temporalAnomaly.anomaly_vector'])
def setUp(self): self.helper = CLAModelClassifierHelper(Mock(spec=CLAModel))
class CLAClassifierHelperTest(unittest.TestCase): """CLAModelClassifierHelper unit tests.""" def setUp(self): self.helper = CLAModelClassifierHelper(Mock(spec=CLAModel)) @patch.object(Configuration, 'get') @patch.object(CLAModelClassifierHelper, 'compute') def testInit(self,compute, configurationGet): anomalyParams = { 'autoDetectWaitRecords': 100, 'autoDetectThreshold': 101, 'anomalyCacheRecords': 102, 'anomalyVectorType': 'tpc' } conf = { 'nupic.model.temporalAnomaly.wait_records': 160, 'nupic.model.temporalAnomaly.auto_detect_threshold': 2.0, 'nupic.model.temporalAnomaly.window_length': 1111, 'nupic.model.temporalAnomaly.anomaly_vector': 'tpc', } configurationGet.side_effect = conf.get helper = CLAModelClassifierHelper(Mock(spec=CLAModel), anomalyParams) self.assertEqual(helper._autoDetectWaitRecords, anomalyParams['autoDetectWaitRecords']) self.assertEqual(helper._autoDetectThreshold, anomalyParams['autoDetectThreshold']) self.assertEqual(helper._history_length, anomalyParams['anomalyCacheRecords']) self.assertEqual(helper._vectorType, anomalyParams['anomalyVectorType']) helper = CLAModelClassifierHelper(Mock(spec=CLAModel), None) self.assertEqual(helper._autoDetectWaitRecords, conf['nupic.model.temporalAnomaly.wait_records']) self.assertEqual(helper._autoDetectThreshold, conf['nupic.model.temporalAnomaly.auto_detect_threshold']) self.assertEqual(helper._history_length, conf['nupic.model.temporalAnomaly.window_length']) self.assertEqual(helper._vectorType, conf['nupic.model.temporalAnomaly.anomaly_vector']) @patch.object(CLAModelClassifierHelper, 'compute') def testRun(self,compute): state = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": [1,4,5], "anomalyLabel": "Label" } compute.return_value = _CLAClassificationRecord(**state) result = self.helper.run() compute.assert_called_once_with() self.assertEqual(result, state['anomalyLabel']) def testGetLabels(self): # No saved_states self.helper.saved_states = [] self.assertEqual(self.helper.getLabels(), \ {'isProcessing': False, 'recordLabels': []}) # Invalid ranges self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.getLabels, start=100, end=100) self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.getLabels, start=-100, end=-100) self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.getLabels, start=100, end=-100) # Valid no threshold labels values = { 'categoryRecencyList': [4, 5, 7], } self.helper.saved_categories = ['TestCategory'] categoryList = [1,1,1] classifier = self.helper.clamodel._getAnomalyClassifier().getSelf() classifier.getParameter.side_effect = values.get classifier._knn._categoryList = categoryList results = self.helper.getLabels() self.assertTrue('isProcessing' in results) self.assertTrue('recordLabels' in results) self.assertEqual(len(results['recordLabels']), len(values['categoryRecencyList'])) for record in results['recordLabels']: self.assertTrue(record['ROWID'] in values['categoryRecencyList']) self.assertEqual(record['labels'], self.helper.saved_categories) @patch.object(CLAModelClassifierHelper, '_getStateAnomalyVector') @patch.object(CLAModelClassifierHelper, '_updateState') def testAddLabel(self, _updateState, _getStateAnomalyVector): self.helper.clamodel._getAnomalyClassifier().getSelf().getParameter.return_value = [1,2,3] self.helper.saved_states = [] self.assertRaises(CLAModelInvalidRangeError, self.helper.addLabel, start=100, end=100, labelName="test") # Invalid ranges self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.addLabel, start=100, end=100, labelName="test") self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.addLabel, start=-100, end=-100, labelName="test") self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.addLabel, start=100, end=-100, labelName="test") # Valid no threshold labels self.helper.saved_states = [ Mock(ROWID=10, anomalyLabel=["Test"], setByUser=False), Mock(ROWID=11, anomalyLabel=[], setByUser=False), Mock(ROWID=12, anomalyLabel=["Test"], setByUser=True)] results = self.helper.addLabel(11, 12, "Added") # Verifies records were udpated self.assertEqual(results, None) self.assertTrue('Added' in self.helper.saved_states[1].anomalyLabel) self.assertTrue(self.helper.saved_states[1].setByUser) # Verifies record added to KNN classifier knn = self.helper.clamodel._getAnomalyClassifier().getSelf()._knn knn.learn.assert_called_once_with(ANY, ANY, rowID=11) # Verifies records after added label is recomputed _updateState.assert_called_once_with(self.helper.saved_states[2]) @patch.object(CLAModelClassifierHelper, '_getStateAnomalyVector') @patch.object(CLAModelClassifierHelper, '_updateState') def testRemoveLabel(self, _updateState, _getStateAnomalyVector): classifier = self.helper.clamodel._getAnomalyClassifier().getSelf() classifier.getParameter.return_value = [10,11,12] classifier._knn._numPatterns = 3 classifier._knn.removeIds.side_effect = self.mockRemoveIds self.helper.saved_states = [] self.assertRaises(CLAModelInvalidRangeError, self.helper.removeLabels,) # Invalid ranges self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.removeLabels, start=100, end=100) self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.removeLabels, start=-100, end=-100) self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.removeLabels, start=100, end=-100) # Valid no threshold labels self.helper.saved_states = [ Mock(ROWID=10, anomalyLabel=["Test"], setByUser=False), Mock(ROWID=11, anomalyLabel=["Test"], setByUser=False), Mock(ROWID=12, anomalyLabel=["Test"], setByUser=True)] results = self.helper.removeLabels(11, 12, "Test") self.assertEqual(results, {'status': 'success'}) self.assertTrue('Test' not in self.helper.saved_states[1].anomalyLabel) # Verifies records removed from KNN classifier knn = self.helper.clamodel._getAnomalyClassifier().getSelf()._knn self.assertEqual(knn.removeIds.mock_calls, [call([11]), call([])]) # Verifies records after removed record are updated _updateState.assert_called_once_with(self.helper.saved_states[2]) @patch.object(CLAModelClassifierHelper, '_getStateAnomalyVector') @patch.object(CLAModelClassifierHelper, '_updateState') def testRemoveLabelNoFilter(self, _updateState, _getStateAnomalyVector): classifier = self.helper.clamodel._getAnomalyClassifier().getSelf() values = { 'categoryRecencyList': [10, 11, 12] } classifier.getParameter.side_effect = values.get classifier._knn._numPatterns = 3 classifier._knn.removeIds.side_effect = self.mockRemoveIds # Valid no threshold labels self.helper.saved_states = [ Mock(ROWID=10, anomalyLabel=["Test"], setByUser=False), Mock(ROWID=11, anomalyLabel=["Test"], setByUser=False), Mock(ROWID=12, anomalyLabel=["Test"], setByUser=True)] results = self.helper.removeLabels(11, 12) self.assertEqual(results, {'status': 'success'}) self.assertTrue('Test' not in self.helper.saved_states[1].anomalyLabel) # Verifies records removed from KNN classifier knn = self.helper.clamodel._getAnomalyClassifier().getSelf()._knn self.assertEqual(knn.removeIds.mock_calls, [call([11]), call([])]) # Verifies records after removed record are updated _updateState.assert_called_once_with(self.helper.saved_states[2]) @patch.object(CLAModelClassifierHelper, '_updateState') def testSetGetThreshold(self, updateState): self.helper.saved_states = [Mock(), Mock(), Mock()] self.helper.setAutoDetectThreshold(1.0) self.assertAlmostEqual(self.helper._autoDetectThreshold, 1.0) self.assertEqual(len(updateState.mock_calls), len(self.helper.saved_states)) self.assertAlmostEqual(self.helper.getAutoDetectThreshold(), 1.0) self.assertRaises(Exception, self.helper.setAutoDetectThreshold, 'invalid') @patch.object(CLAModelClassifierHelper, '_updateState') def testSetGetWaitRecords(self, updateState): self.helper.saved_states = [ Mock(ROWID=10, anomalyLabel=["Test"], setByUser=False), Mock(ROWID=11, anomalyLabel=["Test"], setByUser=False), Mock(ROWID=12, anomalyLabel=["Test"], setByUser=True)] self.helper.setAutoDetectWaitRecords(20) self.assertEqual(self.helper._autoDetectWaitRecords, 20) self.assertEqual(len(updateState.mock_calls), len(self.helper.saved_states)) self.assertEqual(self.helper.getAutoDetectWaitRecords(), 20) # Test invalid parameter type self.assertRaises(Exception, self.helper.setAutoDetectWaitRecords, 'invalid') # Test invalid value before first record ROWID in cache self.assertRaises(Exception, self.helper.setAutoDetectWaitRecords, 0) @patch.object(CLAModelClassifierHelper, '_addRecordToKNN') @patch.object(CLAModelClassifierHelper, '_deleteRecordsFromKNN') @patch.object(CLAModelClassifierHelper, '_recomputeRecordFromKNN') @patch.object(CLAModelClassifierHelper, '_categoryToLabelList') def testUpdateState(self, toLabelList, recompute, deleteRecord, addRecord): record = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": "", "anomalyLabel": ["Label"], "setByUser": False } # Test record not labeled and not above threshold deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectWaitRecords = 0 self.helper._autoDetectThreshold = 1.1 toLabelList.return_value = [] state = _CLAClassificationRecord(**record) self.helper._updateState(state) self.assertEqual(state.anomalyLabel, []) deleteRecord.assert_called_once_with([state]) # Test record not labeled and above threshold deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectThreshold = 0.5 toLabelList.return_value = [] state = _CLAClassificationRecord(**record) self.helper._updateState(state) self.assertEqual(state.anomalyLabel, \ [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL]) addRecord.assert_called_once_with(state) # Test record not labeled and above threshold during wait period deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectWaitRecords = 10 self.helper._autoDetectThreshold = 0.5 toLabelList.return_value = [] state = _CLAClassificationRecord(**record) self.helper._updateState(state) self.assertEqual(state.anomalyLabel, []) self.assertTrue(not addRecord.called) # Test record labeled and not above threshold deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectWaitRecords = 0 self.helper._autoDetectThreshold = 1.1 toLabelList.return_value = ["Label"] state = _CLAClassificationRecord(**record) self.helper._updateState(state) self.assertEqual(state.anomalyLabel, ["Label"]) self.assertTrue(not addRecord.called) # Test setByUser deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectThreshold = 1.1 toLabelList.return_value = ["Label 2"] recordCopy = copy.deepcopy(record) recordCopy['setByUser'] = True state = _CLAClassificationRecord(**recordCopy) self.helper._updateState(state) self.assertEqual(state.anomalyLabel, [recordCopy["anomalyLabel"][0], toLabelList.return_value[0]]) addRecord.assert_called_once_with(state) # Test removal of above threshold deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectThreshold = 1.1 toLabelList.return_value = [] recordCopy = copy.deepcopy(record) recordCopy['setByUser'] = True recordCopy['anomalyLabel'] = \ [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL, CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL + \ CLAModelClassifierHelper.AUTO_TAG] state = _CLAClassificationRecord(**recordCopy) self.helper._updateState(state) self.assertEqual(state.anomalyLabel, []) # Auto classified threshold deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectThreshold = 1.1 toLabelList.return_value = \ [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL] recordCopy = copy.deepcopy(record) recordCopy['setByUser'] = True recordCopy['anomalyLabel'] = \ [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL] state = _CLAClassificationRecord(**recordCopy) self.helper._updateState(state) self.assertEqual(state.anomalyLabel, [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL + \ CLAModelClassifierHelper.AUTO_TAG]) addRecord.assert_called_once_with(state) # Test precedence of threshold label above auto threshold label deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectThreshold = 0.8 toLabelList.return_value = \ [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL, CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL + \ CLAModelClassifierHelper.AUTO_TAG] recordCopy = copy.deepcopy(record) recordCopy['setByUser'] = True recordCopy['anomalyLabel'] = \ [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL] state = _CLAClassificationRecord(**recordCopy) self.helper._updateState(state) self.assertEqual(state.anomalyLabel, [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL]) addRecord.assert_called_once_with(state) @patch.object(CLAModelClassifierHelper, '_getStateAnomalyVector') def testAddRecordToKNN(self, getAnomalyVector): getAnomalyVector.return_value = "Vector" values = { 'categoryRecencyList': [1, 2, 3] } classifier = self.helper.clamodel._getAnomalyClassifier().getSelf() classifier.getParameter.side_effect = values.get state = { "ROWID": 5, "anomalyScore": 1.0, "anomalyVector": "", "anomalyLabel": ["Label"], "setByUser": False } record = _CLAClassificationRecord(**state) # Test with record not already in KNN self.helper._addRecordToKNN(record) classifier._knn.learn.assert_called_once_with("Vector", ANY, rowID=state['ROWID']) self.assertTrue(not classifier._knn.prototypeSetCategory.called) classifier._knn.learn.reset_mock() # Test with record already in KNN values = { 'categoryRecencyList': [1, 2, 3, 5] } classifier.getParameter.side_effect = values.get self.helper._addRecordToKNN(record) classifier._knn.prototypeSetCategory.assert_called_once_with(\ state['ROWID'], ANY) self.assertTrue(not classifier._knn.learn.called) @patch.object(CLAModelClassifierHelper, '_getStateAnomalyVector') def testDeleteRangeFromKNN(self, getAnomalyVector): getAnomalyVector.return_value = "Vector" values = { 'categoryRecencyList': [1, 2, 3] } classifier = self.helper.clamodel._getAnomalyClassifier().getSelf() classifier.getParameter.side_effect = values.get classifier._knn._numPatterns = len(values['categoryRecencyList']) classifier._knn.removeIds.side_effect = self.mockRemoveIds # Test with record not already in KNN self.helper._deleteRangeFromKNN(start=1,end=3) classifier._knn.removeIds.assert_called_once_with([1,2]) classifier._knn.removeIds.reset_mock() # Test with record already in KNN values = { 'categoryRecencyList': [1, 2, 3, 5] } classifier.getParameter.side_effect = values.get self.helper._deleteRangeFromKNN(start=1) classifier._knn.removeIds.assert_called_once_with([1,2,3,5]) @patch.object(CLAModelClassifierHelper, '_getStateAnomalyVector') def testRecomputeRecordFromKNN(self, getAnomalyVector): getAnomalyVector.return_value = "Vector" values = { 'categoryRecencyList': [1, 2, 3, 5, 6, 7, 8, 9], 'latestDists': numpy.array([0.7, 0.2, 0.5, 1, 0.3, 0.2, 0.1]), 'categories': ['A','B','C','D','E','F','G'] } classifier = self.helper.clamodel._getAnomalyClassifier().getSelf() classifier.getLatestDistances.return_value = values['latestDists'] classifier.getCategoryList.return_value = values['categories'] classifier.getParameter.side_effect = values.get state = { "ROWID": 5, "anomalyScore": 1.0, "anomalyVector": "", "anomalyLabel": ["Label"], "setByUser": False } record = _CLAClassificationRecord(**state) # Test finding best category before record - exists self.helper._classificationMaxDist = 0.4 self.helper._autoDetectWaitRecords = 0 result = self.helper._recomputeRecordFromKNN(record) self.assertEqual(result, 'B') # Test finding best category before record - does not exists self.helper._classificationMaxDist = 0.1 result = self.helper._recomputeRecordFromKNN(record) self.assertEqual(result, None) # Test finding best category before record - not record before record.ROWID = 0 self.helper._classificationMaxDist = 0.1 result = self.helper._recomputeRecordFromKNN(record) self.assertEqual(result, None) def testConstructClassificationVector(self): modelParams = { '__numRunCalls': 0 } spVals = { 'params': { 'activeOutputCount': 5 }, 'output': { 'bottomUpOut': numpy.array([1,1,0,0,1]) } } tpVals = { 'params': { 'cellsPerColumn': 2, 'columnCount': 2 }, 'output': { 'lrnActive': numpy.array([1,0,0,1]), 'topDownOut': numpy.array([1,0,0,0,1]) } } self.helper.clamodel.getParameter.side_effect = modelParams.get sp = self.helper.clamodel._getSPRegion() tp = self.helper.clamodel._getTPRegion() tpImp = tp.getSelf()._tfdr sp.getParameter.side_effect = spVals['params'].get sp.getOutputData.side_effect = spVals['output'].get self.helper._activeColumnCount = 5 tp.getParameter.side_effect = tpVals['params'].get tp.getOutputData.side_effect = tpVals['output'].get tpImp.getLearnActiveStateT.return_value = tpVals['output']['lrnActive'] # Test TP Cell vector self.helper._vectorType = 'tpc' vector = self.helper._constructClassificationRecord() self.assertEqual(vector.anomalyVector, tpImp.getLearnActiveStateT().nonzero()[0].tolist()) # Test SP and TP Column Error vector self.helper._vectorType = 'sp_tpe' self.helper._prevPredictedColumns = numpy.array([1,0,0,0,1]).nonzero()[0] vector = self.helper._constructClassificationRecord() self.assertEqual(vector.anomalyVector, [0, 1, 4]) self.helper._prevPredictedColumns = numpy.array([1,0,1,0,0]).nonzero()[0] vector = self.helper._constructClassificationRecord() self.assertEqual(vector.anomalyVector, [0, 1, 4, 7]) self.helper._vectorType = 'invalidType' self.assertRaises(TypeError, self.helper._constructClassificationRecord) @patch.object(CLAModelClassifierHelper ,'_updateState') @patch.object(CLAModelClassifierHelper, '_constructClassificationRecord') def testCompute(self, createRecord, updateState): state = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": "Vector", "anomalyLabel": "Label" } record = _CLAClassificationRecord(**state) createRecord.return_value = record # Test add first record self.helper._history_length = 10 self.helper._autoDetectWaitRecords = 0 self.helper.saved_states = [] result = self.helper.compute() self.assertEqual(result, record) self.assertEqual(len(self.helper.saved_states), 1) updateState.assert_called_once_with(result) # Test add record before wait records updateState.reset_mock() self.helper._history_length = 10 self.helper._autoDetectWaitRecords = 10 self.helper.saved_states = [] result = self.helper.compute() self.assertEqual(result, record) self.assertEqual(len(self.helper.saved_states), 1) result = self.helper.compute() self.assertEqual(result, record) self.assertEqual(len(self.helper.saved_states), 2) self.assertTrue(not updateState.called) # Test exceeded cache length updateState.reset_mock() self.helper._history_length = 1 self.helper.saved_states = [] result = self.helper.compute() self.assertEqual(result, record) self.assertEqual(len(self.helper.saved_states), 1) result = self.helper.compute() self.assertEqual(result, record) self.assertEqual(len(self.helper.saved_states), 1) self.assertTrue(not updateState.called) def testCategoryToList(self): result = self.helper._categoryToLabelList(None) self.assertEqual(result, []) self.helper.saved_categories = ['A', 'B', 'C'] result = self.helper._categoryToLabelList(1) self.assertEqual(result, ['A']) result = self.helper._categoryToLabelList(4) self.assertEqual(result, ['C']) result = self.helper._categoryToLabelList(5) self.assertEqual(result, ['A','C']) def testGetAnomalyVector(self): state = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": [1,4,5], "anomalyLabel": "Label" } record = _CLAClassificationRecord(**state) self.helper._anomalyVectorLength = 10 vector = self.helper._getStateAnomalyVector(record) self.assertEqual(len(vector), self.helper._anomalyVectorLength) self.assertEqual(vector.nonzero()[0].tolist(), record.anomalyVector) # Tests for configuration ############################################################################# @patch.object(Configuration, 'get') def testConfiguration(self, configurationGet): conf = { 'nupic.model.temporalAnomaly.wait_records': 160, 'nupic.model.temporalAnomaly.auto_detect_threshold': 2.0, 'nupic.model.temporalAnomaly.window_length': 1111, 'nupic.model.temporalAnomaly.anomaly_vector': 'tpc' } configurationGet.side_effect = conf.get helper = CLAModelClassifierHelper(Mock(spec=CLAModel)) self.assertEqual(helper._autoDetectWaitRecords, conf['nupic.model.temporalAnomaly.wait_records']) self.assertTrue(helper._autoDetectThreshold, conf['nupic.model.temporalAnomaly.auto_detect_threshold']) self.assertTrue(helper._history_length, conf['nupic.model.temporalAnomaly.window_length']) self.assertTrue(helper._vectorType, conf['nupic.model.temporalAnomaly.anomaly_vector']) @patch.object(Configuration, 'get') def testConfigurationFail(self, configurationGet): conf = { 'nupic.model.temporalAnomaly.wait_records': 160, 'nupic.model.temporalAnomaly.anomaly_vector': 'tpc' } configurationGet.side_effect = conf.get self.assertRaises(TypeError, CLAModelClassifierHelper, Mock(spec=CLAModel)) @patch.object(Configuration, 'get') def testSetState(self, configurationGet): conf = { 'nupic.model.temporalAnomaly.wait_records': 160, 'nupic.model.temporalAnomaly.anomaly_vector': 'tpc' } configurationGet.side_effect = conf.get state = dict(_version=1,_classificationDelay=100) self.helper._vectorType = None state = self.helper.__setstate__(state) self.assertEqual(self.helper._vectorType, conf['nupic.model.temporalAnomaly.anomaly_vector']) self.assertEqual(self.helper._version, CLAModelClassifierHelper.__VERSION__) state = dict(_version=2, _classificationDelay=100) state = self.helper.__setstate__(state) self.assertEqual(self.helper._version, CLAModelClassifierHelper.__VERSION__) state = dict(_version="invalid") self.assertRaises(Exception, self.helper.__setstate__, state) # Tests for _CLAClassificationRecord class ############################################################################# def testCLAClassificationRecord(self): record = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": "Vector", "anomalyLabel": "Label" } state = _CLAClassificationRecord(**record) self.assertEqual(state.ROWID, record['ROWID']) self.assertEqual(state.anomalyScore, record['anomalyScore']) self.assertEqual(state.anomalyVector, record['anomalyVector']) self.assertEqual(state.anomalyLabel, record['anomalyLabel']) self.assertEqual(state.setByUser, False) record = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": "Vector", "anomalyLabel": "Label", "setByUser": True } state = _CLAClassificationRecord(**record) self.assertEqual(state.ROWID, record['ROWID']) self.assertEqual(state.anomalyScore, record['anomalyScore']) self.assertEqual(state.anomalyVector, record['anomalyVector']) self.assertEqual(state.anomalyLabel, record['anomalyLabel']) self.assertEqual(state.setByUser, record['setByUser']) def testCLAClassificationRecordGetState(self): record = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": "Vector", "anomalyLabel": "Label", "setByUser": False } state = _CLAClassificationRecord(**record) self.assertEqual(state.__getstate__(), record) def testCLAClassificationRecordSetState(self): record = { "ROWID": None, "anomalyScore": None, "anomalyVector": None, "anomalyLabel": None, "setByUser": None } state = _CLAClassificationRecord(**record) record = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": "Vector", "anomalyLabel": "Label", "setByUser": False } state.__setstate__(record) self.assertEqual(state.ROWID, record['ROWID']) self.assertEqual(state.anomalyScore, record['anomalyScore']) self.assertEqual(state.anomalyVector, record['anomalyVector']) self.assertEqual(state.anomalyLabel, record['anomalyLabel']) self.assertEqual(state.setByUser, record['setByUser']) def mockRemoveIds(self, ids): self.helper.clamodel._getAnomalyClassifier().getSelf()._knn._numPatterns -= len(ids) for idx in ids: if idx in self.helper.clamodel._getAnomalyClassifier().getSelf().getParameter('categoryRecencyList'): self.helper.clamodel._getAnomalyClassifier().getSelf().getParameter('categoryRecencyList').remove(idx)
class CLAClassifierHelperTest(unittest.TestCase): """CLAModelClassifierHelper unit tests.""" def setUp(self): self.helper = CLAModelClassifierHelper(Mock(spec=CLAModel)) @patch.object(Configuration, 'get') @patch.object(CLAModelClassifierHelper, 'compute') def testInit(self, compute, configurationGet): anomalyParams = { 'autoDetectWaitRecords': 100, 'autoDetectThreshold': 101, 'anomalyCacheRecords': 102, 'anomalyVectorType': 'tpc' } conf = { 'nupic.model.temporalAnomaly.wait_records': 160, 'nupic.model.temporalAnomaly.auto_detect_threshold': 2.0, 'nupic.model.temporalAnomaly.window_length': 1111, 'nupic.model.temporalAnomaly.anomaly_vector': 'tpc', } configurationGet.side_effect = conf.get helper = CLAModelClassifierHelper(Mock(spec=CLAModel), anomalyParams) self.assertEqual(helper._autoDetectWaitRecords, anomalyParams['autoDetectWaitRecords']) self.assertEqual(helper._autoDetectThreshold, anomalyParams['autoDetectThreshold']) self.assertEqual(helper._history_length, anomalyParams['anomalyCacheRecords']) self.assertEqual(helper._vectorType, anomalyParams['anomalyVectorType']) helper = CLAModelClassifierHelper(Mock(spec=CLAModel), None) self.assertEqual(helper._autoDetectWaitRecords, conf['nupic.model.temporalAnomaly.wait_records']) self.assertEqual( helper._autoDetectThreshold, conf['nupic.model.temporalAnomaly.auto_detect_threshold']) self.assertEqual(helper._history_length, conf['nupic.model.temporalAnomaly.window_length']) self.assertEqual(helper._vectorType, conf['nupic.model.temporalAnomaly.anomaly_vector']) @patch.object(CLAModelClassifierHelper, 'compute') def testRun(self, compute): state = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": [1, 4, 5], "anomalyLabel": "Label" } compute.return_value = _CLAClassificationRecord(**state) result = self.helper.run() compute.assert_called_once_with() self.assertEqual(result, state['anomalyLabel']) def testGetLabels(self): # No saved_states self.helper.saved_states = [] self.assertEqual(self.helper.getLabels(), \ {'isProcessing': False, 'recordLabels': []}) # Invalid ranges self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.getLabels, start=100, end=100) self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.getLabels, start=-100, end=-100) self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.getLabels, start=100, end=-100) # Valid no threshold labels values = { 'categoryRecencyList': [4, 5, 7], } self.helper.saved_categories = ['TestCategory'] categoryList = [1, 1, 1] classifier = self.helper.clamodel._getAnomalyClassifier().getSelf() classifier.getParameter.side_effect = values.get classifier._knn._categoryList = categoryList results = self.helper.getLabels() self.assertTrue('isProcessing' in results) self.assertTrue('recordLabels' in results) self.assertEqual(len(results['recordLabels']), len(values['categoryRecencyList'])) for record in results['recordLabels']: self.assertTrue(record['ROWID'] in values['categoryRecencyList']) self.assertEqual(record['labels'], self.helper.saved_categories) @patch.object(CLAModelClassifierHelper, '_getStateAnomalyVector') @patch.object(CLAModelClassifierHelper, '_updateState') def testAddLabel(self, _updateState, _getStateAnomalyVector): self.helper.clamodel._getAnomalyClassifier().getSelf( ).getParameter.return_value = [1, 2, 3] self.helper.saved_states = [] self.assertRaises(CLAModelInvalidRangeError, self.helper.addLabel, start=100, end=100, labelName="test") # Invalid ranges self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.addLabel, start=100, end=100, labelName="test") self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.addLabel, start=-100, end=-100, labelName="test") self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.addLabel, start=100, end=-100, labelName="test") # Valid no threshold labels self.helper.saved_states = [ Mock(ROWID=10, anomalyLabel=["Test"], setByUser=False), Mock(ROWID=11, anomalyLabel=[], setByUser=False), Mock(ROWID=12, anomalyLabel=["Test"], setByUser=True) ] results = self.helper.addLabel(11, 12, "Added") # Verifies records were udpated self.assertEqual(results, None) self.assertTrue('Added' in self.helper.saved_states[1].anomalyLabel) self.assertTrue(self.helper.saved_states[1].setByUser) # Verifies record added to KNN classifier knn = self.helper.clamodel._getAnomalyClassifier().getSelf()._knn knn.learn.assert_called_once_with(ANY, ANY, rowID=11) # Verifies records after added label is recomputed _updateState.assert_called_once_with(self.helper.saved_states[2]) @patch.object(CLAModelClassifierHelper, '_getStateAnomalyVector') @patch.object(CLAModelClassifierHelper, '_updateState') def testRemoveLabel(self, _updateState, _getStateAnomalyVector): classifier = self.helper.clamodel._getAnomalyClassifier().getSelf() classifier.getParameter.return_value = [10, 11, 12] classifier._knn._numPatterns = 3 classifier._knn.removeIds.side_effect = self.mockRemoveIds self.helper.saved_states = [] self.assertRaises( CLAModelInvalidRangeError, self.helper.removeLabels, ) # Invalid ranges self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.removeLabels, start=100, end=100) self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.removeLabels, start=-100, end=-100) self.helper.saved_states = [Mock(ROWID=10)] self.assertRaises(CLAModelInvalidRangeError, self.helper.removeLabels, start=100, end=-100) # Valid no threshold labels self.helper.saved_states = [ Mock(ROWID=10, anomalyLabel=["Test"], setByUser=False), Mock(ROWID=11, anomalyLabel=["Test"], setByUser=False), Mock(ROWID=12, anomalyLabel=["Test"], setByUser=True) ] results = self.helper.removeLabels(11, 12, "Test") self.assertEqual(results, {'status': 'success'}) self.assertTrue('Test' not in self.helper.saved_states[1].anomalyLabel) # Verifies records removed from KNN classifier knn = self.helper.clamodel._getAnomalyClassifier().getSelf()._knn self.assertEqual(knn.removeIds.mock_calls, [call([11]), call([])]) # Verifies records after removed record are updated _updateState.assert_called_once_with(self.helper.saved_states[2]) @patch.object(CLAModelClassifierHelper, '_getStateAnomalyVector') @patch.object(CLAModelClassifierHelper, '_updateState') def testRemoveLabelNoFilter(self, _updateState, _getStateAnomalyVector): classifier = self.helper.clamodel._getAnomalyClassifier().getSelf() values = {'categoryRecencyList': [10, 11, 12]} classifier.getParameter.side_effect = values.get classifier._knn._numPatterns = 3 classifier._knn.removeIds.side_effect = self.mockRemoveIds # Valid no threshold labels self.helper.saved_states = [ Mock(ROWID=10, anomalyLabel=["Test"], setByUser=False), Mock(ROWID=11, anomalyLabel=["Test"], setByUser=False), Mock(ROWID=12, anomalyLabel=["Test"], setByUser=True) ] results = self.helper.removeLabels(11, 12) self.assertEqual(results, {'status': 'success'}) self.assertTrue('Test' not in self.helper.saved_states[1].anomalyLabel) # Verifies records removed from KNN classifier knn = self.helper.clamodel._getAnomalyClassifier().getSelf()._knn self.assertEqual(knn.removeIds.mock_calls, [call([11]), call([])]) # Verifies records after removed record are updated _updateState.assert_called_once_with(self.helper.saved_states[2]) @patch.object(CLAModelClassifierHelper, '_updateState') def testSetGetThreshold(self, updateState): self.helper.saved_states = [Mock(), Mock(), Mock()] self.helper.setAutoDetectThreshold(1.0) self.assertAlmostEqual(self.helper._autoDetectThreshold, 1.0) self.assertEqual(len(updateState.mock_calls), len(self.helper.saved_states)) self.assertAlmostEqual(self.helper.getAutoDetectThreshold(), 1.0) self.assertRaises(Exception, self.helper.setAutoDetectThreshold, 'invalid') @patch.object(CLAModelClassifierHelper, '_updateState') def testSetGetWaitRecords(self, updateState): self.helper.saved_states = [ Mock(ROWID=10, anomalyLabel=["Test"], setByUser=False), Mock(ROWID=11, anomalyLabel=["Test"], setByUser=False), Mock(ROWID=12, anomalyLabel=["Test"], setByUser=True) ] self.helper.setAutoDetectWaitRecords(20) self.assertEqual(self.helper._autoDetectWaitRecords, 20) self.assertEqual(len(updateState.mock_calls), len(self.helper.saved_states)) self.assertEqual(self.helper.getAutoDetectWaitRecords(), 20) # Test invalid parameter type self.assertRaises(Exception, self.helper.setAutoDetectWaitRecords, 'invalid') # Test invalid value before first record ROWID in cache self.assertRaises(Exception, self.helper.setAutoDetectWaitRecords, 0) @patch.object(CLAModelClassifierHelper, '_addRecordToKNN') @patch.object(CLAModelClassifierHelper, '_deleteRecordsFromKNN') @patch.object(CLAModelClassifierHelper, '_recomputeRecordFromKNN') @patch.object(CLAModelClassifierHelper, '_categoryToLabelList') def testUpdateState(self, toLabelList, recompute, deleteRecord, addRecord): record = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": "", "anomalyLabel": ["Label"], "setByUser": False } # Test record not labeled and not above threshold deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectWaitRecords = 0 self.helper._autoDetectThreshold = 1.1 toLabelList.return_value = [] state = _CLAClassificationRecord(**record) self.helper._updateState(state) self.assertEqual(state.anomalyLabel, []) deleteRecord.assert_called_once_with([state]) # Test record not labeled and above threshold deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectThreshold = 0.5 toLabelList.return_value = [] state = _CLAClassificationRecord(**record) self.helper._updateState(state) self.assertEqual(state.anomalyLabel, \ [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL]) addRecord.assert_called_once_with(state) # Test record not labeled and above threshold during wait period deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectWaitRecords = 10 self.helper._autoDetectThreshold = 0.5 toLabelList.return_value = [] state = _CLAClassificationRecord(**record) self.helper._updateState(state) self.assertEqual(state.anomalyLabel, []) self.assertTrue(not addRecord.called) # Test record labeled and not above threshold deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectWaitRecords = 0 self.helper._autoDetectThreshold = 1.1 toLabelList.return_value = ["Label"] state = _CLAClassificationRecord(**record) self.helper._updateState(state) self.assertEqual(state.anomalyLabel, ["Label"]) self.assertTrue(not addRecord.called) # Test setByUser deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectThreshold = 1.1 toLabelList.return_value = ["Label 2"] recordCopy = copy.deepcopy(record) recordCopy['setByUser'] = True state = _CLAClassificationRecord(**recordCopy) self.helper._updateState(state) self.assertEqual( state.anomalyLabel, [recordCopy["anomalyLabel"][0], toLabelList.return_value[0]]) addRecord.assert_called_once_with(state) # Test removal of above threshold deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectThreshold = 1.1 toLabelList.return_value = [] recordCopy = copy.deepcopy(record) recordCopy['setByUser'] = True recordCopy['anomalyLabel'] = \ [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL, CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL + \ CLAModelClassifierHelper.AUTO_TAG] state = _CLAClassificationRecord(**recordCopy) self.helper._updateState(state) self.assertEqual(state.anomalyLabel, []) # Auto classified threshold deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectThreshold = 1.1 toLabelList.return_value = \ [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL] recordCopy = copy.deepcopy(record) recordCopy['setByUser'] = True recordCopy['anomalyLabel'] = \ [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL] state = _CLAClassificationRecord(**recordCopy) self.helper._updateState(state) self.assertEqual(state.anomalyLabel, [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL + \ CLAModelClassifierHelper.AUTO_TAG]) addRecord.assert_called_once_with(state) # Test precedence of threshold label above auto threshold label deleteRecord.reset_mock() addRecord.reset_mock() self.helper._autoDetectThreshold = 0.8 toLabelList.return_value = \ [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL, CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL + \ CLAModelClassifierHelper.AUTO_TAG] recordCopy = copy.deepcopy(record) recordCopy['setByUser'] = True recordCopy['anomalyLabel'] = \ [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL] state = _CLAClassificationRecord(**recordCopy) self.helper._updateState(state) self.assertEqual( state.anomalyLabel, [CLAModelClassifierHelper.AUTO_THRESHOLD_CLASSIFIED_LABEL]) addRecord.assert_called_once_with(state) @patch.object(CLAModelClassifierHelper, '_getStateAnomalyVector') def testAddRecordToKNN(self, getAnomalyVector): getAnomalyVector.return_value = "Vector" values = {'categoryRecencyList': [1, 2, 3]} classifier = self.helper.clamodel._getAnomalyClassifier().getSelf() classifier.getParameter.side_effect = values.get state = { "ROWID": 5, "anomalyScore": 1.0, "anomalyVector": "", "anomalyLabel": ["Label"], "setByUser": False } record = _CLAClassificationRecord(**state) # Test with record not already in KNN self.helper._addRecordToKNN(record) classifier._knn.learn.assert_called_once_with("Vector", ANY, rowID=state['ROWID']) self.assertTrue(not classifier._knn.prototypeSetCategory.called) classifier._knn.learn.reset_mock() # Test with record already in KNN values = {'categoryRecencyList': [1, 2, 3, 5]} classifier.getParameter.side_effect = values.get self.helper._addRecordToKNN(record) classifier._knn.prototypeSetCategory.assert_called_once_with(\ state['ROWID'], ANY) self.assertTrue(not classifier._knn.learn.called) @patch.object(CLAModelClassifierHelper, '_getStateAnomalyVector') def testDeleteRangeFromKNN(self, getAnomalyVector): getAnomalyVector.return_value = "Vector" values = {'categoryRecencyList': [1, 2, 3]} classifier = self.helper.clamodel._getAnomalyClassifier().getSelf() classifier.getParameter.side_effect = values.get classifier._knn._numPatterns = len(values['categoryRecencyList']) classifier._knn.removeIds.side_effect = self.mockRemoveIds # Test with record not already in KNN self.helper._deleteRangeFromKNN(start=1, end=3) classifier._knn.removeIds.assert_called_once_with([1, 2]) classifier._knn.removeIds.reset_mock() # Test with record already in KNN values = {'categoryRecencyList': [1, 2, 3, 5]} classifier.getParameter.side_effect = values.get self.helper._deleteRangeFromKNN(start=1) classifier._knn.removeIds.assert_called_once_with([1, 2, 3, 5]) @patch.object(CLAModelClassifierHelper, '_getStateAnomalyVector') def testRecomputeRecordFromKNN(self, getAnomalyVector): getAnomalyVector.return_value = "Vector" values = { 'categoryRecencyList': [1, 2, 3, 5, 6, 7, 8, 9], 'latestDists': numpy.array([0.7, 0.2, 0.5, 1, 0.3, 0.2, 0.1]), 'categories': ['A', 'B', 'C', 'D', 'E', 'F', 'G'] } classifier = self.helper.clamodel._getAnomalyClassifier().getSelf() classifier.getLatestDistances.return_value = values['latestDists'] classifier.getCategoryList.return_value = values['categories'] classifier.getParameter.side_effect = values.get state = { "ROWID": 5, "anomalyScore": 1.0, "anomalyVector": "", "anomalyLabel": ["Label"], "setByUser": False } record = _CLAClassificationRecord(**state) # Test finding best category before record - exists self.helper._classificationMaxDist = 0.4 self.helper._autoDetectWaitRecords = 0 result = self.helper._recomputeRecordFromKNN(record) self.assertEqual(result, 'B') # Test finding best category before record - does not exists self.helper._classificationMaxDist = 0.1 result = self.helper._recomputeRecordFromKNN(record) self.assertEqual(result, None) # Test finding best category before record - not record before record.ROWID = 0 self.helper._classificationMaxDist = 0.1 result = self.helper._recomputeRecordFromKNN(record) self.assertEqual(result, None) def testConstructClassificationVector(self): modelParams = {'__numRunCalls': 0} spVals = { 'params': { 'activeOutputCount': 5 }, 'output': { 'bottomUpOut': numpy.array([1, 1, 0, 0, 1]) } } tpVals = { 'params': { 'cellsPerColumn': 2, 'columnCount': 2 }, 'output': { 'lrnActive': numpy.array([1, 0, 0, 1]), 'topDownOut': numpy.array([1, 0, 0, 0, 1]) } } self.helper.clamodel.getParameter.side_effect = modelParams.get sp = self.helper.clamodel._getSPRegion() tp = self.helper.clamodel._getTPRegion() tpImp = tp.getSelf()._tfdr sp.getParameter.side_effect = spVals['params'].get sp.getOutputData.side_effect = spVals['output'].get self.helper._activeColumnCount = 5 tp.getParameter.side_effect = tpVals['params'].get tp.getOutputData.side_effect = tpVals['output'].get tpImp.getLearnActiveStateT.return_value = tpVals['output']['lrnActive'] # Test TP Cell vector self.helper._vectorType = 'tpc' vector = self.helper._constructClassificationRecord() self.assertEqual(vector.anomalyVector, tpImp.getLearnActiveStateT().nonzero()[0].tolist()) # Test SP and TP Column Error vector self.helper._vectorType = 'sp_tpe' self.helper._prevPredictedColumns = numpy.array([1, 0, 0, 0, 1]).nonzero()[0] vector = self.helper._constructClassificationRecord() self.assertEqual(vector.anomalyVector, [0, 1, 4]) self.helper._prevPredictedColumns = numpy.array([1, 0, 1, 0, 0]).nonzero()[0] vector = self.helper._constructClassificationRecord() self.assertEqual(vector.anomalyVector, [0, 1, 4, 7]) self.helper._vectorType = 'invalidType' self.assertRaises(TypeError, self.helper._constructClassificationRecord) @patch.object(CLAModelClassifierHelper, '_updateState') @patch.object(CLAModelClassifierHelper, '_constructClassificationRecord') def testCompute(self, createRecord, updateState): state = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": "Vector", "anomalyLabel": "Label" } record = _CLAClassificationRecord(**state) createRecord.return_value = record # Test add first record self.helper._history_length = 10 self.helper._autoDetectWaitRecords = 0 self.helper.saved_states = [] result = self.helper.compute() self.assertEqual(result, record) self.assertEqual(len(self.helper.saved_states), 1) updateState.assert_called_once_with(result) # Test add record before wait records updateState.reset_mock() self.helper._history_length = 10 self.helper._autoDetectWaitRecords = 10 self.helper.saved_states = [] result = self.helper.compute() self.assertEqual(result, record) self.assertEqual(len(self.helper.saved_states), 1) result = self.helper.compute() self.assertEqual(result, record) self.assertEqual(len(self.helper.saved_states), 2) self.assertTrue(not updateState.called) # Test exceeded cache length updateState.reset_mock() self.helper._history_length = 1 self.helper.saved_states = [] result = self.helper.compute() self.assertEqual(result, record) self.assertEqual(len(self.helper.saved_states), 1) result = self.helper.compute() self.assertEqual(result, record) self.assertEqual(len(self.helper.saved_states), 1) self.assertTrue(not updateState.called) def testCategoryToList(self): result = self.helper._categoryToLabelList(None) self.assertEqual(result, []) self.helper.saved_categories = ['A', 'B', 'C'] result = self.helper._categoryToLabelList(1) self.assertEqual(result, ['A']) result = self.helper._categoryToLabelList(4) self.assertEqual(result, ['C']) result = self.helper._categoryToLabelList(5) self.assertEqual(result, ['A', 'C']) def testGetAnomalyVector(self): state = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": [1, 4, 5], "anomalyLabel": "Label" } record = _CLAClassificationRecord(**state) self.helper._anomalyVectorLength = 10 vector = self.helper._getStateAnomalyVector(record) self.assertEqual(len(vector), self.helper._anomalyVectorLength) self.assertEqual(vector.nonzero()[0].tolist(), record.anomalyVector) # Tests for configuration ############################################################################# @patch.object(Configuration, 'get') def testConfiguration(self, configurationGet): conf = { 'nupic.model.temporalAnomaly.wait_records': 160, 'nupic.model.temporalAnomaly.auto_detect_threshold': 2.0, 'nupic.model.temporalAnomaly.window_length': 1111, 'nupic.model.temporalAnomaly.anomaly_vector': 'tpc' } configurationGet.side_effect = conf.get helper = CLAModelClassifierHelper(Mock(spec=CLAModel)) self.assertEqual(helper._autoDetectWaitRecords, conf['nupic.model.temporalAnomaly.wait_records']) self.assertTrue( helper._autoDetectThreshold, conf['nupic.model.temporalAnomaly.auto_detect_threshold']) self.assertTrue(helper._history_length, conf['nupic.model.temporalAnomaly.window_length']) self.assertTrue(helper._vectorType, conf['nupic.model.temporalAnomaly.anomaly_vector']) @patch.object(Configuration, 'get') def testConfigurationFail(self, configurationGet): conf = { 'nupic.model.temporalAnomaly.wait_records': 160, 'nupic.model.temporalAnomaly.anomaly_vector': 'tpc' } configurationGet.side_effect = conf.get self.assertRaises(TypeError, CLAModelClassifierHelper, Mock(spec=CLAModel)) @patch.object(Configuration, 'get') def testSetState(self, configurationGet): conf = { 'nupic.model.temporalAnomaly.wait_records': 160, 'nupic.model.temporalAnomaly.anomaly_vector': 'tpc' } configurationGet.side_effect = conf.get state = dict(_version=1, _classificationDelay=100) self.helper._vectorType = None state = self.helper.__setstate__(state) self.assertEqual(self.helper._vectorType, conf['nupic.model.temporalAnomaly.anomaly_vector']) self.assertEqual(self.helper._version, CLAModelClassifierHelper.__VERSION__) state = dict(_version=2, _classificationDelay=100) state = self.helper.__setstate__(state) self.assertEqual(self.helper._version, CLAModelClassifierHelper.__VERSION__) state = dict(_version="invalid") self.assertRaises(Exception, self.helper.__setstate__, state) # Tests for _CLAClassificationRecord class ############################################################################# def testCLAClassificationRecord(self): record = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": "Vector", "anomalyLabel": "Label" } state = _CLAClassificationRecord(**record) self.assertEqual(state.ROWID, record['ROWID']) self.assertEqual(state.anomalyScore, record['anomalyScore']) self.assertEqual(state.anomalyVector, record['anomalyVector']) self.assertEqual(state.anomalyLabel, record['anomalyLabel']) self.assertEqual(state.setByUser, False) record = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": "Vector", "anomalyLabel": "Label", "setByUser": True } state = _CLAClassificationRecord(**record) self.assertEqual(state.ROWID, record['ROWID']) self.assertEqual(state.anomalyScore, record['anomalyScore']) self.assertEqual(state.anomalyVector, record['anomalyVector']) self.assertEqual(state.anomalyLabel, record['anomalyLabel']) self.assertEqual(state.setByUser, record['setByUser']) def testCLAClassificationRecordGetState(self): record = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": "Vector", "anomalyLabel": "Label", "setByUser": False } state = _CLAClassificationRecord(**record) self.assertEqual(state.__getstate__(), record) def testCLAClassificationRecordSetState(self): record = { "ROWID": None, "anomalyScore": None, "anomalyVector": None, "anomalyLabel": None, "setByUser": None } state = _CLAClassificationRecord(**record) record = { "ROWID": 0, "anomalyScore": 1.0, "anomalyVector": "Vector", "anomalyLabel": "Label", "setByUser": False } state.__setstate__(record) self.assertEqual(state.ROWID, record['ROWID']) self.assertEqual(state.anomalyScore, record['anomalyScore']) self.assertEqual(state.anomalyVector, record['anomalyVector']) self.assertEqual(state.anomalyLabel, record['anomalyLabel']) self.assertEqual(state.setByUser, record['setByUser']) def mockRemoveIds(self, ids): self.helper.clamodel._getAnomalyClassifier().getSelf( )._knn._numPatterns -= len(ids) for idx in ids: if idx in self.helper.clamodel._getAnomalyClassifier().getSelf( ).getParameter('categoryRecencyList'): self.helper.clamodel._getAnomalyClassifier().getSelf( ).getParameter('categoryRecencyList').remove(idx)