diff --git a/bindings/py/tests/regions/network_test.py b/bindings/py/tests/regions/network_test.py index d91b62671f..534d8b1867 100644 --- a/bindings/py/tests/regions/network_test.py +++ b/bindings/py/tests/regions/network_test.py @@ -32,8 +32,9 @@ TEST_DATA = [0,1,2,3,4] EXPECTED_RESULT1 = [ 4, 5 ] -EXPECTED_RESULT2 = [ 4, 11, 28, 42, 43, 87, 89, 93, 110, 127, 132, 137, 149, 187, 193] -EXPECTED_RESULT3 = [ 134, 371, 924, 1358, 1386, 2791, 2876, 2996, 3526, 4089, 4242, 4406, 4778, 5994, 6199] +#EXPECTED_RESULT2 = [ 4, 11, 28, 42, 43, 87, 89, 93, 110, 127, 132, 137, 149, 187, 193] +EXPECTED_RESULT2 = [ 16, 32, 44, 81, 104, 109, 114, 166, 197, 198 ] +EXPECTED_RESULT3 = [ 518, 1043, 1436, 2606, 3338, 3495, 3676, 5332, 6310, 6361 ] class LinkRegion(PyRegion): @@ -312,12 +313,13 @@ def testBuiltInRegions(self): sp_output = sp.getOutputArray("bottomUpOut") sdr = sp_output.getSDR() + #print(sdr) self.assertTrue(np.array_equal(sdr.sparse, EXPECTED_RESULT2)) tm_output = tm.getOutputArray("predictedActiveCells") sdr = tm_output.getSDR() - print(sdr.sparse) - print(EXPECTED_RESULT3) + #print(sdr) + #print(EXPECTED_RESULT3) self.assertTrue(np.array_equal(sdr.sparse, EXPECTED_RESULT3)) def testExecuteCommand1(self): diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d505a2e299..4ca0259b75 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -185,6 +185,7 @@ set(examples_files examples/hotgym/Hotgym.cpp # contains conflicting main() examples/hotgym/HelloSPTP.cpp examples/hotgym/HelloSPTP.hpp + examples/napi_sine/napi_sine.cpp examples/mnist/MNIST_SP.cpp ) @@ -356,6 +357,30 @@ else() ${EXTERNAL_INCLUDES} ) endif() + +######################################################### +## NetworkAPI version of benchmark_sine + +set(src_executable_napi_sine napi_sine) +add_executable(${src_executable_napi_sine} examples/napi_sine/napi_sine.cpp) +# link with the static library +target_link_libraries(${src_executable_napi_sine} + ${INTERNAL_LINKER_FLAGS} + ${core_library} + ${COMMON_OS_LIBS} +) +target_compile_options( ${src_executable_napi_sine} PUBLIC ${INTERNAL_CXX_FLAGS}) +target_compile_definitions(${src_executable_napi_sine} PRIVATE ${COMMON_COMPILER_DEFINITIONS}) +target_include_directories(${src_executable_napi_sine} PRIVATE + ${CORE_LIB_INCLUDES} + ${EXTERNAL_INCLUDES} + ) +add_custom_target(sine_napi_run + COMMAND ${src_executable_napi_sine} + DEPENDS ${src_executable_napi_sine} + COMMENT "Executing ${src_executable_napi_sine}" + VERBATIM) + ######################################################### ## MNIST Spatial Pooler Example # @@ -392,6 +417,7 @@ install(TARGETS install(TARGETS ${src_executable_hotgym} + ${src_executable_napi_sine} ${src_executable_mnistsp} RUNTIME DESTINATION bin LIBRARY DESTINATION lib diff --git a/src/examples/hotgym/HelloSPTP.cpp b/src/examples/hotgym/HelloSPTP.cpp index 59582e6f1e..8a0b153a3e 100644 --- a/src/examples/hotgym/HelloSPTP.cpp +++ b/src/examples/hotgym/HelloSPTP.cpp @@ -121,7 +121,7 @@ EPOCHS = 2; // make test faster in Debug input.addNoise(0.01f, rnd); //change 1% of the SDR for each iteration, this makes a random sequence, but seemingly stable tRng.stop(); - //SP (global x local) + //SP (global and local) if(useSPlocal) { tSPloc.start(); spLocal.compute(input, true, outSPlocal); @@ -154,7 +154,7 @@ EPOCHS = 2; // make test faster in Debug avgAnomOld_ = avgAnom10.getCurrentAvg(); //update } tAnLikelihood.start(); - anLikelihood.anomalyProbability(an); //FIXME AnLikelihood is 0.0, probably not working correctly + anLikely = anLikelihood.anomalyProbability(an); tAnLikelihood.stop(); @@ -173,13 +173,14 @@ EPOCHS = 2; // make test faster in Debug << "\n"; // output values - cout << "Epoch = " << e << endl; + cout << "Epoch = " << e+1 << endl; cout << "Anomaly = " << an << endl; cout << "Anomaly (avg) = " << avgAnom10.getCurrentAvg() << endl; cout << "Anomaly (Likelihood) = " << anLikely << endl; - cout << "SP (g)= " << outSP << endl; - cout << "SP (l)= " << outSPlocal <(avgAnom10.getCurrentAvg() * 10000.0f) == static_cast(goldAnAvg * 10000.0f)) << "Deterministic average anom score failed:" << avgAnom10.getCurrentAvg() << " should be: " << goldAnAvg; + std::cout << "outputs match\n"; } #endif diff --git a/src/examples/napi_sine/README.md b/src/examples/napi_sine/README.md new file mode 100644 index 0000000000..ca2a497bd6 --- /dev/null +++ b/src/examples/napi_sine/README.md @@ -0,0 +1,83 @@ +# C++ example using Network API +The program `sine_napi` is an example of an app using the Network API tools +available in the htm.core library. In this example we generate a sine wave +with some noise as the input. This is passed to an encoder to turn that +into a quantized format. This is passed to an instance of SpatialPooler (SP). + +The output of the SP passed on to the temporalMemory (TM) algorithm. The +output of the TM can be written to a file so that it can be plotted. + +``` + /////////////////////////////////////////////////////////////// + // + // .------------------. + // | encoder | + // data--->| (RDSERegion) | + // | | + // `------------------' + // | + // .------------------. + // | SP (global) | + // | (SPRegion) | + // | | + // `------------------' + // | + // .------------------. + // | TM | + // | (TMRegion) | + // | | + // `------------------' + // + ////////////////////////////////////////////////////////////////// +``` + +Each "region" is a wrapper around an algorithm. This wrapper provides a uniform interface that can be plugged into the Network API engine for execution. The htm.core library contains regions for each of the primary algorithms in the library. The user can create their own algorithms and corresponding regions and plug them into the Network API engine by registering them with the Network class. The following chart shows the 'built-in' C++ regions. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Built-in RegionAlgorithm
ScalarSensorScalarEncoder; Original encoder for numeric values
RDSERegionRandomDistributedScalarEncoder (RDSE); advanced encoder for numeric values.
SPRegionSpatialPooler (SP)
TMRegionTemporalMemory (TM)
VectorFileSensorfor reading from a file
VectorFileEffectorfor writing to a file
+ +## Usage + +``` + sine_napi [iterations [filename]] +``` +- *iterations* is the number of times to execute the regions configured into the network. The default is 5000. +- *filename* is the path for a file to be written which contains the following for each iteration. The default is no file written. +``` + , , \n +``` + + +## Experimentation +It is intended that this program be used as a launching point for experimenting with combinations of the regions and using different parameters. Try it and see what happens... \ No newline at end of file diff --git a/src/examples/napi_sine/napi_sine.cpp b/src/examples/napi_sine/napi_sine.cpp new file mode 100644 index 0000000000..bc66eb9463 --- /dev/null +++ b/src/examples/napi_sine/napi_sine.cpp @@ -0,0 +1,163 @@ +/* --------------------------------------------------------------------- + * HTM Community Edition of NuPIC + * Copyright (C) 2013-2015, Numenta, Inc. + * + * 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. + * --------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include "htm/utils/MovingAverage.hpp" +#include "htm/algorithms/AnomalyLikelihood.hpp" +#include + +using namespace htm; + +static bool verbose = true; +#define VERBOSE if (verbose) std::cout << " " + + +//this runs as an executable + +int main(int argc, char* argv[]) { + htm::UInt EPOCHS = 5000; // number of iterations (calls to encoder/SP/TP compute() ) +#ifndef NDEBUG + EPOCHS = 2; // make test faster in Debug +#endif + + const UInt DIM_INPUT = 1000; // Width of encoder output + const UInt COLS = 2048; // number of columns in SP, TP + const UInt CELLS = 8; // cells per column in TP + Random rnd(42); // uses fixed seed for deterministic output + std::ofstream ofs; + + std::string encoder_params = "{size: " + std::to_string(DIM_INPUT) + ", sparsity: 0.2, radius: 0.03, seed: 2019, noise: 0.01}"; + std::string sp_global_params = "{columnCount: " + std::to_string(COLS) + ", globalInhibition: true}"; + std::string tm_params = "{cellsPerColumn: " + std::to_string(CELLS) + ", orColumnOutputs: true}"; + + // Runtime arguments: napi_sine [epochs [filename]] + if(argc >= 2) { + EPOCHS = std::stoi(argv[1]); // number of iterations (default 5000) + } + if (argc >= 3) { + ofs.open(argv[2], std::ios::out); // output filename (for plotting) + } + + try { + + std::cout << "initializing. DIM_INPUT=" << DIM_INPUT << ", COLS=" << COLS << ", CELLS=" << CELLS << "\n"; + + Network net; + + // Declare the regions to use + std::shared_ptr encoder = net.addRegion("encoder", "RDSERegion", encoder_params); + std::shared_ptr sp_global = net.addRegion("sp_global", "SPRegion", sp_global_params); + std::shared_ptr tm = net.addRegion("tm", "TMRegion", tm_params); + + // Setup data flows between regions + net.link("encoder", "sp_global", "", "", "encoded", "bottomUpIn"); + net.link("sp_global", "tm", "", "", "bottomUpOut", "bottomUpIn"); + + net.initialize(); + + + /////////////////////////////////////////////////////////////// + // + // .----------------. + // | encoder | + // data--->| (RDSERegion) | + // | | + // `-----------------' + // | + // .-----------------. + // | sp_global | + // | (SPRegion) | + // | | + // `-----------------' + // | + // .-----------------. + // | tm | + // | (TMRegion) | + // | | + // `-----------------' + // + ////////////////////////////////////////////////////////////////// + + + // enable this to see a trace as it executes + //net.setLogLevel(LogLevel::LogLevel_Verbose); + + std::cout << "Running: " << EPOCHS << " Iterations.\n "; + + float anLikely = 0.0f; + MovingAverage avgAnomaly(1000); + AnomalyLikelihood anLikelihood; + + // RUN + float x = 0.00f; + for (size_t e = 0; e < EPOCHS; e++) { + // genarate some data to send to the encoder + + // -- A sine wave, one degree rotation per iteration (an alternate function) + //double data = std::sin(i * (3.1415 / 180)); + + // -- sine wave, 0.01 radians per iteration (Note: first iteration is for x=0.01, not 0) + x += 0.01f; // step size for fn(x) + double data = std::sin(x); + encoder->setParameterReal64("sensedValue", data); // feed data into RDSE encoder for this iteration. + + // Execute an iteration. + net.run(1); + + float an = ((float *)tm->getOutputData("anomaly").getBuffer())[0]; + avgAnomaly.compute(an); + anLikely = anLikelihood.anomalyProbability(an); + + + // Save the data for plotting. , , , \n + if (ofs.is_open()) { + ofs << e << "," << data << "," << an << "," << anLikely << std::endl; + } + + if (e == EPOCHS - 1) + { + + // output values + VERBOSE << "Result after " << e + 1 << " iterations.\n"; + VERBOSE << " Anomaly = " << an << std::endl; + VERBOSE << " Anomaly(avg) = " << avgAnomaly.getCurrentAvg() << std::endl; + VERBOSE << " Anomaly(Likelihood) = " << anLikely << endl; + VERBOSE << " Encoder out = " << encoder->getOutputData("encoded").getSDR(); + VERBOSE << " SP (global) = " << sp_global->getOutputData("bottomUpOut").getSDR(); + VERBOSE << " TM predictive = " << tm->getOutputData("predictiveCells").getSDR(); + } + } + if (ofs.is_open()) + ofs.close(); + + + std::cout << "finished\n"; + + + } catch (Exception &ex) { + std::cerr << ex.what(); + if (ofs.is_open()) + ofs.close(); + return 1; + } + + return 0; +} + diff --git a/src/htm/algorithms/SpatialPooler.hpp b/src/htm/algorithms/SpatialPooler.hpp index b27eed0226..04f29a036d 100644 --- a/src/htm/algorithms/SpatialPooler.hpp +++ b/src/htm/algorithms/SpatialPooler.hpp @@ -66,17 +66,18 @@ class SpatialPooler : public Serializable SpatialPooler(); SpatialPooler(const vector inputDimensions, const vector columnDimensions, - UInt potentialRadius = 16u, Real potentialPct = 0.5f, - bool globalInhibition = true, + UInt potentialRadius = 16u, + Real potentialPct = 0.5f, + bool globalInhibition = true, Real localAreaDensity = 0.05f, //5% - UInt stimulusThreshold = 0u, + UInt stimulusThreshold = 0u, Real synPermInactiveDec = 0.008f, - Real synPermActiveInc = 0.05f, + Real synPermActiveInc = 0.05f, Real synPermConnected = 0.1f, - Real minPctOverlapDutyCycles = 0.001f, - UInt dutyCyclePeriod = 1000u, + Real minPctOverlapDutyCycles = 0.001f, + UInt dutyCyclePeriod = 1000u, Real boostStrength = 0.0f, - Int seed = 1, + Int seed = 1, UInt spVerbosity = 0u, bool wrapAround = true); diff --git a/src/htm/regions/RDSERegion.cpp b/src/htm/regions/RDSERegion.cpp index 34e8e617cc..2d823cfa4c 100644 --- a/src/htm/regions/RDSERegion.cpp +++ b/src/htm/regions/RDSERegion.cpp @@ -28,6 +28,7 @@ #include #include #include +#include "htm/utils/Random.hpp" #include #include @@ -47,18 +48,23 @@ namespace htm { resolution: {type: Real32, default: "0.0"}, category: {type: Bool, default: "false"}, seed: {type: UInt32, default: "0"}, - sensedValue: {type: Real64, default: "0.0", access: ReadWrite }}, + noise: {description: "amount of noise to add to the output SDR. 0.01 is 1%", + type: Real32, default: "0.0", access: ReadWrite }, + sensedValue: {description: "The value to encode. Overriden by input 'values'.", + type: Real64, default: "0.0", access: ReadWrite }}, inputs: { - values: {type: Real64, count: 1, isDefaultInput: yes, isRegionLevel: yes}}, + values: {description: "Values to encode. Overrides sensedValue.", + type: Real64, count: 1, isDefaultInput: yes, isRegionLevel: yes}}, outputs: { - encoded: {type: SDR, count: 0, isDefaultOutput: yes, isRegionLevel: yes }}} )"); + encoded: {description: "Encoded bits. Not a true Sparse Data Representation.", + type: SDR, count: 0, isDefaultOutput: yes, isRegionLevel: yes }}} )"); return ns; } RDSERegion::RDSERegion(const ValueMap &par, Region *region) : RegionImpl(region) { - + rnd_ = Random(42); spec_.reset(createSpec()); ValueMap params = ValidateParameters(par, spec_.get()); @@ -73,7 +79,7 @@ RDSERegion::RDSERegion(const ValueMap &par, Region *region) : RegionImpl(region) encoder_ = std::make_shared(args); sensedValue_ = params.getScalarT("sensedValue"); - + noise_ = params.getScalarT("noise"); } RDSERegion::RDSERegion(ArWrapper &wrapper, Region *region) @@ -99,6 +105,11 @@ void RDSERegion::compute() { } SDR &output = getOutput("encoded")->getData().getSDR(); encoder_->encode((Real64)sensedValue_, output); + + // Add some noise. + // noise_ = 0.01 means change 1% of the SDR for each iteration, this makes a random sequence, but seemingly stable + if (noise_ != 0.0f) + output.addNoise(noise_, rnd_); } @@ -106,6 +117,10 @@ void RDSERegion::setParameterReal64(const std::string &name, Int64 index, Real64 if (name == "sensedValue") sensedValue_ = value; else RegionImpl::setParameterReal64(name, index, value); } +void RDSERegion::setParameterReal32(const std::string &name, Int64 index, Real32 value) { + if (name == "noise") noise_ = value; + else RegionImpl::setParameterReal32(name, index, value); +} Real64 RDSERegion::getParameterReal64(const std::string &name, Int64 index) { if (name == "sensedValue") { return sensedValue_;} @@ -114,6 +129,7 @@ Real64 RDSERegion::getParameterReal64(const std::string &name, Int64 index) { Real32 RDSERegion::getParameterReal32(const std::string &name, Int64 index) { if (name == "resolution") return encoder_->parameters.resolution; + else if (name == "noise") return noise_; else if (name == "radius") return encoder_->parameters.radius; else if (name == "sparsity") return encoder_->parameters.sparsity; else return RegionImpl::getParameterReal32(name, index); diff --git a/src/htm/regions/RDSERegion.hpp b/src/htm/regions/RDSERegion.hpp index c0b86a56f2..57c8852fec 100644 --- a/src/htm/regions/RDSERegion.hpp +++ b/src/htm/regions/RDSERegion.hpp @@ -55,7 +55,8 @@ class RDSERegion : public RegionImpl, Serializable { virtual Real32 getParameterReal32(const std::string &name, Int64 index = -1) override; virtual UInt32 getParameterUInt32(const std::string &name, Int64 index = -1) override; virtual bool getParameterBool(const std::string &name, Int64 index = -1) override; - virtual void setParameterReal64(const std::string &name, Int64 index, Real64 value) override; + virtual void setParameterReal32(const std::string &name, Int64 index, Real32 value) override; + virtual void setParameterReal64(const std::string &name, Int64 index, Real64 value) override; virtual void initialize() override; void compute() override; @@ -67,6 +68,8 @@ class RDSERegion : public RegionImpl, Serializable { template void save_ar(Archive& ar) const { ar(CEREAL_NVP(sensedValue_)); + ar(CEREAL_NVP(noise_)); + ar(CEREAL_NVP(rnd_)); ar(cereal::make_nvp("encoder", encoder_)); } // FOR Cereal Deserialization @@ -77,6 +80,8 @@ class RDSERegion : public RegionImpl, Serializable { template void load_ar(Archive& ar) { ar(CEREAL_NVP(sensedValue_)); + ar(CEREAL_NVP(noise_)); + ar(CEREAL_NVP(rnd_)); ar(cereal::make_nvp("encoder", encoder_)); setDimensions(encoder_->dimensions); } @@ -89,6 +94,8 @@ class RDSERegion : public RegionImpl, Serializable { private: Real64 sensedValue_; + Real32 noise_; + Random rnd_; std::shared_ptr encoder_; }; } // namespace htm diff --git a/src/htm/regions/SPRegion.cpp b/src/htm/regions/SPRegion.cpp index 18268b4fb0..7efaa434b2 100644 --- a/src/htm/regions/SPRegion.cpp +++ b/src/htm/regions/SPRegion.cpp @@ -43,9 +43,9 @@ SPRegion::SPRegion(const ValueMap &values, Region *region) // parameters out of the map and set aside so we can pass them to the SpatialPooler // algorithm when we create it during initialization(). args_.columnCount = values.getScalarT("columnCount", 0); - args_.potentialRadius = values.getScalarT("potentialRadius", 0); + args_.potentialRadius = values.getScalarT("potentialRadius", 16u); args_.potentialPct = values.getScalarT("potentialPct", 0.5); - args_.globalInhibition = values.getScalarT("globalInhibition", false); + args_.globalInhibition = values.getScalarT("globalInhibition", true); args_.localAreaDensity = values.getScalarT("localAreaDensity", 0.05f); args_.stimulusThreshold = values.getScalarT("stimulusThreshold", 0); args_.synPermInactiveDec = values.getScalarT("synPermInactiveDec", 0.008f); @@ -54,7 +54,7 @@ SPRegion::SPRegion(const ValueMap &values, Region *region) args_.minPctOverlapDutyCycles = values.getScalarT("minPctOverlapDutyCycles", 0.001f); args_.dutyCyclePeriod = values.getScalarT("dutyCyclePeriod", 1000); args_.boostStrength = values.getScalarT("boostStrength", 0.0f); - args_.seed = values.getScalarT("seed", -1); + args_.seed = values.getScalarT("seed", 1); args_.spVerbosity = values.getScalarT("spVerbosity", 0); args_.wrapAround = values.getScalarT("wrapAround", true); spatialImp_ = values.getString("spatialImp", ""); @@ -235,7 +235,7 @@ Spec *SPRegion::createSpec() { NTA_BasicType_UInt32, // type 1, // elementCount "", // constraints - "0", // defaultValue + "16", // defaultValue ParameterSpec::ReadWriteAccess)); // access ns->parameters.add( @@ -274,7 +274,7 @@ Spec *SPRegion::createSpec() { NTA_BasicType_Bool, // type 1, // elementCount "bool", // constraints - "false", // defaultValue + "true", // defaultValue ParameterSpec::ReadWriteAccess)); // access ns->parameters.add( @@ -425,7 +425,7 @@ Spec *SPRegion::createSpec() { NTA_BasicType_Int32, // type 1, // elementCount "", // constraints - "-1", // defaultValue + "1", // defaultValue ParameterSpec::CreateAccess)); // access ns->parameters.add( diff --git a/src/htm/regions/TMRegion.cpp b/src/htm/regions/TMRegion.cpp index cef3cd3e11..38ce1e0ad6 100644 --- a/src/htm/regions/TMRegion.cpp +++ b/src/htm/regions/TMRegion.cpp @@ -43,18 +43,18 @@ TMRegion::TMRegion(const ValueMap ¶ms, Region *region) // algorithm when we create it during initialization(). memset((char *)&args_, 0, sizeof(args_)); args_.numberOfCols = params.getScalarT("numberOfCols", 0); // normally not passed in. - args_.cellsPerColumn = params.getScalarT("cellsPerColumn", 32); - args_.activationThreshold = params.getScalarT("activationThreshold", 13); + args_.cellsPerColumn = params.getScalarT("cellsPerColumn", 32u); + args_.activationThreshold = params.getScalarT("activationThreshold", 13u); args_.initialPermanence = params.getScalarT("initialPermanence", 0.21f); args_.connectedPermanence = params.getScalarT("connectedPermanence", 0.50f); - args_.minThreshold = params.getScalarT("minThreshold", 8); - args_.maxNewSynapseCount = params.getScalarT("maxNewSynapseCount", 20); + args_.minThreshold = params.getScalarT("minThreshold", 10u); + args_.maxNewSynapseCount = params.getScalarT("maxNewSynapseCount", 20u); args_.permanenceIncrement = params.getScalarT("permanenceIncrement", 0.10f); args_.permanenceDecrement = params.getScalarT("permanenceDecrement", 0.10f); args_.predictedSegmentDecrement = params.getScalarT("predictedSegmentDecrement", 0.0f); args_.seed = params.getScalarT("seed", 42); - args_.maxSegmentsPerCell = params.getScalarT("maxSegmentsPerCell", 255); - args_.maxSynapsesPerSegment = params.getScalarT("maxSynapsesPerSegment", 255); + args_.maxSegmentsPerCell = params.getScalarT("maxSegmentsPerCell", 255u); + args_.maxSynapsesPerSegment = params.getScalarT("maxSynapsesPerSegment", 255u); args_.checkInputs = params.getScalarT("checkInputs", true); args_.orColumnOutputs = params.getScalarT("orColumnOutputs", false); args_.externalPredictiveInputs = 0; // will be obtained from externalPredictiveInputs inputs dimensions. @@ -102,6 +102,8 @@ Dimensions TMRegion::askImplForOutputDimensions(const std::string &name) { if (name == "bottomUpOut" && args_.orColumnOutputs) { // It's size is numberOfCols. return region_dim; + } else if (name == "predictiveCells" && args_.orColumnOutputs) { + return region_dim; } else if (name == "bottomUpOut" || name == "activeCells" || name == "predictedActiveCells" || name == "predictiveCells") { // It's size is numberOfCols * args_.cellsPerColumn. @@ -234,12 +236,13 @@ void TMRegion::compute() { out = getOutput("bottomUpOut"); //call Network::setLogLevel(LogLevel::LogLevel_Verbose); // to output the NTA_DEBUG statements below - SDR& sdr = out->getData().getSDR(); - tm_->getActiveCells(sdr); //active cells - if (args_.orColumnOutputs) { //output as columns - sdr = tm_->cellsToColumns(sdr); - } - NTA_DEBUG << "compute "<< *out << std::endl; + SDR active({args_.numberOfCols, args_.cellsPerColumn}); + tm_->getActiveCells(active); //active cells + if (args_.orColumnOutputs) // output as columns + out->getData().getSDR() = tm_->cellsToColumns(active); + else + out->getData().getSDR() = active; + NTA_DEBUG << "compute " << *out << std::endl; out = getOutput("activeCells"); tm_->getActiveCells(out->getData().getSDR()); @@ -256,7 +259,11 @@ void TMRegion::compute() { NTA_DEBUG << "compute "<< *out << std::endl; out = getOutput("predictiveCells"); - out->getData().getSDR() = tm_->getPredictiveCells(); + SDR predictive = tm_->getPredictiveCells(); + if (args_.orColumnOutputs) // output as columns + out->getData().getSDR() = tm_->cellsToColumns(predictive); + else + out->getData().getSDR() = predictive; NTA_DEBUG << "compute " << *out << std::endl; } @@ -336,7 +343,7 @@ Spec *TMRegion::createSpec() { NTA_BasicType_UInt32, // type 1, // elementCount "", // constraints - "8", // defaultValue + "10", // defaultValue ParameterSpec::CreateAccess)); // access ns->parameters.add( diff --git a/src/htm/utils/Random.hpp b/src/htm/utils/Random.hpp index 03c79c00e3..a5c0bb8fa9 100644 --- a/src/htm/utils/Random.hpp +++ b/src/htm/utils/Random.hpp @@ -129,7 +129,7 @@ class Random : public Serializable { * return random from range [from, to) */ Real realRange(Real from, Real to) { - NTA_ASSERT(from <= to); + NTA_ASSERT(from <= to) << "realRange: invalid range."; const Real split = to - from; return from + static_cast(split * getReal64()); } diff --git a/src/test/unit/engine/CppRegionTest.cpp b/src/test/unit/engine/CppRegionTest.cpp index 258070c5db..ad818ea6e3 100644 --- a/src/test/unit/engine/CppRegionTest.cpp +++ b/src/test/unit/engine/CppRegionTest.cpp @@ -152,9 +152,7 @@ TEST(CppRegionTest, testCppLinkingSDR) { << "Expected dimensions on the output to match dimensions on the buffer."; VERBOSE << r2OutputArray << "\n"; SDR exp({20u, 3u}); - exp.setSparse(SDR_sparse_t{ - 4, 21, 32, 46 - }); + exp.setSparse(SDR_sparse_t{10, 38, 57}); EXPECT_EQ(r2OutputArray, exp.getDense()) << "got " << r2OutputArray; } diff --git a/src/test/unit/regions/RDSERegionTest.cpp b/src/test/unit/regions/RDSERegionTest.cpp index 7bd317405e..477ce40d2e 100644 --- a/src/test/unit/regions/RDSERegionTest.cpp +++ b/src/test/unit/regions/RDSERegionTest.cpp @@ -52,7 +52,7 @@ #define VERBOSE if(verbose)std::cerr << "[ ] " static bool verbose = false; // turn this on to print extra stuff for debugging the test. -const UInt EXPECTED_SPEC_COUNT = 8u; // The number of parameters expected in the RDSERegion Spec +const UInt EXPECTED_SPEC_COUNT = 9u; // The number of parameters expected in the RDSERegion Spec using namespace htm; namespace testing diff --git a/src/test/unit/regions/TMRegionTest.cpp b/src/test/unit/regions/TMRegionTest.cpp index 89ab022a27..13699afa24 100644 --- a/src/test/unit/regions/TMRegionTest.cpp +++ b/src/test/unit/regions/TMRegionTest.cpp @@ -213,7 +213,7 @@ TEST(TMRegionTest, testLinking) { std::shared_ptr region1 = net.addRegion("region1", "VectorFileSensor",parameters); std::shared_ptr region2 = net.addRegion("region2", "SPRegion", "{dim: [2,10]}"); std::shared_ptr region3 = net.addRegion("region3", "TMRegion", - "{activationThreshold: 9, cellsPerColumn: 5}"); + "{activationThreshold: 11, cellsPerColumn: 5}"); std::shared_ptr region4 = net.addRegion("region4", "VectorFileEffector", "{outputFile: '" + test_output_file + "'}"); @@ -316,9 +316,7 @@ TEST(TMRegionTest, testLinking) { << numberOfCols << " * " << cellsPerColumn; VERBOSE << " " << r3OutputArray << ")\n"; std::vector expected3outa = VectorHelpers::sparseToBinary( - { - 95, 96, 97, 98, 99 - }, (UInt32)r3OutputArray.getCount()); + {70, 71, 72, 73, 74 }, (UInt32)r3OutputArray.getCount()); EXPECT_EQ(r3OutputArray, expected3outa) << r3OutputArray;