diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f74f03c893..1d00ee56f4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -293,7 +293,6 @@ set(src_nupiccore_srcs nupic/algorithms/ClassifierResult.cpp nupic/algorithms/CondProbTable.cpp nupic/algorithms/Connections.cpp - nupic/algorithms/FastClaClassifier.cpp nupic/algorithms/GaborNode.cpp nupic/algorithms/ImageSensorLite.cpp nupic/algorithms/InSynapse.cpp @@ -521,7 +520,6 @@ add_executable(${src_executable_gtests} test/unit/algorithms/Cells4Test.cpp test/unit/algorithms/CondProbTableTest.cpp test/unit/algorithms/ConnectionsTest.cpp - test/unit/algorithms/FastCLAClassifierTest.cpp test/unit/algorithms/NearestNeighborUnitTest.cpp test/unit/algorithms/SDRClassifierTest.cpp test/unit/algorithms/SegmentTest.cpp diff --git a/src/nupic/algorithms/FastClaClassifier.cpp b/src/nupic/algorithms/FastClaClassifier.cpp deleted file mode 100644 index 7e440e472a..0000000000 --- a/src/nupic/algorithms/FastClaClassifier.cpp +++ /dev/null @@ -1,707 +0,0 @@ -/* --------------------------------------------------------------------- - * Numenta Platform for Intelligent Computing (NuPIC) - * Copyright (C) 2013-2015, 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 Affero 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 Affero Public License for more details. - * - * You should have received a copy of the GNU Affero Public License - * along with this program. If not, see http://www.gnu.org/licenses. - * - * http://numenta.org/licenses/ - * --------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -using namespace std; - -namespace nupic -{ - namespace algorithms - { - namespace cla_classifier - { - - FastCLAClassifier::FastCLAClassifier( - const vector& steps, Real64 alpha, Real64 actValueAlpha, - UInt verbosity) : alpha_(alpha), actValueAlpha_(actValueAlpha), - learnIteration_(0), recordNumMinusLearnIteration_(0), - maxBucketIdx_(0), version_(claClassifierVersion), - verbosity_(verbosity) - { - for (const auto & step : steps) - { - steps_.push_back(step); - } - recordNumMinusLearnIterationSet_ = false; - maxSteps_ = 0; - for (auto & elem : steps_) - { - UInt current = elem + 1; - if (current > maxSteps_) - { - maxSteps_ = current; - } - } - actualValues_.push_back(0.0); - actualValuesSet_.push_back(false); - } - - FastCLAClassifier::~FastCLAClassifier() - { - } - - void FastCLAClassifier::fastCompute( - UInt recordNum, const vector& patternNZ, UInt bucketIdx, - Real64 actValue, bool category, bool learn, bool infer, - ClassifierResult* result) - { - // Save the offset between recordNum and learnIteration_ if this is the - // first compute. - if (!recordNumMinusLearnIterationSet_) - { - recordNumMinusLearnIteration_ = recordNum - learnIteration_; - recordNumMinusLearnIterationSet_ = true; - } - - // Update the learn iteration. - learnIteration_ = recordNum - recordNumMinusLearnIteration_; - - // Update the input pattern history. - patternNZHistory_.emplace_front(patternNZ.begin(), patternNZ.end()); - - iterationNumHistory_.push_front(learnIteration_); - if (patternNZHistory_.size() > maxSteps_) - { - patternNZHistory_.pop_back(); - iterationNumHistory_.pop_back(); - } - - // If inference is enabled, compute the likelihoods and add them to the - // return value. - if (infer) - { - // Add the actual values to the return value. For buckets that haven't - // been seen yet, the actual value doesn't matter since it will have - // zero likelihood. - vector* actValueVector = result->createVector( - -1, actualValues_.size(), 0.0); - for (UInt i = 0; i < actualValues_.size(); ++i) - { - if (actualValuesSet_[i]) - { - (*actValueVector)[i] = actualValues_[i]; - } else { - // if doing 0-step ahead prediction, we shouldn't use any - // knowledge of the classification input during inference - if (steps_.at(0) == 0) - { - (*actValueVector)[i] = 0; - } else { - (*actValueVector)[i] = actValue; - } - } - } - - // Generate the predictions for each steps-ahead value - for (auto step = steps_.begin(); step != steps_.end(); ++step) - { - // Skip if we don't have data yet. - if (activeBitHistory_.find(*step) == activeBitHistory_.end()) - { - // This call creates the vector with specified default values. - result->createVector( - *step, actualValues_.size(), 1.0 / actualValues_.size()); - continue; - } - - vector* likelihoods = result->createVector( - *step, maxBucketIdx_ + 1, 0.0); - vector bitVotes(maxBucketIdx_ + 1, 0.0); - - for (const auto & elem : patternNZ) - { - if (activeBitHistory_[*step].find(elem) != - activeBitHistory_[*step].end()) - { - BitHistory& history = - activeBitHistory_[*step].find(elem)->second; - for (auto & bitVote : bitVotes) { - bitVote = 0.0; - } - history.infer(learnIteration_, &bitVotes); - for (UInt i = 0; i < bitVotes.size(); ++i) { - (*likelihoods)[i] += bitVotes[i]; - } - } - } - Real64 total = 0.0; - for (auto & likelihood : *likelihoods) - { - total += likelihood; - } - for (auto & likelihood : *likelihoods) - { - if (total > 0.0) - { - likelihood = likelihood / total; - } else { - likelihood = 1.0 / likelihoods->size(); - } - } - } - } - - // If learning is enabled, update the bit histories. - if (learn) - { - // Update the predicted actual values for each bucket. - if (bucketIdx > maxBucketIdx_) - { - maxBucketIdx_ = bucketIdx; - } - while (actualValues_.size() <= maxBucketIdx_) - { - actualValues_.push_back(0.0); - actualValuesSet_.push_back(false); - } - if (!actualValuesSet_[bucketIdx] || category) - { - actualValues_[bucketIdx] = actValue; - actualValuesSet_[bucketIdx] = true; - } else { - actualValues_[bucketIdx] = - ((1.0 - actValueAlpha_) * actualValues_[bucketIdx]) + - (actValueAlpha_ * actValue); - } - - for (auto & elem : steps_) - { - UInt step = elem; - - // Check if there is a pattern that should be assigned to this - // classification in our history. If not, skip it. - bool found = false; - deque>::const_iterator patternIteration = - patternNZHistory_.begin(); - for (deque::const_iterator learnIteration = - iterationNumHistory_.begin(); - learnIteration !=iterationNumHistory_.end(); - ++learnIteration, ++patternIteration) - { - if (*learnIteration == (learnIteration_ - step)) - { - found = true; - break; - } - } - if (!found) - { - continue; - } - - // Store classification info for each active bit from the pattern - // that we got step time steps ago. - const vector learnPatternNZ = *patternIteration; - for (auto & learnPatternNZ_j : learnPatternNZ) - { - UInt bit = learnPatternNZ_j; - // This will implicitly insert the key "step" into the map if it - // doesn't exist yet. - auto it = activeBitHistory_[step].find(bit); - if (it == activeBitHistory_[step].end()) - { - activeBitHistory_[step][bit] = - BitHistory(bit, step, alpha_, verbosity_); - } - activeBitHistory_[step][bit].store(learnIteration_, bucketIdx); - } - } - } - } - - UInt FastCLAClassifier::persistentSize() const - { - // TODO: this won't scale! - stringstream s; - s.flags(ios::scientific); - s.precision(numeric_limits::digits10 + 1); - save(s); - return s.str().size(); - } - - void FastCLAClassifier::save(ostream& outStream) const - { - // Write a starting marker and version. - outStream << "FastCLAClassifier" << endl; - outStream << version_ << endl; - - // Store the simple variables first. - outStream << version() << " " - << alpha_ << " " - << actValueAlpha_ << " " - << learnIteration_ << " " - << maxSteps_ << " " - << maxBucketIdx_ << " " - << verbosity_ << " " - << endl; - - // V1 additions. - outStream << recordNumMinusLearnIteration_ << " " - << recordNumMinusLearnIterationSet_ << " "; - outStream << iterationNumHistory_.size() << " "; - for (const auto & elem : iterationNumHistory_) - { - outStream << elem << " "; - } - outStream << endl; - - // Store the different prediction steps. - outStream << steps_.size() << " "; - for (auto & elem : steps_) - { - outStream << elem << " "; - } - outStream << endl; - - // Store the input pattern history. - outStream << patternNZHistory_.size() << " "; - for (auto & pattern : patternNZHistory_) - { - outStream << pattern.size() << " "; - for (auto & pattern_j : pattern) - { - outStream << pattern_j << " "; - } - } - outStream << endl; - - // Store the bucket duty cycles. - outStream << activeBitHistory_.size() << " "; - for (const auto & elem : activeBitHistory_) - { - outStream << elem.first << " "; - outStream << elem.second.size() << " "; - for (auto it2 = elem.second.begin(); it2 != elem.second.end(); ++it2) - { - outStream << it2->first << " "; - it2->second.save(outStream); - } - } - - // Store the actual values for each bucket. - outStream << actualValues_.size() << " "; - for (UInt i = 0; i < actualValues_.size(); ++i) - { - outStream << actualValues_[i] << " "; - outStream << actualValuesSet_[i] << " "; - } - outStream << endl; - - // Write an ending marker. - outStream << "~FastCLAClassifier" << endl; - - } - - void FastCLAClassifier::load(istream& inStream) - { - // Clean up the existing data structures before loading - steps_.clear(); - iterationNumHistory_.clear(); - patternNZHistory_.clear(); - actualValues_.clear(); - actualValuesSet_.clear(); - activeBitHistory_.clear(); - - // Check the starting marker. - string marker; - inStream >> marker; - NTA_CHECK(marker == "FastCLAClassifier"); - - // Check the version. - UInt version; - inStream >> version; - NTA_CHECK(version <= 1); - - // Load the simple variables. - inStream >> version_ - >> alpha_ - >> actValueAlpha_ - >> learnIteration_ - >> maxSteps_ - >> maxBucketIdx_ - >> verbosity_; - - // V1 additions. - UInt numIterationHistory; - UInt curIterationNum; - if (version == 1) - { - inStream >> recordNumMinusLearnIteration_ - >> recordNumMinusLearnIterationSet_; - inStream >> numIterationHistory; - for (UInt i = 0; i < numIterationHistory; ++i) - { - inStream >> curIterationNum; - iterationNumHistory_.push_back(curIterationNum); - } - } else { - recordNumMinusLearnIterationSet_ = false; - } - - // Load the prediction steps. - UInt size; - UInt step; - inStream >> size; - for (UInt i = 0; i < size; ++i) - { - inStream >> step; - steps_.push_back(step); - } - - // Load the input pattern history. - inStream >> size; - UInt vSize; - for (UInt i = 0; i < size; ++i) - { - inStream >> vSize; - patternNZHistory_.emplace_back(vSize); - for (UInt j = 0; j < vSize; ++j) - { - inStream >> patternNZHistory_[i][j]; - } - if (version == 0) - { - iterationNumHistory_.push_back( - learnIteration_ - (size - i)); - } - } - - // Load the bucket duty cycles. - UInt numSteps; - UInt numInputBits; - UInt inputBit; - inStream >> numSteps; - for (UInt i = 0; i < numSteps; ++i) - { - inStream >> step; - // Insert the step to initialize the BitHistory - activeBitHistory_[step]; - inStream >> numInputBits; - for (UInt j = 0; j < numInputBits; ++j) - { - inStream >> inputBit; - activeBitHistory_[step][inputBit].load(inStream); - } - } - - // Load the actual values for each bucket. - UInt numBuckets; - Real64 actualValue; - bool actualValueSet; - inStream >> numBuckets; - for (UInt i = 0; i < numBuckets; ++i) - { - inStream >> actualValue; - actualValues_.push_back(actualValue); - inStream >> actualValueSet; - actualValuesSet_.push_back(actualValueSet); - } - - // Check for the end marker. - inStream >> marker; - NTA_CHECK(marker == "~FastCLAClassifier"); - - // Update the version number. - version_ = claClassifierVersion; - } - - void FastCLAClassifier::write(ClaClassifierProto::Builder& proto) const - { - auto stepsProto = proto.initSteps(steps_.size()); - for (UInt i = 0; i < steps_.size(); i++) - { - stepsProto.set(i, steps_[i]); - } - - proto.setAlpha(alpha_); - proto.setActValueAlpha(actValueAlpha_); - proto.setLearnIteration(learnIteration_); - proto.setRecordNumMinusLearnIteration(recordNumMinusLearnIteration_); - proto.setRecordNumMinusLearnIterationSet( - recordNumMinusLearnIterationSet_); - proto.setMaxSteps(maxSteps_); - - auto patternNZHistoryProto = - proto.initPatternNZHistory(patternNZHistory_.size()); - for (UInt i = 0; i < patternNZHistory_.size(); i++) - { - const auto & pattern = patternNZHistory_[i]; - auto patternProto = patternNZHistoryProto.init(i, pattern.size()); - for (UInt j = 0; j < pattern.size(); j++) - { - patternProto.set(j, pattern[j]); - } - } - - auto iterationNumHistoryProto = - proto.initIterationNumHistory(iterationNumHistory_.size()); - for (UInt i = 0; i < iterationNumHistory_.size(); i++) - { - iterationNumHistoryProto.set(i, iterationNumHistory_[i]); - } - - auto activeBitHistoryProtos = - proto.initActiveBitHistory(activeBitHistory_.size()); - UInt i = 0; - for (const auto & stepBitHistory : activeBitHistory_) - { - auto stepBitHistoryProto = activeBitHistoryProtos[i]; - stepBitHistoryProto.setSteps(stepBitHistory.first); - auto indexBitHistoryListProto = - stepBitHistoryProto.initBitHistories(stepBitHistory.second.size()); - UInt j = 0; - for (const auto & indexBitHistory : stepBitHistory.second) - { - auto indexBitHistoryProto = indexBitHistoryListProto[j]; - indexBitHistoryProto.setIndex(indexBitHistory.first); - auto bitHistoryProto = indexBitHistoryProto.initHistory(); - indexBitHistory.second.write(bitHistoryProto); - j++; - } - i++; - } - - proto.setMaxBucketIdx(maxBucketIdx_); - - auto actualValuesProto = proto.initActualValues(actualValues_.size()); - for (UInt i = 0; i < actualValues_.size(); i++) - { - actualValuesProto.set(i, actualValues_[i]); - } - - auto actualValuesSetProto = - proto.initActualValuesSet(actualValuesSet_.size()); - for (UInt i = 0; i < actualValuesSet_.size(); i++) - { - actualValuesSetProto.set(i, actualValuesSet_[i]); - } - - proto.setVersion(version_); - proto.setVerbosity(verbosity_); - } - - void FastCLAClassifier::read(ClaClassifierProto::Reader& proto) - { - // Clean up the existing data structures before loading - steps_.clear(); - iterationNumHistory_.clear(); - patternNZHistory_.clear(); - actualValues_.clear(); - actualValuesSet_.clear(); - activeBitHistory_.clear(); - - for (auto step : proto.getSteps()) - { - steps_.push_back(step); - } - - alpha_ = proto.getAlpha(); - actValueAlpha_ = proto.getActValueAlpha(); - learnIteration_ = proto.getLearnIteration(); - recordNumMinusLearnIteration_ = proto.getRecordNumMinusLearnIteration(); - recordNumMinusLearnIterationSet_ = - proto.getRecordNumMinusLearnIterationSet(); - maxSteps_ = proto.getMaxSteps(); - - auto patternNZHistoryProto = proto.getPatternNZHistory(); - for (UInt i = 0; i < patternNZHistoryProto.size(); i++) - { - patternNZHistory_.emplace_back(patternNZHistoryProto[i].size()); - for (UInt j = 0; j < patternNZHistoryProto[i].size(); j++) - { - patternNZHistory_[i][j] = patternNZHistoryProto[i][j]; - } - } - - auto iterationNumHistoryProto = proto.getIterationNumHistory(); - for (UInt i = 0; i < iterationNumHistoryProto.size(); i++) - { - iterationNumHistory_.push_back(iterationNumHistoryProto[i]); - } - - auto activeBitHistoryProto = proto.getActiveBitHistory(); - for (UInt i = 0; i < activeBitHistoryProto.size(); i++) - { - auto stepBitHistories = activeBitHistoryProto[i]; - UInt steps = stepBitHistories.getSteps(); - for (auto indexBitHistoryProto : stepBitHistories.getBitHistories()) - { - BitHistory& bitHistory = - activeBitHistory_[steps][indexBitHistoryProto.getIndex()]; - auto bitHistoryProto = indexBitHistoryProto.getHistory(); - bitHistory.read(bitHistoryProto); - } - } - - maxBucketIdx_ = proto.getMaxBucketIdx(); - - for (auto actValue : proto.getActualValues()) - { - actualValues_.push_back(actValue); - } - - for (auto actValueSet : proto.getActualValuesSet()) - { - actualValuesSet_.push_back(actValueSet); - } - - version_ = proto.getVersion(); - verbosity_ = proto.getVerbosity(); - } - - bool FastCLAClassifier::operator==(const FastCLAClassifier& other) const - { - if (steps_.size() != other.steps_.size()) - { - return false; - } - for (UInt i = 0; i < steps_.size(); i++) - { - if (steps_.at(i) != other.steps_.at(i)) - { - return false; - } - } - - if (fabs(alpha_ - other.alpha_) > 0.000001 || - fabs(actValueAlpha_ - other.actValueAlpha_) > 0.000001 || - learnIteration_ != other.learnIteration_ || - recordNumMinusLearnIteration_ != - other.recordNumMinusLearnIteration_ || - recordNumMinusLearnIterationSet_ != - other.recordNumMinusLearnIterationSet_ || - maxSteps_ != other.maxSteps_) - { - return false; - } - - if (patternNZHistory_.size() != other.patternNZHistory_.size()) - { - return false; - } - for (UInt i = 0; i < patternNZHistory_.size(); i++) - { - if (patternNZHistory_.at(i).size() != - other.patternNZHistory_.at(i).size()) - { - return false; - } - for (UInt j = 0; j < patternNZHistory_.at(i).size(); j++) - { - if (patternNZHistory_.at(i).at(j) != - other.patternNZHistory_.at(i).at(j)) - { - return false; - } - } - } - - if (iterationNumHistory_.size() != - other.iterationNumHistory_.size()) - { - return false; - } - for (UInt i = 0; i < iterationNumHistory_.size(); i++) - { - if (iterationNumHistory_.at(i) != - other.iterationNumHistory_.at(i)) - { - return false; - } - } - - if (activeBitHistory_.size() != other.activeBitHistory_.size()) - { - return false; - } - for (auto it1 = activeBitHistory_.begin(); - it1 != activeBitHistory_.end(); it1++) - { - auto thisInnerMap = it1->second; - auto otherInnerMap = other.activeBitHistory_.at(it1->first); - if (thisInnerMap.size() != otherInnerMap.size()) - { - return false; - } - for (auto it2 = thisInnerMap.begin(); it2 != thisInnerMap.end(); - it2++) - { - auto thisBitHistory = it2->second; - auto otherBitHistory = otherInnerMap.at(it2->first); - if (thisBitHistory != otherBitHistory) - { - return false; - } - } - } - - if (maxBucketIdx_ != other.maxBucketIdx_) - { - return false; - } - - if (actualValues_.size() != other.actualValues_.size() || - actualValuesSet_.size() != other.actualValuesSet_.size()) - { - return false; - } - for (UInt i = 0; i < actualValues_.size(); i++) - { - if (fabs(actualValues_[i] - other.actualValues_[i]) > 0.000001 || - fabs(actualValuesSet_[i] - other.actualValuesSet_[i]) > 0.00001) - { - return false; - } - } - - if (version_ != other.version_ || - verbosity_ != other.verbosity_) - { - return false; - } - - return true; - } - - } // end namespace cla_classifier - } // end namespace algorithms -} // end namespace nupic diff --git a/src/nupic/algorithms/FastClaClassifier.hpp b/src/nupic/algorithms/FastClaClassifier.hpp deleted file mode 100644 index 9b0244eed1..0000000000 --- a/src/nupic/algorithms/FastClaClassifier.hpp +++ /dev/null @@ -1,203 +0,0 @@ -/* --------------------------------------------------------------------- - * Numenta Platform for Intelligent Computing (NuPIC) - * Copyright (C) 2013-2015, 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 Affero 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 Affero Public License for more details. - * - * You should have received a copy of the GNU Affero Public License - * along with this program. If not, see http://www.gnu.org/licenses. - * - * http://numenta.org/licenses/ - * --------------------------------------------------------------------- - */ - -/** @file - * Definitions for the CLAClassifier. - */ - -#ifndef NTA_fast_cla_classifier_HPP -#define NTA_fast_cla_classifier_HPP - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace nupic -{ - namespace algorithms - { - namespace cla_classifier - { - - const UInt claClassifierVersion = 1; - - class BitHistory; - class ClassifierResult; - - /** CLA classifier implementation in C++. - * - * @b Responsibility - * The CLAClassifier is responsible for computing the likelihoods for - * each bucket when given an input pattern from the level below. This - * includes keeping track of past inputs and learning how each input bit - * history predicts future bucket values. - * - * @b Description - * The input pattern history is stored as patternNZHistory_ and the duty - * cycles are stored in BitHistory objects in activeBitHistory_. - * - */ - class FastCLAClassifier : public Serializable - { - public: - - /** - * Constructor for use when deserializing. - */ - FastCLAClassifier() {} - - /** - * Constructor. - * - * @param steps The different number of steps to learn and predict. - * @param alpha The alpha to use when decaying the duty cycles. - * @param actValueAlpha The alpha to use when decaying the actual - * values for each bucket. - * @param verbosity The logging verbosity. - */ - FastCLAClassifier( - const vector& steps, Real64 alpha, Real64 actValueAlpha, - UInt verbosity); - - /** - * Destructor. - */ - virtual ~FastCLAClassifier(); - - /** - * Compute the likelihoods for each bucket. - * - * @param recordNum An incrementing integer for each record. Gaps in - * numbers correspond to missing records. - * @param patternNZ The active input bit indices. - * @param bucketIdx The current value bucket index. - * @param actValue The current scalar value. - * @param category Whether the actual values represent categories. - * @param learn Whether or not to perform learning. - * @param infer Whether or not to perform inference. - * @param result A mapping from prediction step to a vector of - * likelihoods where the value at an index corresponds - * to the bucket with the same index. In addition, the - * values for key 0 correspond to the actual values to - * used when predicting each bucket. - */ - virtual void fastCompute( - UInt recordNum, const vector& patternNZ, UInt bucketIdx, - Real64 actValue, bool category, bool learn, bool infer, - ClassifierResult* result); - - UInt version() const - { - return version_; - } - - /** - * Get the size of the string needed for the serialized state. - */ - UInt persistentSize() const; - - /** - * Save the state to the ostream. - */ - void save(std::ostream& outStream) const; - - /** - * Load state from istream. - */ - void load(std::istream& inStream); - - /** - * Save the state to the builder. - */ - void write(ClaClassifierProto::Builder& proto) const override; - - /** - * Save the state to the stream. - */ - using Serializable::write; - - /** - * Load state from reader. - */ - void read(ClaClassifierProto::Reader& proto) override; - - /** - * Load state from stream. - */ - using Serializable::read; - - /** - * Compare the other instance to this one. - * - * @param other Another instance of FastCLAClassifier to compare to. - * @returns true iff other is identical to this instance. - */ - virtual bool operator==(const FastCLAClassifier& other) const; - - private: - // The list of prediction steps to learn and infer. - vector steps_; - // The alpha used to decay the duty cycles in the BitHistorys. - Real64 alpha_; - // The alpha used to decay the actual values used for each bucket. - Real64 actValueAlpha_; - // An incrementing count of the number of learning iterations that - // have been performed. - UInt learnIteration_; - // This contains the offset between the recordNum (provided by - // caller) and learnIteration (internal only, always starts at 0). - UInt recordNumMinusLearnIteration_; - bool recordNumMinusLearnIterationSet_; - // The maximum number of the prediction steps. - UInt maxSteps_; - // Stores the input pattern history, starting with the previous input - // and containing _maxSteps total input patterns. - deque< vector > patternNZHistory_; - deque iterationNumHistory_; - // Mapping from the number of steps in the future to predict to the - // input bit index to a BitHistory that contains the duty cycles for - // each bucket. - map< UInt, map > activeBitHistory_; - // The highest bucket index that has been seen so far. - UInt maxBucketIdx_; - // The current actual values used for each bucket index. The index of - // the actual value matches the index of the bucket. - vector actualValues_; - // A boolean that distinguishes between actual values that have been - // seen and those that have not. - vector actualValuesSet_; - UInt version_; - UInt verbosity_; - }; // end class FastCLAClassifier - - } // end namespace cla_classifier - } // end namespace algorithms -} // end namespace nupic - -#endif // NTA_fast_cla_classifier_HPP diff --git a/src/nupic/bindings/algorithms.i b/src/nupic/bindings/algorithms.i index df47f76511..a7ebd2b123 100644 --- a/src/nupic/bindings/algorithms.i +++ b/src/nupic/bindings/algorithms.i @@ -92,7 +92,6 @@ _ALGORITHMS = _algorithms #include #include #include -#include #include #include #include @@ -1255,175 +1254,6 @@ void forceRetentionOfImageSensorLiteLibrary(void) { } -%include - -%pythoncode %{ - import numpy -%} - -%extend nupic::algorithms::cla_classifier::FastCLAClassifier -{ - %pythoncode %{ - VERSION = 0 - - def __init__(self, steps=(1,), alpha=0.001, actValueAlpha=0.3, verbosity=0): - self.this = _ALGORITHMS.new_FastCLAClassifier( - steps, alpha, actValueAlpha, verbosity) - self.valueToCategory = {} - self.version = FastCLAClassifier.VERSION - - def compute(self, recordNum, patternNZ, classification, learn, infer): - isNone = False - noneSentinel = 3.14159 - - if type(classification["actValue"]) in (int, float): - actValue = classification["actValue"] - category = False - elif classification["actValue"] is None: - # Use the sentinel value so we know if it gets used in actualValues - # returned. - actValue = noneSentinel - # Turn learning off this step. - learn = False - category = False - # This does not get used when learning is disabled anyway. - classification["bucketIdx"] = 0 - isNone = True - else: - actValue = int(classification["bucketIdx"]) - category = True - - result = self.convertedCompute( - recordNum, patternNZ, int(classification["bucketIdx"]), - actValue, category, learn, infer) - - if isNone: - for i, v in enumerate(result["actualValues"]): - if v - noneSentinel < 0.00001: - result["actualValues"][i] = None - arrayResult = dict((k, numpy.array(v)) if k != "actualValues" else (k, v) - for k, v in result.iteritems()) - - if self.valueToCategory or isinstance(classification["actValue"], basestring): - # Convert the bucketIdx back to the original value. - for i in xrange(len(arrayResult["actualValues"])): - if arrayResult["actualValues"][i] is not None: - arrayResult["actualValues"][i] = self.valueToCategory.get(int( - arrayResult["actualValues"][i]), classification["actValue"]) - - self.valueToCategory[actValue] = classification["actValue"] - - return arrayResult - - def __getstate__(self): - # Save the local attributes but override the C++ classifier with the - # string representation. - d = dict(self.__dict__) - d["this"] = self.getCState() - return d - - def __setstate__(self, state): - # Create an empty C++ classifier and populate it from the serialized - # string. - self.this = _ALGORITHMS.new_FastCLAClassifier() - if isinstance(state, str): - self.loadFromString(state) - self.valueToCategory = {} - else: - assert state["version"] == 0 - self.loadFromString(state["this"]) - # Use the rest of the state to set local Python attributes. - del state["this"] - self.__dict__.update(state) - - @classmethod - def read(cls, proto): - instance = cls() - instance.convertedRead(proto) - return instance - - def write(self, pyBuilder): - """Serialize the FastCLAClassifier instance using capnp. - - :param: Destination ClaClassifierProto message builder - """ - reader = ClaClassifierProto.from_bytes(self._writeAsCapnpPyBytes()) # copy - pyBuilder.from_dict(reader.to_dict()) # copy - - - def convertedRead(self, proto): - """Initialize the FastCLAClassifier instance from the given - ClaClassifierProto reader. - - :param proto: ClaClassifierProto message reader containing data from a - previously serialized SpatialPooler instance. - - """ - self._initFromCapnpPyBytes(proto.as_builder().to_bytes()) # copy * 2 - %} - - void loadFromString(const std::string& inString) - { - std::istringstream inStream(inString); - self->load(inStream); - } - - PyObject* getCState() - { - SharedPythonOStream py_s(self->persistentSize()); - std::ostream& s = py_s.getStream(); - // TODO: Consider writing floats as binary instead. - s.flags(ios::scientific); - s.precision(numeric_limits::digits10 + 1); - self->save(s); - return py_s.close(); - } - - PyObject* convertedCompute(UInt recordNum, const vector& patternNZ, - UInt bucketIdx, Real64 actValue, bool category, - bool learn, bool infer) - { - ClassifierResult result; - self->fastCompute(recordNum, patternNZ, bucketIdx, actValue, category, - learn, infer, &result); - PyObject* d = PyDict_New(); - for (map*>::const_iterator it = result.begin(); - it != result.end(); ++it) - { - PyObject* key; - if (it->first == -1) - { - key = PyString_FromString("actualValues"); - } else { - key = PyInt_FromLong(it->first); - } - - PyObject* value = PyList_New(it->second->size()); - for (UInt i = 0; i < it->second->size(); ++i) - { - PyObject* pyActValue = PyFloat_FromDouble(it->second->at(i)); - PyList_SetItem(value, i, pyActValue); - } - - PyDict_SetItem(d, key, value); - Py_DECREF(value); - } - return d; - } - - inline PyObject* _writeAsCapnpPyBytes() const - { - return nupic::PyCapnpHelper::writeAsPyBytes(*self); - } - - inline void _initFromCapnpPyBytes(PyObject* pyBytes) - { - nupic::PyCapnpHelper::initFromPyBytes(*self, pyBytes); - } - -} - - %include %pythoncode %{ diff --git a/src/test/unit/algorithms/FastCLAClassifierTest.cpp b/src/test/unit/algorithms/FastCLAClassifierTest.cpp deleted file mode 100644 index d433a7075e..0000000000 --- a/src/test/unit/algorithms/FastCLAClassifierTest.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* --------------------------------------------------------------------- - * Numenta Platform for Intelligent Computing (NuPIC) - * Copyright (C) 2013-2015, 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 Affero 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 Affero Public License for more details. - * - * You should have received a copy of the GNU Affero Public License - * along with this program. If not, see http://www.gnu.org/licenses. - * - * http://numenta.org/licenses/ - * --------------------------------------------------------------------- - */ - -/** @file - * Implementation of unit tests for NearestNeighbor - */ - -#include -#include - -#include - -#include -#include -#include -#include -#include - -using namespace std; -using namespace nupic; -using namespace nupic::algorithms::cla_classifier; - -namespace -{ - - TEST(FastCLAClassifierTest, Basic) - { - vector steps; - steps.push_back(1); - FastCLAClassifier c = FastCLAClassifier(steps, 0.1, 0.1, 0); - - // Create a vector of input bit indices - vector input1; - input1.push_back(1); - input1.push_back(5); - input1.push_back(9); - ClassifierResult result1; - c.fastCompute(0, input1, 4, 34.7, false, true, true, &result1); - - // Create a vector of input bit indices - vector input2; - input2.push_back(1); - input2.push_back(5); - input2.push_back(9); - ClassifierResult result2; - c.fastCompute(1, input2, 4, 34.7, false, true, true, &result2); - - { - bool foundMinus1 = false; - bool found1 = false; - for (auto it = result2.begin(); - it != result2.end(); ++it) - { - if (it->first == -1) - { - // The -1 key is used for the actual values - ASSERT_EQ(false, foundMinus1) - << "already found key -1 in classifier result"; - foundMinus1 = true; - ASSERT_EQ((long unsigned int)5, it->second->size()) - << "Expected five buckets since it has only seen bucket 4 (so it " - << "has buckets 0-4)."; - ASSERT_TRUE(fabs(it->second->at(4) - 34.7) < 0.000001) - << "Incorrect actual value for bucket 4"; - } else if (it->first == 1) { - // Check the one-step prediction - ASSERT_EQ(false, found1) - << "already found key 1 in classifier result"; - found1 = true; - ASSERT_EQ((long unsigned int)5, it->second->size()) - << "expected five bucket predictions"; - ASSERT_LT(fabs(it->second->at(0) - 0.2), 0.000001) - << "incorrect prediction for bucket 0"; - ASSERT_LT(fabs(it->second->at(1) - 0.2), 0.000001) - << "incorrect prediction for bucket 1"; - ASSERT_LT(fabs(it->second->at(2) - 0.2), 0.000001) - << "incorrect prediction for bucket 2"; - ASSERT_LT(fabs(it->second->at(3) - 0.2), 0.000001) - << "incorrect prediction for bucket 3"; - ASSERT_LT(fabs(it->second->at(4) - 0.2), 0.000001) - << "incorrect prediction for bucket 4"; - } - } - ASSERT_TRUE(foundMinus1) << "key -1 not found in classifier result"; - ASSERT_TRUE(found1) << "key 1 not found in classifier result"; - } - } - - TEST(FastCLAClassifierTest, SaveLoad) - { - vector steps; - steps.push_back(1); - FastCLAClassifier c1 = FastCLAClassifier(steps, 0.1, 0.1, 0); - FastCLAClassifier c2 = FastCLAClassifier(steps, 0.1, 0.1, 0); - - // Create a vector of input bit indices - vector input1; - input1.push_back(1); - input1.push_back(5); - input1.push_back(9); - ClassifierResult result; - c1.fastCompute(0, input1, 4, 34.7, false, true, true, &result); - - { - stringstream ss; - c1.save(ss); - c2.load(ss); - } - - ASSERT_TRUE(c1 == c2); - - ClassifierResult result1, result2; - c1.fastCompute(1, input1, 4, 35.7, false, true, true, &result1); - c2.fastCompute(1, input1, 4, 35.7, false, true, true, &result2); - - ASSERT_TRUE(result1 == result2); - } - - TEST(FastCLAClassifierTest, WriteRead) - { - vector steps; - steps.push_back(1); - FastCLAClassifier c1 = FastCLAClassifier(steps, 0.1, 0.1, 0); - FastCLAClassifier c2 = FastCLAClassifier(steps, 0.1, 0.1, 0); - - // Create a vector of input bit indices - vector input1; - input1.push_back(1); - input1.push_back(5); - input1.push_back(9); - ClassifierResult result; - c1.fastCompute(0, input1, 4, 34.7, false, true, true, &result); - - { - stringstream ss; - c1.write(ss); - c2.read(ss); - } - - ASSERT_TRUE(c1 == c2); - - ClassifierResult result1, result2; - c1.fastCompute(1, input1, 4, 35.7, false, true, true, &result1); - c2.fastCompute(1, input1, 4, 35.7, false, true, true, &result2); - - ASSERT_TRUE(result1 == result2); - } - -} // end namespace diff --git a/src/test/unit/algorithms/SDRClassifierTest.cpp b/src/test/unit/algorithms/SDRClassifierTest.cpp index 134cd9e3f2..dbd6922eb6 100644 --- a/src/test/unit/algorithms/SDRClassifierTest.cpp +++ b/src/test/unit/algorithms/SDRClassifierTest.cpp @@ -130,7 +130,7 @@ namespace vector bucketIdxList; bucketIdxList.push_back(4); vector actValueList; - actValueList.push_back(34.7); + actValueList.push_back(34.7); ClassifierResult result1; for (UInt i = 0; i < 10; ++i) { @@ -302,40 +302,40 @@ namespace for(int i=0; i<1000; i++) { ClassifierResult result1; - ClassifierResult result2; - c.compute(recordNum, input1, bucketIdxList1, actValueList1, false, true, true, &result1); + ClassifierResult result2; + c.compute(recordNum, input1, bucketIdxList1, actValueList1, false, true, true, &result1); recordNum += 1; c.compute(recordNum, input2, bucketIdxList2, actValueList2, false, true, true, &result2); recordNum += 1; } ClassifierResult result1; - ClassifierResult result2; - c.compute(recordNum, input1, bucketIdxList1, actValueList1, false, true, true, &result1); + ClassifierResult result2; + c.compute(recordNum, input1, bucketIdxList1, actValueList1, false, true, true, &result1); recordNum += 1; c.compute(recordNum, input2, bucketIdxList2, actValueList2, false, true, true, &result2); recordNum += 1; - + for (auto it = result1.begin(); it != result1.end(); ++it) { if (it->first == 0) { ASSERT_LT(fabs(it->second->at(0) - 0.5), 0.1) - << "Incorrect prediction for bucket 0 (expected=0.5)"; + << "Incorrect prediction for bucket 0 (expected=0.5)"; ASSERT_LT(fabs(it->second->at(1) - 0.5), 0.1) - << "Incorrect prediction for bucket 1 (expected=0.5)"; + << "Incorrect prediction for bucket 1 (expected=0.5)"; } } - + for (auto it = result2.begin(); it != result2.end(); ++it) { if (it->first == 0) { ASSERT_LT(fabs(it->second->at(2) - 0.5), 0.1) - << "Incorrect prediction for bucket 2 (expected=0.5)"; + << "Incorrect prediction for bucket 2 (expected=0.5)"; ASSERT_LT(fabs(it->second->at(3) - 0.5), 0.1) - << "Incorrect prediction for bucket 3 (expected=0.5)"; + << "Incorrect prediction for bucket 3 (expected=0.5)"; } } - + } TEST(SDRClassifierTest, SaveLoad) @@ -353,7 +353,7 @@ namespace vector bucketIdxList1; bucketIdxList1.push_back(4); vector actValueList1; - actValueList1.push_back(34.7); + actValueList1.push_back(34.7); ClassifierResult result; c1.compute(0, input1, bucketIdxList1, actValueList1, false, true, true, &result); @@ -388,7 +388,7 @@ namespace vector bucketIdxList1; bucketIdxList1.push_back(4); vector actValueList1; - actValueList1.push_back(34.7); + actValueList1.push_back(34.7); ClassifierResult trainResult1; c1.compute(0, input1, bucketIdxList1, actValueList1, false, true, true, &trainResult1); @@ -400,7 +400,7 @@ namespace vector bucketIdxList2; bucketIdxList2.push_back(2); vector actValueList2; - actValueList2.push_back(24.7); + actValueList2.push_back(24.7); ClassifierResult trainResult2; c1.compute(1, input2, bucketIdxList2, actValueList2, false, true, true, &trainResult2);