diff --git a/API_CHANGELOG.md b/API_CHANGELOG.md index b7d8e15c0e..c3e025de77 100644 --- a/API_CHANGELOG.md +++ b/API_CHANGELOG.md @@ -56,3 +56,5 @@ As a side-effect of this change, the LinkType and LinkParam parameters in the Ne are ignored. PR #271 * Removed all matrix libraries. Use the `Connections` class instead. PR #169 + +* Removed `void SpatialPooler::stripUnlearnedColumns()` as unused and not useful (did not effectively remove any columns). PR #286 diff --git a/bindings/py/cpp_src/bindings/algorithms/py_SDR.cpp b/bindings/py/cpp_src/bindings/algorithms/py_SDR.cpp index afc8ce49a8..963d48d356 100644 --- a/bindings/py/cpp_src/bindings/algorithms/py_SDR.cpp +++ b/bindings/py/cpp_src/bindings/algorithms/py_SDR.cpp @@ -45,7 +45,7 @@ state of a group of neurons or their associated processes. SDR's have three commonly used data formats which are: * dense * sparse -* flatSparse +* coordinates The SDR class has three magic properties, one for each of these data formats. These properties are the primary way of accessing the SDR's data. When these properties are read from, the data is automatically converted to the requested @@ -61,21 +61,21 @@ Example usage: X.dense = [[0, 1, 0], [0, 1, 0], [0, 0, 1]] - X.sparse = [[0, 1, 2], [1, 1, 2]] - X.flatSparse = [ 1, 4, 8 ] + X.sparse = [ 1, 4, 8 ] + X.coordinates = [[0, 1, 2], [1, 1, 2]] # Access data in any format, SDR will automatically convert data formats, # even if it was not the format used by the most recent assignment to the # SDR. - X.dense -> [[ 0, 1, 0 ], - [ 0, 1, 0 ], - [ 0, 0, 1 ]] - X.sparse -> [[ 0, 1, 2 ], [1, 1, 2 ]] - x.flatSparse -> [ 1, 4, 8 ] + X.dense -> [[ 0, 1, 0 ], + [ 0, 1, 0 ], + [ 0, 0, 1 ]] + x.sparse -> [ 1, 4, 8 ] + X.coordinates -> [[ 0, 1, 2 ], [1, 1, 2 ]] # Data format conversions are cached, and when an SDR value changes the # cache is cleared. - X.flatSparse = [1, 2, 3] # Assign new data to the SDR, clearing the cache. + X.sparse = [1, 2, 3] # Assign new data to the SDR, clearing the cache. X.dense # This line will convert formats. X.dense # This line will resuse the result of the previous line @@ -85,12 +85,12 @@ This class will detect that it's being given it's own data and will omit the copy operation. Example Usage of In-Place Assignment: - X = SDR((1000, 1000)) + X = SDR((1000, 1000)) # Initial value is all zeros data = X.dense data[ 0, 4] = 1 data[444, 444] = 1 X.dense = data - X.flatSparse -> [ 4, 444444 ] + X.sparse -> [ 4, 444444 ] Data Validity Warning: The SDR allocates and frees its data when it is constructed and deconstructed, respectively. If you have a numpy array which @@ -102,15 +102,14 @@ Examples of Invalid Data Accesses: del A # The variable "use_after_free" now references data which has been deallocated. # Another way this can happen is: - use_after_free = SDR( dimensions ).sparse - use_after_free = SDR( dimensions ).flatSparse + use_after_free = SDR( dimensions ).dense Data Validity Warning: After assigning a new value to the SDR, all existing numpy arrays of data are invalid. In order to get the latest copy of the data, re-access the data from the SDR. Examples: A = SDR( dimensions ) out_of_date = A.dense - A.flatSparse = [] + A.sparse = [] # The variable "out_of_date" is now liable to be overwritten. A.dense = out_of_date # This does not work, since the data is invalid. )"); @@ -183,34 +182,34 @@ After modifying this array you MUST assign the array back into the SDR, in order to notify the SDR that its dense array has changed and its cached data is out of date. If you did't copy this data, then SDR won't copy either.)"); - py_SDR.def_property("flatSparse", + py_SDR.def_property("sparse", [](SDR &self) { auto capsule = py::capsule(&self, [](void *self) {}); - return py::array(self.getSum(), self.getFlatSparse().data(), capsule); + return py::array(self.getSum(), self.getSparse().data(), capsule); }, - [](SDR &self, SDR_flatSparse_t data) { + [](SDR &self, SDR_sparse_t data) { NTA_CHECK( data.size() <= self.size ); - self.setFlatSparse( data ); }, + self.setSparse( data ); }, R"(A numpy array containing the indices of only the true values in the SDR. These are indices into the flattened SDR. This format allows for quickly accessing all of the true bits in the SDR.)"); - py_SDR.def_property("sparse", + py_SDR.def_property("coordinates", [](SDR &self) { auto capsule = py::capsule(&self, [](void *self) {}); auto outer = py::list(); - auto sparse = self.getSparse().data(); - for(auto dim = 0u; dim < self.dimensions.size(); dim++) { - auto vec = py::array(sparse[dim].size(), sparse[dim].data(), capsule); + auto coords = self.getCoordinates().data(); + for(auto dim = 0u; dim < self.dimensions.size(); ++dim) { + auto vec = py::array(coords[dim].size(), coords[dim].data(), capsule); outer.append(vec); } return outer; }, - [](SDR &self, SDR_sparse_t data) { + [](SDR &self, SDR_coordinate_t data) { NTA_CHECK( data.size() == self.dimensions.size() ); - self.setSparse( data ); }, -R"(List of numpy arrays, containing the indices of only the true values in the -SDR. This is a list of lists: the outter list contains an entry for each + self.setCoordinates( data ); }, +R"(List of numpy arrays, containing the coordinates of only the true values in +the SDR. This is a list of lists: the outter list contains an entry for each dimension in the SDR. The inner lists contain the coordinates of each true bit. The inner lists run in parallel. This format is useful because it contains the location of each true bit inside of the SDR's dimensional space.)"); @@ -301,8 +300,8 @@ Example Usage: # Convert SDR dimensions from (4 x 4) to (8 x 2) A = SDR([ 4, 4 ]) B = SDR_Proxy( A, [8, 2]) - A.sparse = ([1, 1, 2], [0, 1, 2]) - B.sparse -> ([2, 2, 5], [0, 1, 0]) + A.coordinates = ([1, 1, 2], [0, 1, 2]) + B.coordinates -> ([2, 2, 5], [0, 1, 0]) SDR_Proxy supports pickle, however loading a pickled SDR proxy will return an SDR, not an SDR_Proxy.)"); @@ -326,12 +325,12 @@ Example Usage: # Setup 2 SDRs to hold the inputs. A = SDR( 10 ) B = SDR( 10 ) - A.flatSparse = [2, 3, 4, 5] - B.flatSparse = [0, 1, 2, 3] + A.sparse = [2, 3, 4, 5] + B.sparse = [0, 1, 2, 3] # Calculate the logical intersection X = SDR_Intersection(A, B) - X.flatSparse -> [2, 3] + X.sparse -> [2, 3] # Assignments to the input SDRs are propigated to the SDR_Intersection B.zero() diff --git a/bindings/py/cpp_src/bindings/algorithms/py_SpatialPooler.cpp b/bindings/py/cpp_src/bindings/algorithms/py_SpatialPooler.cpp index c023b10497..4f30a9abf1 100644 --- a/bindings/py/cpp_src/bindings/algorithms/py_SpatialPooler.cpp +++ b/bindings/py/cpp_src/bindings/algorithms/py_SpatialPooler.cpp @@ -184,12 +184,6 @@ namespace nupic_ext self.compute(get_it(x), learn, get_it(y)); }); - // stripUnlearnedColumns - py_SpatialPooler.def("stripUnlearnedColumns", [](SpatialPooler& self, py::array_t& x) - { - self.stripUnlearnedColumns(get_it(x)); - }); - // setBoostFactors py_SpatialPooler.def("setBoostFactors", [](SpatialPooler& self, py::array_t& x) { diff --git a/bindings/py/tests/SDR_test.py b/bindings/py/tests/SDR_test.py index e67946118b..bf02ce71c9 100644 --- a/bindings/py/tests/SDR_test.py +++ b/bindings/py/tests/SDR_test.py @@ -38,24 +38,24 @@ def testExampleUsage(self): [0, 1, 0], [0, 0, 1]] assert( X.dense.tolist() == [[ 0, 1, 0 ], [ 0, 1, 0 ], [ 0, 0, 1 ]] ) - assert( [list(v) for v in X.sparse] == [[ 0, 1, 2 ], [1, 1, 2 ]] ) - assert( list(X.flatSparse) == [ 1, 4, 8 ] ) - X.sparse = [[0, 1, 2], [1, 1, 2]] + assert( [list(v) for v in X.coordinates] == [[ 0, 1, 2 ], [1, 1, 2 ]] ) + assert( list(X.sparse) == [ 1, 4, 8 ] ) + X.coordinates = [[0, 1, 2], [1, 1, 2]] assert( X.dense.tolist() == [[ 0, 1, 0 ], [ 0, 1, 0 ], [ 0, 0, 1 ]] ) - assert( [list(v) for v in X.sparse] == [[ 0, 1, 2 ], [1, 1, 2 ]] ) - assert( list(X.flatSparse) == [ 1, 4, 8 ] ) - X.flatSparse = [ 1, 4, 8 ] + assert( [list(v) for v in X.coordinates] == [[ 0, 1, 2 ], [1, 1, 2 ]] ) + assert( list(X.sparse) == [ 1, 4, 8 ] ) + X.sparse = [ 1, 4, 8 ] # Access data in any format, SDR will automatically convert data formats, # even if it was not the format used by the most recent assignment to the # SDR. assert( X.dense.tolist() == [[ 0, 1, 0 ], [ 0, 1, 0 ], [ 0, 0, 1 ]] ) - assert( [list(v) for v in X.sparse] == [[ 0, 1, 2 ], [1, 1, 2 ]] ) - assert( list(X.flatSparse) == [ 1, 4, 8 ] ) + assert( [list(v) for v in X.coordinates] == [[ 0, 1, 2 ], [1, 1, 2 ]] ) + assert( list(X.sparse) == [ 1, 4, 8 ] ) # Data format conversions are cached, and when an SDR value changes the # cache is cleared. - X.flatSparse = [1, 2, 3] # Assign new data to the SDR, clearing the cache. + X.sparse = [1, 2, 3] # Assign new data to the SDR, clearing the cache. X.dense # This line will convert formats. X.dense # This line will resuse the result of the previous line @@ -64,7 +64,7 @@ def testExampleUsage(self): data[ 0, 4] = 1 data[444, 444] = 1 X.dense = data - assert(list(X.flatSparse) == [ 4, 444444 ]) + assert(list(X.sparse) == [ 4, 444444 ]) def testConstructor(self): A = SDR((103,)) @@ -87,7 +87,7 @@ def testConstructor(self): def testZero(self): A = SDR((103,)) - A.flatSparse = list(range(20)) + A.sparse = list(range(20)) A.zero() assert( np.sum( A.dense ) == 0 ) @@ -102,7 +102,7 @@ def testDense(self): assert(A.dense[0] + A.dense[99] == 2) # Test modify in-place A.dense = A.dense - assert(set(A.flatSparse) == set((0, 99))) + assert(set(A.sparse) == set((0, 99))) # Test dense dimensions assert(B.dense.shape == (100, 100, 1)) # No crash with dimensions @@ -153,45 +153,45 @@ def testDenseInplace(self): assert( inplace_time < copy_time / 3 ) - def testFlatSparse(self): + def testSparse(self): A = SDR((103,)) B = SDR((100, 100, 1)) - A.flatSparse - B.flatSparse = [1,2,3,4] - assert(all(B.flatSparse == np.array([1,2,3,4]))) + A.sparse + B.sparse = [1,2,3,4] + assert(all(B.sparse == np.array([1,2,3,4]))) - B.flatSparse = [] + B.sparse = [] assert( not B.dense.any() ) # Test wrong dimensions assigned C = SDR( 1000 ) C.randomize( .98 ) try: - A.flatSparse = C.flatSparse + A.sparse = C.sparse except RuntimeError: pass else: self.fail() - def testSparse(self): + def testCoordinates(self): A = SDR((103,)) B = SDR((100, 100, 1)) C = SDR((2, 4, 5, 1,1,1,1, 3)) - A.sparse - B.sparse = [[0, 55, 99], [0, 11, 99], [0, 0, 0]] + A.coordinates + B.coordinates = [[0, 55, 99], [0, 11, 99], [0, 0, 0]] assert(B.dense[0, 0, 0] == 1) assert(B.dense[55, 11, 0] == 1) assert(B.dense[99, 99, 0] == 1) C.randomize( .5 ) - assert( len(C.sparse) == len(C.dimensions) ) + assert( len(C.coordinates) == len(C.dimensions) ) # Test wrong dimensions assigned C = SDR((2, 4, 5, 1,1,1,1, 3)) C.randomize( .5 ) try: - A.sparse = C.sparse + A.coordinates = C.coordinates except RuntimeError: pass else: @@ -200,14 +200,14 @@ def testSparse(self): def testSetSDR(self): A = SDR((103,)) B = SDR((103,)) - A.flatSparse = [66] + A.sparse = [66] B.setSDR( A ) assert( B.dense[66] == 1 ) assert( B.getSum() == 1 ) B.dense[77] = 1 B.dense = B.dense A.setSDR( B ) - assert( set(A.flatSparse) == set((66, 77)) ) + assert( set(A.sparse) == set((66, 77)) ) # Test wrong dimensions assigned C = SDR((2, 4, 5, 1,1,1,1, 3)) @@ -326,8 +326,8 @@ def testExampleUsage(self): # Convert SDR dimensions from (4 x 4) to (8 x 2) A = SDR([ 4, 4 ]) B = SDR_Proxy( A, [8, 2]) - A.sparse = ([1, 1, 2], [0, 1, 2]) - assert( (np.array(B.sparse) == ([2, 2, 5], [0, 1, 0]) ).all() ) + A.coordinates = ([1, 1, 2], [0, 1, 2]) + assert( (np.array(B.coordinates) == ([2, 2, 5], [0, 1, 0]) ).all() ) def testLostSDR(self): # You need to keep a reference to the SDR, since SDR class does not use smart pointers. @@ -343,8 +343,8 @@ def testChaining(self): A.dense.fill( 1 ) A.dense = A.dense - assert( len(C.flatSparse) == A.size ) - assert( len(D.flatSparse) == A.size ) + assert( len(C.sparse) == A.size ) + assert( len(D.sparse) == A.size ) del B @pytest.mark.skip(reason="Known issue: https://github.com/htm-community/nupic.cpp/issues/160") @@ -356,10 +356,10 @@ class SdrIntersectionTest(unittest.TestCase): def testExampleUsage(self): A = SDR( 10 ) B = SDR( 10 ) - A.flatSparse = [2, 3, 4, 5] - B.flatSparse = [0, 1, 2, 3] + A.sparse = [2, 3, 4, 5] + B.sparse = [0, 1, 2, 3] X = SDR_Intersection(A, B) - assert((X.flatSparse == [2, 3]).all()) + assert((X.sparse == [2, 3]).all()) B.zero() assert(X.getSparsity() == 0) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 68a093ff63..4744c74518 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -400,23 +400,6 @@ add_custom_target(mnist COMMENT "Executing ${src_executable_mnistsp}" VERBATIM) -######################################################### -## ASCII Example -# -set(src_executable_ascii ascii) -add_executable(${src_executable_ascii} "examples/ascii.cpp") -target_link_libraries(${src_executable_ascii} ${core_library}) -target_compile_options(${src_executable_ascii} PUBLIC ${INTERNAL_CXX_FLAGS}) -target_compile_definitions(${src_executable_ascii} PRIVATE ${COMMON_COMPILER_DEFINITIONS}) -target_include_directories(${src_executable_ascii} PRIVATE - ${CORE_LIB_INCLUDES} - ${EXTERNAL_INCLUDES} - ) -# add_custom_target(ascii -# COMMAND ${src_executable_ascii} -# DEPENDS ${src_executable_ascii} -# COMMENT "Executing ${src_executable_ascii}" -# VERBATIM) ################################################## # @@ -426,7 +409,6 @@ install(TARGETS ${core_library} ${src_executable_hotgym} ${src_executable_mnistsp} - ${src_executable_ascii} RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) diff --git a/src/examples/ascii.cpp b/src/examples/ascii.cpp deleted file mode 100644 index 355f2fdb90..0000000000 --- a/src/examples/ascii.cpp +++ /dev/null @@ -1,26 +0,0 @@ - -#include -#include -#include -#include - -using namespace std; - - -int main() { - cout << "ASCII" << endl; - - auto dataFilename = "./ascii.cpp"; - ifstream dataFile( dataFilename ); - string str((istreambuf_iterator(dataFile)), istreambuf_iterator()); - - // Make model - - // Run model - - // Measure online stability - - // Measure inter/intra catagory overlap - - // Measure whole word classification accuracy -} diff --git a/src/examples/hotgym/HelloSPTP.cpp b/src/examples/hotgym/HelloSPTP.cpp index 2d4a8fce1b..490b800645 100644 --- a/src/examples/hotgym/HelloSPTP.cpp +++ b/src/examples/hotgym/HelloSPTP.cpp @@ -123,7 +123,6 @@ Real64 BenchmarkHotgym::run(UInt EPOCHS, bool useSPlocal, bool useSPglobal, bool tSPloc.start(); fill(outSP.begin(), outSP.end(), 0); spLocal.compute(input.data(), true, outSP.data()); - spLocal.stripUnlearnedColumns(outSP.data()); tSPloc.stop(); NTA_CHECK(outSP.size() == COLS); } @@ -132,7 +131,6 @@ Real64 BenchmarkHotgym::run(UInt EPOCHS, bool useSPlocal, bool useSPglobal, bool tSPglob.start(); fill(outSP.begin(), outSP.end(), 0); spGlobal.compute(input.data(), true, outSP.data()); - spGlobal.stripUnlearnedColumns(outSP.data()); tSPglob.stop(); NTA_CHECK(outSP.size() == COLS); } diff --git a/src/examples/mnist/MNIST_SP.cpp b/src/examples/mnist/MNIST_SP.cpp index 4e5d23a7fe..be6357ed50 100644 --- a/src/examples/mnist/MNIST_SP.cpp +++ b/src/examples/mnist/MNIST_SP.cpp @@ -24,208 +24,173 @@ */ #include -#include -#include +#include //uint8_t #include #include +#include #include #include #include -#include #include +#include // MNIST data itself + read methods, namespace mnist:: + +namespace examples { + using namespace std; using namespace nupic; -// using nupic::algorithms::spatial_pooler_extended::SpatialPoolerExtended; + +using nupic::algorithms::spatial_pooler::SpatialPooler; +using nupic::algorithms::column_pooler::ColumnPooler; +using nupic::algorithms::column_pooler::DefaultTopology; +using nupic::algorithms::connections::Permanence; using nupic::algorithms::sdr_classifier::SDRClassifier; using nupic::algorithms::cla_classifier::ClassifierResult; - -vector read_mnist_labels(string path) { - ifstream file(path); - if( !file.is_open() ) { - cerr << "ERROR: Failed to open file " << path << endl; - exit(1); - } - int magic_number = 0; - int number_of_labels = 0; - file.read( (char*) &magic_number, 4); - file.read( (char*) &number_of_labels, 4); - if(magic_number != 0x00000801) { - std::reverse((char*) &magic_number, (char*) &magic_number + 4); - std::reverse((char*) &number_of_labels, (char*) &number_of_labels + 4); - } - if(magic_number != 0x00000801) { - cerr << "ERROR: MNIST data is compressed or corrupt" << endl; - exit(1); - } - vector retval; - for(int i = 0; i < number_of_labels; ++i) { - unsigned char label = 0; - file.read( (char*) &label, 1); - retval.push_back((UInt) label); - } - return retval; -} - - -vector read_mnist_images(string path) { - ifstream file(path); - if( !file.is_open() ) { - cerr << "ERROR: Failed to open file " << path << endl; - exit(1); - } - int magic_number = 0; - int number_of_images = 0; - int n_rows = 0; - int n_cols = 0; - file.read( (char*) &magic_number, 4); - file.read( (char*) &number_of_images, 4); - file.read( (char*) &n_rows, 4); - file.read( (char*) &n_cols, 4); - if(magic_number != 0x00000803) { - std::reverse((char*) &magic_number, (char*) &magic_number + 4); - std::reverse((char*) &number_of_images, (char*) &number_of_images + 4); - std::reverse((char*) &n_rows, (char*) &n_rows + 4); - std::reverse((char*) &n_cols, (char*) &n_cols + 4); - } - if(magic_number != 0x00000803) { - cerr << "ERROR: MNIST data is compressed or corrupt" << endl; - exit(1); - } - NTA_ASSERT(n_rows == 28); - NTA_ASSERT(n_cols == 28); - UInt img_size = n_rows * n_cols; - vector retval; - for(int i = 0; i < number_of_images; ++i) { - auto data_raw = new unsigned char[img_size]; - file.read( (char*) data_raw, img_size); - // Copy the data into an array of UInt's - auto data = new UInt[img_size]; - // auto data = new UInt[2 * img_size]; - // Apply a threshold to the image, yielding a B & W image. - for(UInt pixel = 0; pixel < img_size; pixel++) { - data[pixel] = data_raw[pixel] >= 128 ? 1 : 0; - // data[2 * pixel] = data_raw[pixel] >= 128 ? 1 : 0; - // data[2 * pixel + 1] = 1 - data[2 * pixel]; - } - retval.push_back(data); - delete[] data_raw; - } - return retval; -} - - -int main(int argc, char **argv) { - UInt verbosity = 1; - auto train_dataset_iterations = 1u; - // int opt; - // while ( (opt = getopt(argc, argv, "tv")) != -1 ) { // for each option... - // switch ( opt ) { - // case 't': - // train_dataset_iterations += 1; - // break; - // case 'v': - // verbosity = 1; - // break; - // case '?': - // cerr << "Unknown option: '" << char(optopt) << "'!" << endl; - // break; - // } - // } - - SDR input({28, 28}); - ColumnPooler htm( +class MNIST { + + private: + SpatialPooler sp; + ColumnPooler cp; + SDR input; + SDR columns; + SDRClassifier clsr; + mnist::MNIST_dataset, uint8_t> dataset; + + public: + UInt verbosity = 1; + const UInt train_dataset_iterations = 1u; + + +void setup() { + + input.initialize({28, 28}); + sp.initialize( + /* inputDimensions */ input.dimensions, + /* columnDimensions */ {28, 28}, //mostly affects speed, to some threshold accuracy only marginally + /* potentialRadius */ 5u, + /* potentialPct */ 0.5f, + /* globalInhibition */ false, + /* localAreaDensity */ 0.20f, //% active bits, //quite important variable (speed x accuracy) + /* numActiveColumnsPerInhArea */ -1, + /* stimulusThreshold */ 6u, + /* synPermInactiveDec */ 0.005f, + /* synPermActiveInc */ 0.01f, + /* synPermConnected */ 0.4f, + /* minPctOverlapDutyCycles */ 0.001f, + /* dutyCyclePeriod */ 1402, + /* boostStrength */ 2.5f, //boosting does help + /* seed */ 93u, + /* spVerbosity */ 1u, + /* wrapAround */ false); //wrap is false for this problem + + cp.initialize( /* proximalInputDimensions */ input.dimensions, - /* distalInputDimensions */ {1}, - /* inhibitionDimensions */ {10, 10}, + /* distalInputDimensions */ vector{1}, + /* inhibitionDimensions */ vector{10, 10}, /* cellsPerInhbitionArea */ 120, /* sparsity */ .015, - /* potentialPool */ DefaultTopology(.9, 4., false), + /* potentialPool */ DefaultTopology(.9, 4., true), + /* proximalSegments */ 1, /* proximalSegmentThreshold */ 3, // 7, // 14, /* proximalIncrement */ .032, /* proximalDecrement */ .00928, /* proximalSynapseThreshold */ .422, - /* distalMaxSegments */ 0, - /* distalMaxSynapsesPerSegment */ 0, - /* distalSegmentThreshold */ 0, - /* distalSegmentMatch */ 0, - /* distalAddSynapses */ 0, - /* distalIncrement */ 0, - /* distalDecrement */ 0, - /* distalMispredictDecrement */ 0, - /* distalSynapseThreshold */ 0, - /* stability_rate */ 0, - /* fatigue_rate */ 0, + + /* distalMaxSegments */ 0u, + /* distalMaxSynapsesPerSegment */ 0u, + /* distalSegmentThreshold */ 0u, + /* distalSegmentMatch */ 0u, + /* distalAddSynapses */ 0u, + /* distalIncrement */ (Permanence)0.0, + /* distalDecrement */ (Permanence)0.0, + /* distalMispredictDecrement */ (Permanence)0.0, + /* distalSynapseThreshold */ (Permanence)0.0, + + /* stability_rate */ 0.0, + /* fatigue_rate */ 0.0, /* period */ 1402, /* seed */ 0, /* verbose */ verbosity); - SDR cells( htm.cellDimensions ); - SDR_Metrics columnStats(cells, 1402); +// columns.initialize({sp.getNumColumns()}); + columns.initialize(cp.cellDimensions); - SDRClassifier clsr( + clsr.initialize( /* steps */ {0}, /* alpha */ .001, /* actValueAlpha */ .3, verbosity); + dataset = mnist::read_dataset(string("../ThirdParty/mnist_data/mnist-src/")); //from CMake +} + +void train() { // Train - auto train_images = read_mnist_images("./mnist_data/train-images-idx3-ubyte"); - auto train_labels = read_mnist_labels("./mnist_data/train-labels-idx1-ubyte"); + if(verbosity) - cout << "Training for " << (train_dataset_iterations * train_labels.size()) + cout << "Training for " << (train_dataset_iterations * dataset.training_labels.size()) << " cycles ..." << endl; - for(auto i = 0u; i < train_dataset_iterations; i++) { + size_t i = 0; + + SDR_Metrics inputStats(input, 1402); + SDR_Metrics columnStats(columns, 1402); + + for(auto epoch = 0u; epoch < train_dataset_iterations; epoch++) { + NTA_INFO << "epoch " << epoch; // Shuffle the training data. - vector index( train_labels.size() ); - for(auto s = 0u; s < train_labels.size(); s++) - index[s] = s; - Random(3).shuffle( index.begin(), index.end() ); + vector index( dataset.training_labels.size() ); + index.assign(dataset.training_labels.cbegin(), dataset.training_labels.cend()); + Random().shuffle( index.begin(), index.end() ); - for(auto s = 0u; s < train_labels.size(); s++) { + for(const auto idx : index) { // index = order of label (shuffeled) // Get the input & label - UInt *image = train_images[ index[s] ]; - UInt label = train_labels[ index[s] ]; + const auto image = dataset.training_images.at(idx); + const UInt label = dataset.training_labels.at(idx); // Compute & Train input.setDense( image ); - htm.compute(input, true, cells); + //sp.compute(input, true, columns); //TOGGLE SP/CP computation + cp.compute(input, true, columns); + ClassifierResult result; - clsr.compute(htm.iterationNum, cells.getFlatSparse(), + //clsr.compute(sp.getIterationNum(), columns.getSparse(), //TOGGLE + clsr.compute(cp.iterationNum, columns.getSparse(), /* bucketIdxList */ {label}, /* actValueList */ {(Real)label}, /* category */ true, /* learn */ true, /* infer */ false, &result); - if( verbosity and htm.iterationNum % 1000 == 0 ) - cout << "." << flush; + if( verbosity && (++i % 1000 == 0) ) cout << "." << flush; } + if( verbosity ) cout << endl; } - if( verbosity ) cout << endl; - - cout << columnStats; + cout << "epoch ended" << endl; + cout << inputStats << endl; + cout << columnStats << endl; +} +void test() { // Test - auto test_images = read_mnist_images("./mnist_data/t10k-images-idx3-ubyte"); - auto test_labels = read_mnist_labels("./mnist_data/t10k-labels-idx1-ubyte"); Real score = 0; UInt n_samples = 0; if(verbosity) - cout << "Testing for " << test_labels.size() << " cycles ..." << endl; - for(UInt i = 0; i < test_labels.size(); i++) { + cout << "Testing for " << dataset.test_labels.size() << " cycles ..." << endl; + for(UInt i = 0; i < dataset.test_labels.size(); i++) { // Get the input & label - UInt *image = test_images[i]; - UInt label = test_labels[i]; + const auto image = dataset.test_images.at(i); + const UInt label = dataset.test_labels.at(i); // Compute input.setDense( image ); - htm.compute(input, false, cells); + //sp.compute(input, false, columns); //TOGGLE + cp.compute(input, false, columns); ClassifierResult result; - clsr.compute(htm.iterationNum, cells.getFlatSparse(), + //clsr.compute(sp.getIterationNum(), columns.getSparse(), //TOGGLE + clsr.compute(cp.iterationNum, columns.getSparse(), /* bucketIdxList */ {}, /* actValueList */ {}, /* category */ true, @@ -235,17 +200,29 @@ int main(int argc, char **argv) { // Check results for(auto iter : result) { if( iter.first == 0 ) { - auto *pdf = iter.second; - auto max = std::max_element(pdf->begin(), pdf->end()); - UInt cls = max - pdf->begin(); + const auto *pdf = iter.second; + const auto max = std::max_element(pdf->cbegin(), pdf->cend()); + const UInt cls = max - pdf->cbegin(); if(cls == label) score += 1; n_samples += 1; } } - if( verbosity and i % 1000 == 0 ) - cout << "." << flush; + if( verbosity && i % 1000 == 0 ) cout << "." << flush; } if( verbosity ) cout << endl; - cout << "Score: " << score / n_samples << endl; + cout << "Score: " << 100.0 * score / n_samples << "% " << endl; } + +}; // End class MNIST +} // End namespace examples + +int main(int argc, char **argv) { + examples::MNIST m; + m.setup(); + m.train(); + m.test(); + + return 0; +} + diff --git a/src/nupic/algorithms/ColumnPooler.cpp b/src/nupic/algorithms/ColumnPooler.cpp index 07e3fb0dd5..ffc448b600 100644 --- a/src/nupic/algorithms/ColumnPooler.cpp +++ b/src/nupic/algorithms/ColumnPooler.cpp @@ -43,6 +43,10 @@ #include #include +namespace nupic { +namespace algorithms { +namespace column_pooler { + using namespace std; using namespace nupic; using namespace nupic::math::topology; @@ -63,7 +67,7 @@ class ColumnPooler // : public Serializable vector distalInputDimensions_; vector inhibitionDimensions_; vector cellDimensions_; - UInt cellsPerInhbitionArea_; + UInt cellsPerInhibitionArea_; UInt proximalSegments_; vector rawOverlaps_; @@ -78,7 +82,7 @@ class ColumnPooler // : public Serializable const vector &proximalInputDimensions = proximalInputDimensions_; const vector &distalInputDimensions = distalInputDimensions_; const vector &inhibitionDimensions = inhibitionDimensions_; - const UInt &cellsPerInhbitionArea = cellsPerInhbitionArea_; + const UInt &cellsPerInhibitionArea = cellsPerInhibitionArea_; const vector &cellDimensions = cellDimensions_; const UInt &proximalSegments = proximalSegments_; @@ -107,11 +111,79 @@ class ColumnPooler // : public Serializable TemporalMemory distalConnections; + + ColumnPooler() {}; //default constructor, must call initialize to setup properly + ColumnPooler( + const vector proximalInputDimensions, + const vector distalInputDimensions, + const vector inhibitionDimensions, + UInt cellsPerInhibitionArea, + + Real sparsity, + + Topology_t potentialPool, + UInt proximalSegments, + UInt proximalSegmentThreshold, + Permanence proximalIncrement, + Permanence proximalDecrement, + Permanence proximalSynapseThreshold, + + UInt distalMaxSegments, + UInt distalMaxSynapsesPerSegment, + UInt distalSegmentThreshold, + UInt distalSegmentMatch, + UInt distalAddSynapses, + Permanence distalIncrement, + Permanence distalDecrement, + Permanence distalMispredictDecrement, + Permanence distalSynapseThreshold, + + Real stability_rate, + Real fatigue_rate, + + Real period, + Int seed, + bool verbose) { + initialize( + proximalInputDimensions, + distalInputDimensions, + inhibitionDimensions, + cellsPerInhibitionArea, + + sparsity, + + potentialPool, + proximalSegments, + proximalSegmentThreshold, + proximalIncrement, + proximalDecrement, + proximalSynapseThreshold, + + distalMaxSegments, + distalMaxSynapsesPerSegment, + distalSegmentThreshold, + distalSegmentMatch, + distalAddSynapses, + distalIncrement, + distalDecrement, + distalMispredictDecrement, + distalSynapseThreshold, + + stability_rate, + fatigue_rate, + + period, + seed, + verbose); + } + + + void initialize( const vector proximalInputDimensions, const vector distalInputDimensions, const vector inhibitionDimensions, - UInt cellsPerInhbitionArea, + UInt cellsPerInhibitionArea, Real sparsity, @@ -138,10 +210,12 @@ class ColumnPooler // : public Serializable Real period, Int seed, bool verbose) { + proximalInputDimensions_ = proximalInputDimensions; distalInputDimensions_ = distalInputDimensions; inhibitionDimensions_ = inhibitionDimensions; - cellsPerInhbitionArea_ = cellsPerInhbitionArea; + cellsPerInhibitionArea_ = cellsPerInhibitionArea; + proximalSegments_ = proximalSegments; this->sparsity = sparsity; this->proximalSegmentThreshold = proximalSegmentThreshold; @@ -154,7 +228,7 @@ class ColumnPooler // : public Serializable SDR proximalInputs( proximalInputDimensions ); SDR inhibitionAreas( inhibitionDimensions ); cellDimensions_ = inhibitionAreas.dimensions; - cellDimensions_.push_back( cellsPerInhbitionArea ); + cellDimensions_.push_back( cellsPerInhibitionArea ); SDR cells( cellDimensions_ ); rng_ = Random(seed); @@ -164,14 +238,14 @@ class ColumnPooler // : public Serializable SDR_ActivationFrequency PP_AF( proximalInputs.dimensions, 10 * proximalInputs.size); UInt cell = 0u; for(auto inhib = 0u; inhib < inhibitionAreas.size; ++inhib) { - inhibitionAreas.setFlatSparse(SDR_flatSparse_t{ inhib }); - for(auto c = 0u; c < cellsPerInhbitionArea; ++c, ++cell) { + inhibitionAreas.setSparse(SDR_sparse_t{ inhib }); + for(auto c = 0u; c < cellsPerInhibitionArea; ++c, ++cell) { for(auto s = 0u; s < proximalSegments; ++s) { auto segment = proximalConnections.createSegment( cell ); // Make synapses. potentialPool( inhibitionAreas, proximalInputs ); - for(const auto presyn : proximalInputs.getFlatSparse() ) { + for(const auto presyn : proximalInputs.getSparse() ) { auto permanence = initProximalPermanence(); proximalConnections.createSynapse( segment, presyn, permanence); } @@ -289,7 +363,7 @@ class ColumnPooler // : public Serializable { // Proximal Feed Forward Excitement rawOverlaps_.assign( proximalConnections.numSegments(), 0.0f ); - proximalConnections.computeActivity(rawOverlaps_, feedForwardInputs.getFlatSparse()); + proximalConnections.computeActivity(rawOverlaps_, feedForwardInputs.getSparse()); // Setup for Boosting const Real denominator = 1.0f / log2( sparsity / proximalSegments ); @@ -345,25 +419,25 @@ class ColumnPooler // : public Serializable // const SDR &predictiveCells, SDR &activeCells) { - const UInt inhibitionAreas = activeCells.size / cellsPerInhbitionArea; - const UInt numDesired = (UInt) std::round(sparsity * cellsPerInhbitionArea); - NTA_CHECK(numDesired > 0) << "Not enough cellsPerInhbitionArea (" - << cellsPerInhbitionArea << ") for desired density (" << sparsity << ")."; + const UInt inhibitionAreas = activeCells.size / cellsPerInhibitionArea; + const UInt numDesired = (UInt) std::round(sparsity * cellsPerInhibitionArea); + NTA_CHECK(numDesired > 0) << "Not enough cellsPerInhibitionArea (" + << cellsPerInhibitionArea << ") for desired density (" << sparsity << ")."; // Compare the cell indexes by their overlap. auto compare = [&overlaps](const UInt &a, const UInt &b) -> bool {return overlaps[a] > overlaps[b];}; - auto &active = activeCells.getFlatSparse(); + auto &active = activeCells.getSparse(); active.clear(); - active.reserve(cellsPerInhbitionArea + numDesired * inhibitionAreas ); + active.reserve(cellsPerInhibitionArea + numDesired * inhibitionAreas ); - for(UInt offset = 0u; offset < activeCells.size; offset += cellsPerInhbitionArea) + for(UInt offset = 0u; offset < activeCells.size; offset += cellsPerInhibitionArea) { // Sort the columns by the amount of overlap. First make a list of all of // the mini-column indexes. auto activeBegin = active.end(); - for(UInt i = 0u; i < cellsPerInhbitionArea; i++) + for(UInt i = 0u; i < cellsPerInhibitionArea; i++) active.push_back( i + offset ); // Do a partial sort to divide the winners from the losers. This sort is // faster than a regular sort because it stops after it partitions the @@ -375,7 +449,7 @@ class ColumnPooler // : public Serializable active.end(), compare); // Remove the columns which lost the competition. - active.resize( active.size() - (cellsPerInhbitionArea - numDesired) ); + active.resize( active.size() - (cellsPerInhibitionArea - numDesired) ); // Remove sub-threshold winners for(auto iter = activeBegin; iter != active.end(); ) @@ -388,7 +462,7 @@ class ColumnPooler // : public Serializable ++iter; } } - activeCells.setFlatSparse( active ); + activeCells.setSparse( active ); } @@ -397,9 +471,10 @@ class ColumnPooler // : public Serializable const SDR &active ) { SDR AF_SDR( AF->dimensions ); auto &activeSegments = AF_SDR.getSparse(); - for(const auto &cell : active.getFlatSparse()) + for(const auto &cell : active.getSparse()) { // Adapt Proximal Segments + NTA_CHECK(cell < proximalMaxSegment_.size()) << "cell oob! " << cell << " < " << proximalMaxSegment_.size(); const auto &maxSegment = proximalMaxSegment_[cell]; proximalConnections.adaptSegment(maxSegment, proximalInputActive, proximalIncrement, proximalDecrement); @@ -463,8 +538,8 @@ class DefaultTopology : public Topology_t inputCoords.push_back({ (UInt32)floor(inputCoord) }); } potentialPool.setSparse(inputCoords); - NTA_CHECK(potentialPool.getFlatSparse().size() == 1u); - const auto centerInput = potentialPool.getFlatSparse()[0]; + NTA_CHECK(potentialPool.getSparse().size() == 1u); + const auto centerInput = potentialPool.getSparse()[0]; vector columnInputs; if (wrapAround) { @@ -480,7 +555,8 @@ class DefaultTopology : public Topology_t const UInt numPotential = (UInt)round(columnInputs.size() * potentialPct); const auto selectedInputs = Random().sample(columnInputs, numPotential); - potentialPool.setFlatSparse( selectedInputs ); + potentialPool.setSparse( selectedInputs ); } }; +}}} //-end ns diff --git a/src/nupic/algorithms/Connections.cpp b/src/nupic/algorithms/Connections.cpp index 450c4e99d4..607b53af7e 100644 --- a/src/nupic/algorithms/Connections.cpp +++ b/src/nupic/algorithms/Connections.cpp @@ -318,6 +318,7 @@ Segment Connections::getSegment(CellIdx cell, SegmentIdx idx) const { } const vector &Connections::synapsesForSegment(Segment segment) const { + NTA_ASSERT(segment < segments_.size()) << "Segment out of bounds! " << segment; return segments_[segment].synapses; } @@ -437,7 +438,8 @@ void Connections::computeActivity( } -void Connections::adaptSegment(const Segment segment, const SDR &inputs, +void Connections::adaptSegment(const Segment segment, + const SDR &inputs, const Permanence increment, const Permanence decrement) { diff --git a/src/nupic/algorithms/Connections.hpp b/src/nupic/algorithms/Connections.hpp index 120bf2bbeb..be84e8fd9f 100644 --- a/src/nupic/algorithms/Connections.hpp +++ b/src/nupic/algorithms/Connections.hpp @@ -425,7 +425,8 @@ class Connections : public Serializable * @param increment Change in permanence for synapses with active presynapses. * @param decrement Change in permanence for synapses with inactive presynapses. */ - void adaptSegment(const Segment segment, const SDR &inputs, + void adaptSegment(const Segment segment, + const SDR &inputs, const Permanence increment, const Permanence decrement); diff --git a/src/nupic/algorithms/SpatialPooler.cpp b/src/nupic/algorithms/SpatialPooler.cpp index 6abf03c2bb..0da4229ce7 100644 --- a/src/nupic/algorithms/SpatialPooler.cpp +++ b/src/nupic/algorithms/SpatialPooler.cpp @@ -504,12 +504,12 @@ void SpatialPooler::compute(SDR &input, bool learn, SDR &active) { boostOverlaps_(overlaps_, boostedOverlaps_); - auto &activeVector = active.getFlatSparse(); + auto &activeVector = active.getSparse(); inhibitColumns_(boostedOverlaps_, activeVector); // Notify the active SDR that its internal data vector has changed. Always // call SDR's setter methods even if when modifying the SDR's own data // inplace. - active.setFlatSparse( activeVector ); + active.setSparse( activeVector ); if (learn) { adaptSynapses_(input, active); @@ -523,29 +523,6 @@ void SpatialPooler::compute(SDR &input, bool learn, SDR &active) { } } -// old API version -void SpatialPooler::stripUnlearnedColumns(UInt activeArray[]) const { - SDR active(columnDimensions_); - active.setDense(activeArray); - stripUnlearnedColumns(active); - std::copy(active.getDense().begin(), active.getDense().end(), activeArray); -} - -// performs activeColumns AND current-round learned columns: active & activeDutyCyc_ -void SpatialPooler::stripUnlearnedColumns(SDR& active) const { - auto sparseCols = active.getFlatSparse(); - vector res; - res.reserve(sparseCols.size()); - - for (const auto& col: sparseCols) { - if (activeDutyCycles_[col] > 0) { - res.push_back(col); - } - } - //update original SDR with changed values - active.setFlatSparse(res); -} - void SpatialPooler::boostOverlaps_(const vector &overlaps, //TODO use Eigen sparse vector here vector &boosted) const { @@ -697,12 +674,12 @@ void SpatialPooler::updateDutyCycles_(const vector &overlaps, // Turn the overlaps array into an SDR. Convert directly to flat-sparse to // avoid copies and type convertions. SDR newOverlap({ numColumns_ }); - auto &overlapsSparseVec = newOverlap.getFlatSparse(); + auto &overlapsSparseVec = newOverlap.getSparse(); for (UInt i = 0; i < numColumns_; i++) { if( overlaps[i] != 0 ) overlapsSparseVec.push_back( i ); } - newOverlap.setFlatSparse( overlapsSparseVec ); + newOverlap.setSparse( overlapsSparseVec ); const UInt period = std::min(dutyCyclePeriod_, iterationNum_); @@ -760,7 +737,7 @@ Real SpatialPooler::avgConnectedSpanForColumnND_(UInt column) const { void SpatialPooler::adaptSynapses_(SDR &input, SDR &active) { - for(const auto &column : active.getFlatSparse()) { + for(const auto &column : active.getSparse()) { connections_.adaptSegment(column, input, synPermActiveInc_, synPermInactiveDec_); connections_.raisePermanencesToThreshold( column, synPermConnected_, stimulusThreshold_); @@ -795,7 +772,7 @@ void SpatialPooler::updateDutyCyclesHelper_(vector &dutyCycles, dutyCycles[i] *= decay; const Real increment = 1.0f / period; // All non-zero values are 1. - for(const auto &idx : newValues.getFlatSparse()) + for(const auto &idx : newValues.getSparse()) dutyCycles[idx] += increment; } @@ -863,7 +840,7 @@ void SpatialPooler::updateBookeepingVars_(bool learn) { void SpatialPooler::calculateOverlap_(SDR &input, vector &overlaps) const { overlaps.assign( numColumns_, 0 ); - connections_.computeActivity(overlaps, input.getFlatSparse()); + connections_.computeActivity(overlaps, input.getSparse()); } diff --git a/src/nupic/algorithms/SpatialPooler.hpp b/src/nupic/algorithms/SpatialPooler.hpp index 1e278a5313..f6281efb5b 100644 --- a/src/nupic/algorithms/SpatialPooler.hpp +++ b/src/nupic/algorithms/SpatialPooler.hpp @@ -279,18 +279,6 @@ class SpatialPooler : public Serializable */ virtual void compute(SDR &input, bool learn, SDR &active); - /** - Removes the set of columns who have never been active from the set - of active columns selected in the inhibition round. Such columns - cannot represent learned pattern and are therefore meaningless if - only inference is required. - - @param activeArray An array of 1's and 0's representing winning - columns calculated by the 'compute' method after disabling - any columns that are not learned. - */ - void stripUnlearnedColumns(UInt activeArray[]) const; - void stripUnlearnedColumns(SDR& active) const; /** * Get the version number of this spatial pooler. diff --git a/src/nupic/algorithms/TemporalMemory.cpp b/src/nupic/algorithms/TemporalMemory.cpp index 8172a64b23..6cdc09db83 100644 --- a/src/nupic/algorithms/TemporalMemory.cpp +++ b/src/nupic/algorithms/TemporalMemory.cpp @@ -449,7 +449,7 @@ static void punishPredictedColumn( void TemporalMemory::activateCells(const SDR &activeColumns, bool learn) { NTA_CHECK( activeColumns.dimensions == columnDimensions_ ); - const auto &sparse = activeColumns.getFlatSparse(); + const auto &sparse = activeColumns.getSparse(); activateCells(sparse.size(), sparse.data(), learn); } @@ -528,8 +528,8 @@ void TemporalMemory::activateDendrites(bool learn, { NTA_CHECK( extraActive.size == numberOfCells() ); NTA_CHECK( extraWinners.size == numberOfCells() ); - activateDendrites( learn, extraActive.getFlatSparse(), - extraWinners.getFlatSparse()); + activateDendrites( learn, extraActive.getSparse(), + extraWinners.getSparse()); } else { @@ -675,7 +675,7 @@ vector TemporalMemory::getActiveCells() const { return activeCells_; } void TemporalMemory::getActiveCells(SDR &activeCells) const { NTA_CHECK( activeCells.size == numberOfCells() ); - activeCells.setFlatSparse( getActiveCells() ); + activeCells.setSparse( getActiveCells() ); } vector TemporalMemory::getPredictiveCells() const { @@ -699,7 +699,7 @@ vector TemporalMemory::getPredictiveCells() const { void TemporalMemory::getPredictiveCells(SDR &predictiveCells) const { NTA_CHECK( predictiveCells.size == numberOfCells() ); - predictiveCells.setFlatSparse( getPredictiveCells() ); + predictiveCells.setSparse( getPredictiveCells() ); } vector TemporalMemory::getWinnerCells() const { return winnerCells_; } @@ -707,7 +707,7 @@ vector TemporalMemory::getWinnerCells() const { return winnerCells_; } void TemporalMemory::getWinnerCells(SDR &winnerCells) const { NTA_CHECK( winnerCells.size == numberOfCells() ); - winnerCells.setFlatSparse( getWinnerCells() ); + winnerCells.setSparse( getWinnerCells() ); } vector TemporalMemory::getActiveSegments() const diff --git a/src/nupic/regions/SPRegion.cpp b/src/nupic/regions/SPRegion.cpp index fe303f74bb..0d20344877 100644 --- a/src/nupic/regions/SPRegion.cpp +++ b/src/nupic/regions/SPRegion.cpp @@ -748,10 +748,10 @@ size_t SPRegion::getParameterArrayCount(const std::string &name, Int64 index) { } else if (name == "spatialPoolerOutput") { return getOutput("bottomUpOut")->getData().getCount(); } else if (name == "spInputNonZeros") { - const SDR_flatSparse_t& v = getInput("bottomUpIn")->getData().getSDR()->getFlatSparse(); + const SDR_sparse_t& v = getInput("bottomUpIn")->getData().getSDR()->getSparse(); return v.size(); } else if (name == "spOutputNonZeros") { - const SDR_flatSparse_t& v = getInput("bottomUpOut")->getData().getSDR()->getFlatSparse(); + const SDR_sparse_t& v = getInput("bottomUpOut")->getData().getSDR()->getSparse(); return v.size(); } return 0; diff --git a/src/nupic/types/Sdr.cpp b/src/nupic/types/Sdr.cpp index 275079e53c..9f05c235c9 100644 --- a/src/nupic/types/Sdr.cpp +++ b/src/nupic/types/Sdr.cpp @@ -17,6 +17,9 @@ /** @file * Implementation of the SparseDistributedRepresentation class + * Also Known As "SDR" class + * + * SDR implementation in C++, refer to Sdr.hpp for detailed comments. */ #include "nupic/types/Sdr.hpp" @@ -27,17 +30,11 @@ using namespace std; namespace nupic { -// SDR implementation in .cpp, refer to .hpp for detailed comments - -/** - * SparseDistributedRepresentation class - * Also known as "SDR" class - */ void SparseDistributedRepresentation::clear() const { - dense_valid = false; - flatSparse_valid = false; - sparse_valid = false; + dense_valid = false; + sparse_valid = false; + coordinates_valid = false; } void SparseDistributedRepresentation::do_callbacks() const { @@ -56,36 +53,36 @@ namespace nupic { do_callbacks(); } - void SparseDistributedRepresentation::setFlatSparseInplace() const { + void SparseDistributedRepresentation::setSparseInplace() const { // Check data is valid. #ifdef NTA_ASSERTIONS_ON - NTA_ASSERT(flatSparse_.size() <= size); - for(auto idx : flatSparse_) { + NTA_ASSERT(sparse_.size() <= size); + for(auto idx : sparse_) { NTA_ASSERT(idx < size); } #endif // Set the valid flags. clear(); - flatSparse_valid = true; + sparse_valid = true; do_callbacks(); } - void SparseDistributedRepresentation::setSparseInplace() const { + void SparseDistributedRepresentation::setCoordinatesInplace() const { // Check data is valid. #ifdef NTA_ASSERTIONS_ON - NTA_ASSERT(sparse_.size() == dimensions.size()); + NTA_ASSERT(coordinates_.size() == dimensions.size()); for(UInt dim = 0; dim < dimensions.size(); dim++) { - const auto coord_vec = sparse_[dim]; + const auto &coord_vec = coordinates_[dim]; NTA_ASSERT(coord_vec.size() <= size); - NTA_ASSERT(coord_vec.size() == sparse_[0].size()); // All coordinate vectors have same size. - for(auto idx : coord_vec) { + NTA_ASSERT(coord_vec.size() == coordinates_[0].size()); // All coordinate vectors have same size. + for(const auto &idx : coord_vec) { NTA_ASSERT(idx < dimensions[dim]); } } #endif // Set the valid flags. clear(); - sparse_valid = true; + coordinates_valid = true; do_callbacks(); } @@ -124,37 +121,37 @@ namespace nupic { // Initialize the dense array storage, when it's needed. dense_valid = false; // Initialize the flatSparse array, nothing to do. - flatSparse_valid = true; - // Initialize the index tuple. - sparse_.assign( dimensions.size(), {} ); sparse_valid = true; + // Initialize the index tuple. + coordinates_.assign( dimensions.size(), {} ); + coordinates_valid = true; } - SparseDistributedRepresentation::SparseDistributedRepresentation( const SparseDistributedRepresentation &value ) + SparseDistributedRepresentation::SparseDistributedRepresentation( + const SparseDistributedRepresentation &value ) : SparseDistributedRepresentation( value.dimensions ) { setSDR( value ); } SparseDistributedRepresentation::~SparseDistributedRepresentation() { deconstruct(); } - void SparseDistributedRepresentation::zero() { - flatSparse_.clear(); - setFlatSparseInplace(); + sparse_.clear(); + setSparseInplace(); } + void SparseDistributedRepresentation::setDense( SDR_dense_t &value ) { NTA_ASSERT(value.size() == size); dense_.swap( value ); setDenseInplace(); } - SDR_dense_t& SparseDistributedRepresentation::getDense() const { if( !dense_valid ) { // Convert from flatSparse to dense. dense_.assign( size, 0 ); - for(const auto idx : getFlatSparse()) { + for(const auto &idx : getSparse()) { dense_[idx] = 1; } dense_valid = true; @@ -164,36 +161,38 @@ namespace nupic { Byte SparseDistributedRepresentation::at(const vector &coordinates) const { UInt flat = 0; - NTA_ASSERT(coordinates.size() == dimensions.size()) << "SDR: coordinates must have same dimensions as SDR"; + NTA_ASSERT(coordinates.size() == dimensions.size()) + << "SDR::at() coordinates must have same dimensions as SDR!"; for(UInt i = 0; i < dimensions.size(); i++) { - NTA_ASSERT( coordinates[i] < dimensions[i] ); + NTA_ASSERT( coordinates[i] < dimensions[i] ) + << "SDR::at() coordinates out of bounds!"; flat *= dimensions[i]; flat += coordinates[i]; } return getDense()[flat]; } - void SparseDistributedRepresentation::setFlatSparse( SDR_flatSparse_t &value ) { - flatSparse_.swap( value ); - setFlatSparseInplace(); - } + void SparseDistributedRepresentation::setSparse( SDR_sparse_t &value ) { + sparse_.swap( value ); + setSparseInplace(); + } - SDR_flatSparse_t& SparseDistributedRepresentation::getFlatSparse() const { - if( !flatSparse_valid ) { - flatSparse_.clear(); // Clear out any old data. - if( sparse_valid ) { - // Convert from sparse to flatSparse. - const auto &sparse = getSparse(); - const auto num_nz = size ? sparse[0].size() : 0; - flatSparse_.reserve( num_nz ); - for(UInt nz = 0; nz < num_nz; nz++) { + SDR_sparse_t& SparseDistributedRepresentation::getSparse() const { + if( !sparse_valid ) { + sparse_.clear(); // Clear out any old data. + if( coordinates_valid ) { + // Convert from coordinates to flat-sparse. + const auto &coords = getCoordinates(); + const auto num_nz = size ? coords[0].size() : 0u; + sparse_.reserve( num_nz ); + for(UInt nz = 0; nz < num_nz; ++nz) { UInt flat = 0; - for(UInt dim = 0; dim < dimensions.size(); dim++) { + for(UInt dim = 0; dim < dimensions.size(); ++dim) { flat *= dimensions[dim]; - flat += sparse[dim][nz]; + flat += coords[dim][nz]; } - flatSparse_.push_back(flat); + sparse_.push_back(flat); } } else if( dense_valid ) { @@ -201,39 +200,39 @@ namespace nupic { const auto &dense = getDense(); for(UInt idx = 0; idx < size; idx++) if( dense[idx] != 0 ) - flatSparse_.push_back( idx ); + sparse_.push_back( idx ); } else NTA_THROW << "SDR has no data!"; - flatSparse_valid = true; + sparse_valid = true; } - return flatSparse_; + return sparse_; } - void SparseDistributedRepresentation::setSparse( SDR_sparse_t &value ) { - sparse_.swap( value ); - setSparseInplace(); - } + void SparseDistributedRepresentation::setCoordinates( SDR_coordinate_t &value ) { + coordinates_.swap( value ); + setCoordinatesInplace(); + } - SDR_sparse_t& SparseDistributedRepresentation::getSparse() const { - if( !sparse_valid ) { + SDR_coordinate_t& SparseDistributedRepresentation::getCoordinates() const { + if( !coordinates_valid ) { // Clear out any old data. - for( auto& vec : sparse_ ) { + for( auto& vec : coordinates_ ) { vec.clear(); } - // Convert from flatSparse to sparse. - for( auto idx : getFlatSparse() ) { - for(UInt dim = (UInt)(dimensions.size() - 1); dim > 0; dim--) { - auto dim_sz = dimensions[dim]; - sparse_[dim].push_back( idx % dim_sz ); + // Convert from sparse to coordinates. + for( auto idx : getSparse() ) { + for(UInt dim = (UInt)(dimensions.size() - 1); dim > 0; --dim) { + const auto dim_sz = dimensions[dim]; + coordinates_[dim].push_back( idx % dim_sz ); idx /= dim_sz; } - sparse_[0].push_back(idx); + coordinates_[0].push_back(idx); } - sparse_valid = true; + coordinates_valid = true; } - return sparse_; + return coordinates_; } @@ -245,21 +244,20 @@ namespace nupic { if( dense_valid ) { dense_.assign( value.dense_.begin(), value.dense_.end() ); } - flatSparse_valid = value.flatSparse_valid; - if( flatSparse_valid ) { - flatSparse_.assign( value.flatSparse_.begin(), value.flatSparse_.end() ); - } sparse_valid = value.sparse_valid; if( sparse_valid ) { + sparse_.assign( value.sparse_.begin(), value.sparse_.end() ); + } + coordinates_valid = value.coordinates_valid; + if( coordinates_valid ) { for(UInt dim = 0; dim < dimensions.size(); dim++) - sparse_[dim].assign( value.sparse_[dim].begin(), value.sparse_[dim].end() ); + coordinates_[dim].assign( value.coordinates_[dim].begin(), value.coordinates_[dim].end() ); } - // method. Subclasses may override these getters and ignore the valid - // flags... - if( !dense_valid and !flatSparse_valid and !sparse_valid ) { - const auto data = value.getFlatSparse(); - flatSparse_.assign( data.begin(), data.end() ); - flatSparse_valid = true; + // Subclasses may override these getters and ignore the valid flags... + if( !dense_valid and !sparse_valid and !coordinates_valid ) { + const auto data = value.getSparse(); + sparse_.assign( data.begin(), data.end() ); + sparse_valid = true; } do_callbacks(); } @@ -282,17 +280,16 @@ namespace nupic { randomize( sparsity, rng ); } - void SparseDistributedRepresentation::randomize(Real sparsity, Random &rng) { NTA_ASSERT( sparsity >= 0.0f and sparsity <= 1.0f ); UInt nbits = (UInt) std::round( size * sparsity ); - SDR_flatSparse_t range( size ); - iota( range.begin(), range.end(), 0 ); - flatSparse_.resize( nbits ); + SDR_sparse_t range( size ); + iota( range.begin(), range.end(), 0u ); + sparse_.resize( nbits ); rng.sample( range.data(), size, - flatSparse_.data(), nbits); - setFlatSparseInplace(); + sparse_.data(), nbits); + setSparseInplace(); } @@ -301,7 +298,6 @@ namespace nupic { addNoise( fractionNoise, rng ); } - void SparseDistributedRepresentation::addNoise(Real fractionNoise, Random &rng) { NTA_ASSERT( fractionNoise >= 0. and fractionNoise <= 1. ); NTA_CHECK( ( 1 + fractionNoise) * getSparsity() <= 1. ); @@ -309,7 +305,7 @@ namespace nupic { UInt num_move_bits = (UInt) std::round( fractionNoise * getSum() ); vector turn_off( num_move_bits , 0 ); rng.sample( - (UInt*) getFlatSparse().data(), getSum(), + (UInt*) getSparse().data(), getSum(), (UInt*) turn_off.data(), num_move_bits); auto& dns = getDense(); @@ -366,12 +362,11 @@ namespace nupic { writeVector( dimensions ); // Store the data in the flat-sparse format. - writeVector( getFlatSparse() ); + writeVector( getSparse() ); outStream << "~SDR" << endl; } - void SparseDistributedRepresentation::load(std::istream &inStream) { auto readVector = [&inStream] (vector &vec) { //TODO add to Serializable @@ -379,7 +374,7 @@ namespace nupic { UInt size; inStream >> size; vec.reserve( size ); - for( UInt i = 0; i < size; i++ ) { + for( UInt i = 0; i < size; ++i ) { UInt elem; inStream >> elem; vec.push_back( elem ); @@ -402,11 +397,11 @@ namespace nupic { for(UInt dim : dimensions) size_ *= dim; // Initialize sparse tuple. - sparse_.assign( dimensions.size(), {} ); + coordinates_.assign( dimensions.size(), {} ); // Read the data. - readVector( flatSparse_ ); - setFlatSparseInplace(); + readVector( sparse_ ); + setSparseInplace(); // Consume the end marker. inStream >> marker; @@ -427,7 +422,6 @@ namespace nupic { return index; } - void SparseDistributedRepresentation::removeCallback(UInt index) { NTA_CHECK( index < callbacks.size() ) << "SparseDistributedRepresentation::removeCallback, Invalid Handle!"; @@ -449,7 +443,6 @@ namespace nupic { return index; } - void SparseDistributedRepresentation::removeDestroyCallback(UInt index) { NTA_CHECK( index < destroyCallbacks.size() ) << "SparseDistributedRepresentation::removeDestroyCallback, Invalid Handle!"; diff --git a/src/nupic/types/Sdr.hpp b/src/nupic/types/Sdr.hpp index 1eca332416..8b11ae2860 100644 --- a/src/nupic/types/Sdr.hpp +++ b/src/nupic/types/Sdr.hpp @@ -36,8 +36,8 @@ using namespace std; namespace nupic { typedef vector SDR_dense_t; -typedef vector SDR_flatSparse_t; -typedef vector> SDR_sparse_t; +typedef vector SDR_sparse_t; +typedef vector> SDR_coordinate_t; typedef function SDR_callback_t; /** @@ -50,7 +50,7 @@ typedef function SDR_callback_t; * represent the state of a group of neurons or their associated processes. * * This class automatically converts between the commonly used SDR data formats: - * which are dense, sparse, and flat-sparse. Converted values are cached by + * which are dense, sparse, and coordinates. Converted values are cached by * this class, so getting a value in one format many times incurs no extra * performance cost. Assigning to the SDR via a setter method will clear these * cached values and cause them to be recomputed as needed. @@ -59,19 +59,19 @@ typedef function SDR_callback_t; * the bits in the SDR. This format allows random-access queries of the SDRs * values. * - * Sparse Flat Index Format: Contains the indices of only the true values in + * Sparse Index Format: Contains the indices of only the true values in * the SDR. This is a list of the indices, indexed into the flattened SDR. * This format allows for quickly accessing all of the true bits in the SDR. * - * Sparse Index Format: Contains the indices of only the true values in the - * SDR. This is a list of lists: the outter list contains an entry for - * each dimension in the SDR. The inner lists contain the coordinates of each - * true bit. The inner lists run in parallel. This format is useful because - * it contains the location of each true bit inside of the SDR's dimensional - * space. + * Coordinate Format: Contains the indices of only the true values in the + * SDR. This is a list of lists: the outter list contains an entry for each + * dimension in the SDR. The inner lists contain the coordinates of each true + * bit in that dimension. The inner lists run in parallel. This format is + * useful because it contains the location of each true bit inside of the + * SDR's dimensional space. * - * Flat Formats: This class uses C-order throughout, meaning that when iterating - * through the SDR, the last/right-most index changes fastest. + * Array Memory Layout: This class uses C-order throughout, meaning that when + * iterating through the SDR, the last/right-most index changes fastest. * * Example usage: * @@ -83,19 +83,19 @@ typedef function SDR_callback_t; * X.setDense({ 0, 1, 0, * 0, 1, 0, * 0, 0, 1 }); - * X.setFlatSparse({ 1, 4, 8 }); - * X.setSparse({{ 0, 1, 2,}, { 1, 1, 2 }}); + * X.setSparse({ 1, 4, 8 }); + * X.setCoordinates({{ 0, 1, 2,}, { 1, 1, 2 }}); * * // Access data in any format, SDR will automatically convert data formats. - * X.getDense() -> { 0, 1, 0, 0, 1, 0, 0, 0, 1 } - * X.getSparse() -> {{ 0, 1, 2 }, {1, 1, 2}} - * x.getFlatSparse() -> { 1, 4, 8 } + * X.getDense() -> { 0, 1, 0, 0, 1, 0, 0, 0, 1 } + * X.getCoordinates() -> {{ 0, 1, 2 }, {1, 1, 2}} + * x.getSparse() -> { 1, 4, 8 } * * // Data format conversions are cached, and when an SDR value changes the * // cache is cleared. - * X.setFlatSparse({}); // Assign new data to the SDR, clearing the cache. - * X.getDense(); // This line will convert formats. - * X.getDense(); // This line will resuse the result of the previous line + * X.setSparse({}); // Assign new data to the SDR, clearing the cache. + * X.getDense(); // This line will convert formats. + * X.getDense(); // This line will resuse the result of the previous line * * * Avoiding Copying: To avoid copying call the setter methods with the correct @@ -104,11 +104,11 @@ typedef function SDR_callback_t; * can be modified and reassigned to the SDR, or the caller can allocate their * own data vectors as one of the following types: * vector aka SDR_dense_t - * vector aka SDR_flatSparse_t - * vector> aka SDR_sparse_t + * vector aka SDR_sparse_t + * vector> aka SDR_coordinate_t * - * Example Usage: - * X.zero(); + * Example Usage With Out Copying: + * SDR X( {3, 3} ); * SDR_dense_t newData({ 1, 0, 0, 1, 0, 0, 1, 0, 0 }); * X.setDense( newData ); * // X now points to newData, and newData points to X's old data. @@ -119,7 +119,7 @@ typedef function SDR_callback_t; * dense[2] = true; * // Notify the SDR of the changes, even if using the SDR's own data inplace. * X.setDense( dense ); - * X.getFlatSparse() -> { 2 } + * X.getSparse() -> { 2 } */ class SparseDistributedRepresentation : public Serializable { @@ -128,19 +128,21 @@ class SparseDistributedRepresentation : public Serializable UInt size_; protected: - // internal representation in given data format (not all must match at a time), - // see *_valid below + /** + * Internal representations in each data format. Not all must match at a + * time, see *_valid below. + */ mutable SDR_dense_t dense_; - mutable SDR_flatSparse_t flatSparse_; mutable SDR_sparse_t sparse_; + mutable SDR_coordinate_t coordinates_; /** * These flags remember which data formats are up-to-date and which formats * need to be updated. */ mutable bool dense_valid; - mutable bool flatSparse_valid; mutable bool sparse_valid; + mutable bool coordinates_valid; private: /** @@ -172,23 +174,23 @@ class SparseDistributedRepresentation : public Serializable /** * Update the SDR to reflect the value currently inside of the dense array. * Use this method after modifying the dense buffer inplace, in order to - * propigate any changes to the sparse & flatSparse formats. + * propigate any changes to the sparse & coordinate formats. */ virtual void setDenseInplace() const; /** * Update the SDR to reflect the value currently inside of the flatSparse * vector. Use this method after modifying the flatSparse vector inplace, in - * order to propigate any changes to the dense & sparse formats. + * order to propigate any changes to the dense & coordinate formats. */ - virtual void setFlatSparseInplace() const; + virtual void setSparseInplace() const; /** * Update the SDR to reflect the value currently inside of the sparse * vector. Use this method after modifying the sparse vector inplace, in - * order to propigate any changes to the dense & flatSparse formats. + * order to propigate any changes to the dense & sparse formats. */ - virtual void setSparseInplace() const; + virtual void setCoordinatesInplace() const; /** * Destroy this SDR. Makes SDR unusable, should error or clearly fail if @@ -261,7 +263,6 @@ class SparseDistributedRepresentation : public Serializable setDense(value.data()); } - /** * Copy a new value into the SDR, overwritting the current value. * @@ -303,8 +304,7 @@ class SparseDistributedRepresentation : public Serializable * * @param value A sparse vector to swap into the SDR. */ - void setFlatSparse( SDR_flatSparse_t &value ); - + void setSparse( SDR_sparse_t &value ); /** * Copy a vector of sparse indices of true values. These indicies are into @@ -313,12 +313,11 @@ class SparseDistributedRepresentation : public Serializable * @param value A vector of flat indices to copy into the SDR. */ template - void setFlatSparse( const vector &value ) { - flatSparse_.assign( value.begin(), value.end() ); - setFlatSparseInplace(); + void setSparse( const vector &value ) { + sparse_.assign( value.begin(), value.end() ); + setSparseInplace(); } - /** * Copy an array of sparse indices of true values. These indicies are into * the flattened SDR space. This overwrites the SDR's current value. @@ -327,73 +326,71 @@ class SparseDistributedRepresentation : public Serializable * @param num_values The number of elements in the 'value' array. */ template - void setFlatSparse( const T *value, const UInt num_values ) { - flatSparse_.assign( value, value + num_values ); - setFlatSparseInplace(); + void setSparse( const T *value, const UInt num_values ) { + sparse_.assign( value, value + num_values ); + setSparseInplace(); } - /** * Gets the current value of the SDR. The result of this method call is * saved inside of this SDR until the SDRs value changes. After modifying - * the flatSparse vector you MUST call sdr.setFlatSparse() in order to - * notify the SDR that its flatSparse vector has changed and its cached data - * is out of date. + * the sparse vector you MUST call sdr.setSparse() in order to notify the + * SDR that its flatSparse vector has changed and its cached data is out of + * date. * * @returns A reference to a vector of the indices of the true values in the * flattened SDR. */ - virtual SDR_flatSparse_t& getFlatSparse() const; + virtual SDR_sparse_t& getSparse() const; /** - * Swap a list of indices into the SDR, replacing the SDRs current value. - * These indices are into the SDR space with dimensions. The outter list is - * indexed using an index into the sdr.dimensions list. The inner lists are - * indexed in parallel, they contain the coordinates of the true values in + * Swap a list of coordinates into the SDR, replacing the SDRs current + * value. These are indices into the SDR space with dimensions. This + * accepts a list of lists, containing the coordinates of the true values in * the SDR. * * This method is fast since it swaps the vector content, however it does * modify its argument! * - * @param value A vector> containing the coordinates of the - * true values to swap into the SDR. + * @param value A vector> containing the coordinates of the true + * values to swap into the SDR. The outter list is indexed using an index + * into the sdr.dimensions list. The inner lists are indexed in parallel. */ - void setSparse( SDR_sparse_t &value ); + void setCoordinates( SDR_coordinate_t &value ); /** - * Copy a list of indices into the SDR, overwritting the SDRs current value. - * These indices are into the SDR space with dimensions. The outter list is - * indexed using an index into the sdr.dimensions list. The inner lists are - * indexed in parallel, they contain the coordinates of the true values in + * Copy a list of coordinates into the SDR, overwritting the SDRs current + * value. These are indices into the SDR space with dimensions. This + * accepts a list of lists, containing the coordinates of the true values in * the SDR. * * @param value A list of lists containing the coordinates of the true - * values to copy into the SDR. + * values to copy into the SDR. The outter list is indexed using an index + * into the sdr.dimensions list. The inner lists are indexed in parallel. */ template - void setSparse( const vector> &value ) { + void setCoordinates( const vector> &value ) { NTA_ASSERT(value.size() == dimensions.size()); for(UInt dim = 0; dim < dimensions.size(); dim++) { - sparse_[dim].clear(); - sparse_[dim].resize(value[dim].size()); + coordinates_[dim].clear(); + coordinates_[dim].resize(value[dim].size()); + // Use an explicit type cast. Otherwise Microsoft Visual Studio will + // print an excessive number of warnings. Do NOT replace this with: + // coordinates_[dim].assign(value[dim].cbegin(), value[dim].cend()); for (UInt i = 0; i < value[dim].size(); i++) - sparse_[dim][i] = (UInt)value[dim][i]; - // you will probably want to do this differently... - // but I need to explictly cast during the copy. - //sparse_[dim].assign(value[dim].cbegin(), value[dim].cend()); + coordinates_[dim][i] = (UInt)value[dim][i]; } - setSparseInplace(); + setCoordinatesInplace(); } - /** * Gets the current value of the SDR. The result of this method call is * saved inside of this SDR until the SDRs value changes. * * @returns A reference to a list of lists which contain the coordinates of - * the true values in the SDR. + * the true values in the SDR. */ - virtual SDR_sparse_t& getSparse() const; + virtual SDR_coordinate_t& getCoordinates() const; /** * Deep Copy the given SDR to this SDR. This overwrites the current value of @@ -410,7 +407,7 @@ class SparseDistributedRepresentation : public Serializable * @returns The number of true values in the SDR. */ inline UInt getSum() const - { return (UInt)getFlatSparse().size(); } + { return (UInt)getSparse().size(); } /** * Calculates the sparsity of the SDR, which is the fraction of bits which @@ -474,7 +471,7 @@ class SparseDistributedRepresentation : public Serializable stream << ", "; } stream << " ) "; - auto data = sdr.getFlatSparse(); + auto data = sdr.getSparse(); std::sort( data.begin(), data.end() ); for( UInt i = 0; i < data.size(); i++ ) { stream << data[i]; diff --git a/src/nupic/types/SdrProxy.hpp b/src/nupic/types/SdrProxy.hpp index 395eaddd68..e9e1a284ca 100644 --- a/src/nupic/types/SdrProxy.hpp +++ b/src/nupic/types/SdrProxy.hpp @@ -44,10 +44,10 @@ class SDR_ReadOnly_ : public SDR void setDenseInplace() const override { NTA_THROW << _error_message; } - void setFlatSparseInplace() const override - { NTA_THROW << _error_message; } void setSparseInplace() const override { NTA_THROW << _error_message; } + void setCoordinatesInplace() const override + { NTA_THROW << _error_message; } void setSDR( const SparseDistributedRepresentation &value ) override { NTA_THROW << _error_message; } void load(std::istream &inStream) override @@ -74,8 +74,8 @@ class SDR_ReadOnly_ : public SDR * // Convert SDR dimensions from (4 x 4) to (8 x 2) * SDR A( { 4, 4 }) * SDR_Proxy B( A, { 8, 2 }) - * A.setSparse( {1, 1, 2}, {0, 1, 2}} ) - * auto sparse = B.getSparse() -> {{2, 2, 5}, {0, 1, 0}} + * A.setCoordinates( {1, 1, 2}, {0, 1, 2}} ) + * B.getCoordinates() -> {{2, 2, 5}, {0, 1, 0}} * * SDR_Proxy partially supports the Serializable interface. SDR_Proxies can be * saved but can not be loaded. @@ -118,24 +118,24 @@ class SDR_Proxy : public SDR_ReadOnly_ return parent->getDense(); } - SDR_flatSparse_t& getFlatSparse() const override { + SDR_sparse_t& getSparse() const override { NTA_CHECK( parent != nullptr ) << "Parent SDR has been destroyed!"; - return parent->getFlatSparse(); + return parent->getSparse(); } - SDR_sparse_t& getSparse() const override { + SDR_coordinate_t& getCoordinates() const override { NTA_CHECK( parent != nullptr ) << "Parent SDR has been destroyed!"; if( dimensions.size() == parent->dimensions.size() && equal( dimensions.begin(), dimensions.end(), parent->dimensions.begin() )) { // All things equal, prefer reusing the parent's cached value. - return parent->getSparse(); + return parent->getCoordinates(); } else { - // Don't override getSparse(). It will call either getDense() or - // getFlatSparse() to get its data, and will use this proxies + // Don't override getCoordinates(). It will call either getDense() or + // getSparse() to get its data, and will use this proxies // dimensions. - return SDR::getSparse(); + return SDR::getCoordinates(); } } @@ -326,12 +326,12 @@ class SDR_Concatenation : public SDR_ReadOnly_ * // Setup 2 SDRs to hold the inputs. * SDR A({ 10 }); * SDR B({ 10 }); - * A.setFlatSparse( {2, 3, 4, 5}); - * B.setFlatSparse({0, 1, 2, 3}); + * A.setSparse( {2, 3, 4, 5}); + * B.setSparse({0, 1, 2, 3}); * * // Calculate the logical intersection * SDR_Intersection X(A, B); - * X.getFlatSparse() -> {2, 3} + * X.getSparse() -> {2, 3} * * // Assignments to the input SDRs are propigated to the SDR_Intersection * B.zero(); diff --git a/src/nupic/utils/SdrMetrics.hpp b/src/nupic/utils/SdrMetrics.hpp index e0212a040e..4f5c4d809a 100644 --- a/src/nupic/utils/SdrMetrics.hpp +++ b/src/nupic/utils/SdrMetrics.hpp @@ -252,7 +252,7 @@ class SDR_ActivationFrequency : public SDR_MetricsHelper_ { for(auto &value : activationFrequency_) value *= decay; - const auto &sparse = dataSource.getFlatSparse(); + const auto &sparse = dataSource.getSparse(); for(const auto &idx : sparse) activationFrequency_[idx] += alpha; } @@ -410,7 +410,7 @@ class SDR_Overlap : public SDR_MetricsHelper_ { max_ = -1234.56789f; mean_ = 1234.56789f; variance_ = 1234.56789f; - previous_.getFlatSparse(); + previous_.getSparse(); } void callback(SDR &dataSource, Real alpha) override { diff --git a/src/test/unit/algorithms/SpatialPoolerTest.cpp b/src/test/unit/algorithms/SpatialPoolerTest.cpp index 9fed69fa58..50983f3382 100644 --- a/src/test/unit/algorithms/SpatialPoolerTest.cpp +++ b/src/test/unit/algorithms/SpatialPoolerTest.cpp @@ -813,7 +813,7 @@ TEST(SpatialPoolerTest, testAdaptSynapses) { SDR input1({8}); input1.setDense(SDR_dense_t{1, 0, 0, 1, 1, 0, 1, 0}); - activeColumns.setFlatSparse(SDR_flatSparse_t({ 0, 1, 2 })); + activeColumns.setSparse(SDR_sparse_t({ 0, 1, 2 })); for (UInt column = 0; column < numColumns; column++) { sp.setPotential(column, potentialArr1[column]); @@ -858,7 +858,7 @@ TEST(SpatialPoolerTest, testAdaptSynapses) { sp.setPermanence(column, permanencesArr2[column]); } - activeColumns.setFlatSparse(activeColumnsArr2, 3); + activeColumns.setSparse(activeColumnsArr2, 3); sp.adaptSynapses_(input2, activeColumns); for (UInt column = 0; column < numColumns; column++) { @@ -1696,59 +1696,6 @@ TEST(SpatialPoolerTest, testinitMapPotential2D) { ASSERT_TRUE(check_vector_eq(expectedMask4, mask)); } -TEST(SpatialPoolerTest, testStripUnlearnedColumns) { - SpatialPooler sp; - vector inputDim{5}, columnDim{3}; - sp.initialize(inputDim, columnDim); - - // None learned, none active - { - Real activeDutyCycles[3] = {0, 0, 0}; - UInt activeArray[3] = {0, 0, 0}; - UInt expected[3] = {0, 0, 0}; - - sp.setActiveDutyCycles(activeDutyCycles); - sp.stripUnlearnedColumns(activeArray); - - ASSERT_TRUE(check_vector_eq(activeArray, expected, 3)); - } - - // None learned, some active - { - Real activeDutyCycles[3] = {0, 0, 0}; - UInt activeArray[3] = {1, 0, 1}; - UInt expected[3] = {0, 0, 0}; - - sp.setActiveDutyCycles(activeDutyCycles); - sp.stripUnlearnedColumns(activeArray); - - ASSERT_TRUE(check_vector_eq(activeArray, expected, 3)); - } - - // Some learned, none active - { - Real activeDutyCycles[3] = {1, 1, 0}; - UInt activeArray[3] = {0, 0, 0}; - UInt expected[3] = {0, 0, 0}; - - sp.setActiveDutyCycles(activeDutyCycles); - sp.stripUnlearnedColumns(activeArray); - - ASSERT_TRUE(check_vector_eq(activeArray, expected, 3)); - } - - // Some learned, some active - { - Real activeDutyCycles[3] = {1, 1, 0}; - UInt activeArray[3] = {1, 0, 1}; - UInt expected[3] = {1, 0, 0}; - - sp.setActiveDutyCycles(activeDutyCycles); - sp.stripUnlearnedColumns(activeArray); - - ASSERT_TRUE(check_vector_eq(activeArray, expected, 3)); - } -} TEST(SpatialPoolerTest, getOverlaps) { SpatialPooler sp; diff --git a/src/test/unit/algorithms/TemporalMemoryTest.cpp b/src/test/unit/algorithms/TemporalMemoryTest.cpp index 6392e3e54e..a34d3d7890 100644 --- a/src/test/unit/algorithms/TemporalMemoryTest.cpp +++ b/src/test/unit/algorithms/TemporalMemoryTest.cpp @@ -1548,7 +1548,7 @@ TEST(TemporalMemoryTest, testExtraActive) { Random rng( i + 99u ); // Use deterministic seeds for unit tests. auto &sdr = pattern[i]; sdr.randomize( 0.10f, rng ); - auto &data = sdr.getFlatSparse(); + auto &data = sdr.getSparse(); std::sort(data.begin(), data.end()); } @@ -1584,14 +1584,14 @@ TEST(TemporalMemoryTest, testExtraActive) { predictedColumns.erase( predictedColumns.begin() + i-- ); } // Calculate TM output - const auto &sparse = x.getFlatSparse(); + const auto &sparse = x.getSparse(); tm.compute(sparse.size(), sparse.data(), true); extraActive = tm.getActiveCells(); extraWinners = tm.getWinnerCells(); // Calculate Anomaly of current input based on prior predictions. anom = algorithms::anomaly::computeRawAnomalyScore( - x.getFlatSparse(), predictedColumns); + x.getSparse(), predictedColumns); } } ASSERT_LT( anom, 0.05f ); @@ -1605,7 +1605,7 @@ TEST(TemporalMemoryTest, testExtraActive) { auto predictedCells = tm.getPredictiveCells(); ASSERT_TRUE( predictedCells.empty() ); // No predictions, numActive < threshold // Calculate TM output - const auto &sparse = x.getFlatSparse(); + const auto &sparse = x.getSparse(); tm.compute(sparse.size(), sparse.data(), true); } } diff --git a/src/test/unit/ntypes/ArrayTest.cpp b/src/test/unit/ntypes/ArrayTest.cpp index 2c1c8b5105..d5ea1a53dc 100644 --- a/src/test/unit/ntypes/ArrayTest.cpp +++ b/src/test/unit/ntypes/ArrayTest.cpp @@ -579,7 +579,7 @@ TEST_F(ArrayTest, testArrayBasefunctions) { EXPECT_EQ(m.getCount(), 100u); std::vector row = a.asVector(); - SDR_flatSparse_t &v = a.getSDR()->getFlatSparse(); + SDR_sparse_t &v = a.getSDR()->getSparse(); EXPECT_EQ(v.size(), 10u); diff --git a/src/test/unit/types/SdrProxyTest.cpp b/src/test/unit/types/SdrProxyTest.cpp index faf9bbc322..ff019066de 100644 --- a/src/test/unit/types/SdrProxyTest.cpp +++ b/src/test/unit/types/SdrProxyTest.cpp @@ -26,9 +26,9 @@ using namespace nupic; TEST(SdrProxyTest, TestProxyExamples) { SDR A( { 4, 4 }); SDR_Proxy B( A, { 8, 2 }); - A.setSparse(SDR_sparse_t({{1, 1, 2}, {0, 1, 2}})); - auto sparse = B.getSparse(); - ASSERT_EQ(sparse, SDR_sparse_t({{2, 2, 5}, {0, 1, 0}})); + A.setCoordinates(SDR_coordinate_t({{1, 1, 2}, {0, 1, 2}})); + auto coords = B.getCoordinates(); + ASSERT_EQ(coords, SDR_coordinate_t({{2, 2, 5}, {0, 1, 0}})); } TEST(SdrProxyTest, TestProxyConstructor) { @@ -55,10 +55,10 @@ TEST(SdrProxyTest, TestProxyConstructor) { SDR_Proxy *K = new SDR_Proxy( A ); delete K; SDR_Proxy *L = new SDR_Proxy( A ); - L->getSparse(); + L->getCoordinates(); delete L; delete G; - I->getSparse(); + I->getCoordinates(); delete I; delete J; A.getDense(); @@ -75,21 +75,21 @@ TEST(SdrProxyTest, TestProxyDeconstructor) { SDR_Proxy *D = new SDR_Proxy( *C, {4, 3} ); SDR_Proxy *E = new SDR_Proxy( *C, {2, 6} ); D->getDense(); - E->getSparse(); + E->getCoordinates(); // Test subtree deletion delete C; ASSERT_ANY_THROW( D->getDense() ); - ASSERT_ANY_THROW( E->getSparse() ); + ASSERT_ANY_THROW( E->getCoordinates() ); ASSERT_ANY_THROW( new SDR_Proxy( *E ) ); delete D; // Test rest of tree is OK. - B->getFlatSparse(); + B->getSparse(); A->zero(); - B->getFlatSparse(); + B->getSparse(); // Test delete root. delete A; ASSERT_ANY_THROW( B->getDense() ); - ASSERT_ANY_THROW( E->getSparse() ); + ASSERT_ANY_THROW( E->getCoordinates() ); // Cleanup remaining Proxies. delete B; delete E; @@ -101,8 +101,8 @@ TEST(SdrProxyTest, TestProxyThrows) { SDR *C = &B; ASSERT_ANY_THROW( C->setDense( SDR_dense_t( 10, 1 ) )); - ASSERT_ANY_THROW( C->setSparse( SDR_sparse_t({ {0}, {0} }) )); - ASSERT_ANY_THROW( C->setFlatSparse( SDR_flatSparse_t({ 0, 1, 2 }) )); + ASSERT_ANY_THROW( C->setCoordinates( SDR_coordinate_t({ {0}, {0} }) )); + ASSERT_ANY_THROW( C->setSparse( SDR_sparse_t({ 0, 1, 2 }) )); SDR X({10}); ASSERT_ANY_THROW( C->setSDR( X )); ASSERT_ANY_THROW( C->randomize(0.10f) ); @@ -118,24 +118,24 @@ TEST(SdrProxyTest, TestProxyGetters) { ASSERT_EQ( C->getDense(), SDR_dense_t({ 0, 1, 0, 0, 1, 0 }) ); // Test getting flat sparse - A.setSparse( SDR_sparse_t({ {0, 1}, {0, 1} })); - ASSERT_EQ( C->getSparse(), SDR_sparse_t({ {0, 2}, {0, 0} }) ); + A.setCoordinates( SDR_coordinate_t({ {0, 1}, {0, 1} })); + ASSERT_EQ( C->getCoordinates(), SDR_coordinate_t({ {0, 2}, {0, 0} }) ); // Test getting sparse - A.setFlatSparse( SDR_flatSparse_t({ 2, 3 })); - ASSERT_EQ( C->getFlatSparse(), SDR_flatSparse_t({ 2, 3 }) ); + A.setSparse( SDR_sparse_t({ 2, 3 })); + ASSERT_EQ( C->getSparse(), SDR_sparse_t({ 2, 3 }) ); // Test getting sparse, a second time. - A.setFlatSparse( SDR_flatSparse_t({ 2, 3 })); - ASSERT_EQ( C->getSparse(), SDR_sparse_t({ {1, 1}, {0, 1} }) ); + A.setSparse( SDR_sparse_t({ 2, 3 })); + ASSERT_EQ( C->getCoordinates(), SDR_coordinate_t({ {1, 1}, {0, 1} }) ); // Test getting sparse, when the parent SDR already has sparse computed and // the dimensions are the same. A.zero(); SDR_Proxy D( A ); SDR *E = &D; - A.setSparse( SDR_sparse_t({ {0, 1}, {0, 1} })); - ASSERT_EQ( E->getSparse(), SDR_sparse_t({ {0, 1}, {0, 1} }) ); + A.setCoordinates( SDR_coordinate_t({ {0, 1}, {0, 1} })); + ASSERT_EQ( E->getCoordinates(), SDR_coordinate_t({ {0, 1}, {0, 1} }) ); } TEST(SdrProxyTest, TestSaveLoad) { @@ -158,13 +158,13 @@ TEST(SdrProxyTest, TestSaveLoad) { // Test flat data SDR flat({ 3, 3 }); SDR_Proxy f( flat ); - flat.setFlatSparse(SDR_flatSparse_t({ 1, 4, 8 })); + flat.setSparse(SDR_sparse_t({ 1, 4, 8 })); f.save( outfile ); // Test index data SDR index({ 3, 3 }); SDR_Proxy x( index ); - index.setSparse(SDR_sparse_t({ + index.setCoordinates(SDR_coordinate_t({ { 0, 1, 2 }, { 1, 1, 2 }})); x.save( outfile ); diff --git a/src/test/unit/types/SdrTest.cpp b/src/test/unit/types/SdrTest.cpp index 30b4e42b1e..b8fb34b13f 100644 --- a/src/test/unit/types/SdrTest.cpp +++ b/src/test/unit/types/SdrTest.cpp @@ -38,19 +38,19 @@ TEST(SdrTest, TestConstructor) { SDR b(b_dims); ASSERT_EQ( b.size, 3ul ); ASSERT_EQ( b.dimensions, b_dims ); - ASSERT_EQ( b.getSparse().size(), 1ul ); + ASSERT_EQ( b.getCoordinates().size(), 1ul ); // zero initialized ASSERT_EQ( b.getDense(), vector({0, 0, 0}) ); - ASSERT_EQ( b.getFlatSparse(), vector(0) ); - ASSERT_EQ( b.getSparse(), vector>({{}}) ); + ASSERT_EQ( b.getSparse(), vector(0) ); + ASSERT_EQ( b.getCoordinates(), vector>({{}}) ); // Test 3-D vector c_dims = {11u, 15u, 3u}; SDR c(c_dims); ASSERT_EQ( c.size, 11u * 15u * 3u ); ASSERT_EQ( c.dimensions, c_dims ); - ASSERT_EQ( c.getSparse().size(), 3ul ); - ASSERT_EQ( c.getFlatSparse().size(), 0ul ); + ASSERT_EQ( c.getCoordinates().size(), 3ul ); + ASSERT_EQ( c.getSparse().size(), 0ul ); // Test dimensions are copied not referenced c_dims.push_back(7); ASSERT_EQ( c.dimensions, vector({11u, 15u, 3u}) ); @@ -66,7 +66,7 @@ TEST(SdrTest, TestConstructorCopy) { SDR a({5}); a.setDense( SDR_dense_t({0, 1, 0, 0, 0})); SDR b(a); - ASSERT_EQ( b.getFlatSparse(), vector({1}) ); + ASSERT_EQ( b.getSparse(), vector({1}) ); ASSERT_TRUE(a == b); } @@ -75,10 +75,10 @@ TEST(SdrTest, TestZero) { a.setDense( vector(16, 1) ); a.zero(); ASSERT_EQ( vector(16, 0), a.getDense() ); - ASSERT_EQ( a.getFlatSparse().size(), 0ul); - ASSERT_EQ( a.getSparse().size(), 2ul); - ASSERT_EQ( a.getSparse().at(0).size(), 0ul); - ASSERT_EQ( a.getSparse().at(1).size(), 0ul); + ASSERT_EQ( a.getSparse().size(), 0ul); + ASSERT_EQ( a.getCoordinates().size(), 2ul); + ASSERT_EQ( a.getCoordinates().at(0).size(), 0ul); + ASSERT_EQ( a.getCoordinates().at(1).size(), 0ul); } TEST(SdrTest, TestSDR_Examples) { @@ -95,19 +95,19 @@ TEST(SdrTest, TestSDR_Examples) { 0, 1, 0, 0, 0, 1 })); ASSERT_EQ( data, X.getDense() ); - X.setFlatSparse(SDR_flatSparse_t({ 1, 4, 8 })); + X.setSparse(SDR_sparse_t({ 1, 4, 8 })); ASSERT_EQ( data, X.getDense() ); - X.setSparse(SDR_sparse_t({{ 0, 1, 2,}, { 1, 1, 2 }})); + X.setCoordinates(SDR_coordinate_t({{ 0, 1, 2,}, { 1, 1, 2 }})); ASSERT_EQ( data, X.getDense() ); // Access data in any format, SDR will automatically convert data formats. ASSERT_EQ( X.getDense(), SDR_dense_t({ 0, 1, 0, 0, 1, 0, 0, 0, 1 }) ); - ASSERT_EQ( X.getSparse(), SDR_sparse_t({{ 0, 1, 2 }, {1, 1, 2}}) ); - ASSERT_EQ( X.getFlatSparse(), SDR_flatSparse_t({ 1, 4, 8 }) ); + ASSERT_EQ( X.getCoordinates(), SDR_coordinate_t({{ 0, 1, 2 }, {1, 1, 2}}) ); + ASSERT_EQ( X.getSparse(), SDR_sparse_t({ 1, 4, 8 }) ); // Data format conversions are cached, and when an SDR value changes the // cache is cleared. - X.setFlatSparse(SDR_flatSparse_t({})); // Assign new data to the SDR, clearing the cache. + X.setSparse(SDR_sparse_t({})); // Assign new data to the SDR, clearing the cache. X.getDense(); // This line will convert formats. X.getDense(); // This line will resuse the result of the previous line @@ -129,7 +129,7 @@ TEST(SdrTest, TestSDR_Examples) { dense[2] = true; X.setDense( dense ); // Notify the SDR of the changes. after = X.getDense().data(); - ASSERT_EQ( X.getFlatSparse(), SDR_flatSparse_t({ 2 }) ); + ASSERT_EQ( X.getSparse(), SDR_sparse_t({ 2 }) ); ASSERT_EQ( before, after ); } @@ -174,81 +174,81 @@ TEST(SdrTest, TestSetDenseInplace) { ASSERT_EQ( a.getDense(), a_data ); } -TEST(SdrTest, TestSetFlatSparseVec) { +TEST(SdrTest, TestSetSparseVec) { SDR a({11, 10, 4}); - UInt *before = a.getFlatSparse().data(); + UInt *before = a.getSparse().data(); auto vec = vector(a.size, 1); UInt *data = vec.data(); for(UInt i = 0; i < a.size; i++) vec[i] = i; - a.setFlatSparse( vec ); - UInt *after = a.getFlatSparse().data(); + a.setSparse( vec ); + UInt *after = a.getSparse().data(); ASSERT_NE( before, after ); ASSERT_EQ( after, data ); } -TEST(SdrTest, TestSetFlatSparsePtr) { +TEST(SdrTest, TestSetSparsePtr) { SDR a({11, 10, 4}); auto vec = vector(a.size, 1); for(UInt i = 0; i < a.size; i++) vec[i] = i; a.zero(); - a.setFlatSparse( (UInt*) vec.data(), a.size ); - ASSERT_EQ( a.getFlatSparse(), vec ); - ASSERT_NE( a.getFlatSparse().data(), vec.data()); // true copy not a reference + a.setSparse( (UInt*) vec.data(), a.size ); + ASSERT_EQ( a.getSparse(), vec ); + ASSERT_NE( a.getSparse().data(), vec.data()); // true copy not a reference } -TEST(SdrTest, TestSetFlatSparseInplace) { +TEST(SdrTest, TestSetSparseInplace) { // Test both mutable & inplace methods at the same time, which is the intended use case. SDR a({10, 10}); a.zero(); - auto& a_data = a.getFlatSparse(); + auto& a_data = a.getSparse(); ASSERT_EQ( a_data, vector(0) ); a_data.push_back(0); - a.setFlatSparse( a_data ); - ASSERT_EQ( a.getFlatSparse().data(), a.getFlatSparse().data() ); - ASSERT_EQ( a.getFlatSparse(), a.getFlatSparse() ); - ASSERT_EQ( a.getFlatSparse().data(), a_data.data() ); - ASSERT_EQ( a.getFlatSparse(), a_data ); - ASSERT_EQ( a.getFlatSparse(), vector(1) ); + a.setSparse( a_data ); + ASSERT_EQ( a.getSparse().data(), a.getSparse().data() ); + ASSERT_EQ( a.getSparse(), a.getSparse() ); + ASSERT_EQ( a.getSparse().data(), a_data.data() ); + ASSERT_EQ( a.getSparse(), a_data ); + ASSERT_EQ( a.getSparse(), vector(1) ); a_data.clear(); - a.setFlatSparse( a_data ); + a.setSparse( a_data ); ASSERT_EQ( a.getDense(), vector(a.size, 0) ); } -TEST(SdrTest, TestSetSparse) { +TEST(SdrTest, TestSetCoordinates) { SDR a({4, 1, 3}); - void *before = a.getSparse().data(); + void *before = a.getCoordinates().data(); auto vec = vector>({ { 0, 1, 2, 0 }, { 0, 0, 0, 0 }, { 0, 1, 2, 1 } }); void *data = vec.data(); - a.setSparse( vec ); - void *after = a.getSparse().data(); + a.setCoordinates( vec ); + void *after = a.getCoordinates().data(); ASSERT_EQ( after, data ); ASSERT_NE( before, after ); } -TEST(SdrTest, TestSetSparseCopy) { +TEST(SdrTest, TestSetCoordinatesCopy) { SDR a({ 3, 3 }); - void *before = a.getSparse().data(); + void *before = a.getCoordinates().data(); auto vec = vector>({ { 0.0f, 1.0f, 2.0f }, { 1.0f, 1.0f, 2.0f } }); void *data = vec.data(); - a.setSparse( vec ); - void *after = a.getSparse().data(); + a.setCoordinates( vec ); + void *after = a.getCoordinates().data(); ASSERT_EQ( before, after ); // Data copied from vec into sdr's buffer ASSERT_NE( after, data ); // Data copied from vec into sdr's buffer - ASSERT_EQ( a.getFlatSparse(), SDR_flatSparse_t({ 1, 4, 8 })); + ASSERT_EQ( a.getSparse(), SDR_sparse_t({ 1, 4, 8 })); } -TEST(SdrTest, TestSetSparseInplace) { +TEST(SdrTest, TestSetCoordinatesInplace) { // Test both mutable & inplace methods at the same time, which is the intended use case. SDR a({10, 10}); a.zero(); - auto& a_data = a.getSparse(); + auto& a_data = a.getCoordinates(); ASSERT_EQ( a_data, vector>({{}, {}}) ); a_data[0].push_back(0); a_data[1].push_back(0); @@ -256,17 +256,17 @@ TEST(SdrTest, TestSetSparseInplace) { a_data[1].push_back(7); a_data[0].push_back(7); a_data[1].push_back(1); - a.setSparse( a_data ); + a.setCoordinates( a_data ); ASSERT_EQ( a.getSum(), 3ul ); // I think some of these check the same things but thats ok. - ASSERT_EQ( (void*) a.getSparse().data(), (void*) a.getSparse().data() ); - ASSERT_EQ( a.getSparse(), a.getSparse() ); - ASSERT_EQ( a.getSparse().data(), a_data.data() ); - ASSERT_EQ( a.getSparse(), a_data ); - ASSERT_EQ( a.getFlatSparse(), vector({0, 37, 71}) ); // Check data ok + ASSERT_EQ( (void*) a.getCoordinates().data(), (void*) a.getCoordinates().data() ); + ASSERT_EQ( a.getCoordinates(), a.getCoordinates() ); + ASSERT_EQ( a.getCoordinates().data(), a_data.data() ); + ASSERT_EQ( a.getCoordinates(), a_data ); + ASSERT_EQ( a.getSparse(), vector({0, 37, 71}) ); // Check data ok a_data[0].clear(); a_data[1].clear(); - a.setSparse( a_data ); + a.setCoordinates( a_data ); ASSERT_EQ( a.getDense(), vector(a.size, 0) ); } @@ -276,32 +276,32 @@ TEST(SdrTest, TestSetSDR) { // Test dense assignment works a.setDense(SDR_dense_t({1, 1, 1, 1, 1})); b.setSDR(a); - ASSERT_EQ( b.getFlatSparse(), vector({0, 1, 2, 3, 4}) ); + ASSERT_EQ( b.getSparse(), vector({0, 1, 2, 3, 4}) ); // Test flat sparse assignment works - a.setFlatSparse(SDR_flatSparse_t({0, 1, 2, 3, 4})); + a.setSparse(SDR_sparse_t({0, 1, 2, 3, 4})); b.setSDR(a); ASSERT_EQ( b.getDense(), vector({1, 1, 1, 1, 1}) ); // Test sparse assignment works - a.setSparse(SDR_sparse_t({{0, 1, 2, 3, 4}})); + a.setCoordinates(SDR_coordinate_t({{0, 1, 2, 3, 4}})); b.setSDR(a); ASSERT_EQ( b.getDense(), vector({1, 1, 1, 1, 1}) ); } -TEST(SdrTest, TestGetDenseFromFlatSparse) { +TEST(SdrTest, TestGetDenseFromSparse) { // Test zeros SDR z({4, 4}); - z.setFlatSparse(SDR_flatSparse_t({})); + z.setSparse(SDR_sparse_t({})); ASSERT_EQ( z.getDense(), vector(16, 0) ); // Test ones SDR nz({4, 4}); - nz.setFlatSparse(SDR_flatSparse_t( + nz.setSparse(SDR_sparse_t( {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15})); ASSERT_EQ( nz.getDense(), vector(16, 1) ); // Test 1-D SDR d1({30}); - d1.setFlatSparse(SDR_flatSparse_t({1, 29, 4, 5, 7})); + d1.setSparse(SDR_sparse_t({1, 29, 4, 5, 7})); vector ans(30, 0); ans[1] = 1; ans[29] = 1; @@ -312,7 +312,7 @@ TEST(SdrTest, TestGetDenseFromFlatSparse) { // Test 3-D SDR d3({10, 10, 10}); - d3.setFlatSparse(SDR_flatSparse_t({0, 5, 50, 55, 500, 550, 555, 999})); + d3.setSparse(SDR_sparse_t({0, 5, 50, 55, 500, 550, 555, 999})); vector ans2(1000, 0); ans2[0] = 1; ans2[5] = 1; @@ -325,10 +325,10 @@ TEST(SdrTest, TestGetDenseFromFlatSparse) { ASSERT_EQ( d3.getDense(), ans2 ); } -TEST(SdrTest, TestGetDenseFromSparse) { +TEST(SdrTest, TestGetDenseFromCoordinates) { // Test simple 2-D SDR a({3, 3}); - a.setSparse(SDR_sparse_t({{1, 0, 2}, {2, 0, 2}})); + a.setCoordinates(SDR_coordinate_t({{1, 0, 2}, {2, 0, 2}})); vector ans(9, 0); ans[0] = 1; ans[5] = 1; @@ -337,29 +337,29 @@ TEST(SdrTest, TestGetDenseFromSparse) { // Test zeros SDR z({99, 1}); - z.setSparse(SDR_sparse_t({{}, {}})); + z.setCoordinates(SDR_coordinate_t({{}, {}})); ASSERT_EQ( z.getDense(), vector(99, 0) ); } -TEST(SdrTest, TestGetFlatSparseFromDense) { +TEST(SdrTest, TestGetSparseFromDense) { // Test simple 2-D SDR. SDR a({3, 3}); a.zero(); auto dense = a.getDense(); dense[5] = 1; dense[8] = 1; a.setDense(dense); - ASSERT_EQ(a.getFlatSparse().at(0), 5ul); - ASSERT_EQ(a.getFlatSparse().at(1), 8ul); + ASSERT_EQ(a.getSparse().at(0), 5ul); + ASSERT_EQ(a.getSparse().at(1), 8ul); // Test zero'd SDR. a.setDense( vector(a.size, 0) ); - ASSERT_EQ( a.getFlatSparse().size(), 0ul ); + ASSERT_EQ( a.getSparse().size(), 0ul ); } -TEST(SdrTest, TestGetFlatSparseFromSparse) { +TEST(SdrTest, TestGetSparseFromCoordinates) { // Test simple 2-D SDR. SDR a({3, 3}); a.zero(); - auto& index = a.getSparse(); + auto& index = a.getCoordinates(); ASSERT_EQ( index.size(), 2ul ); ASSERT_EQ( index[0].size(), 0ul ); ASSERT_EQ( index[1].size(), 0ul ); @@ -372,53 +372,53 @@ TEST(SdrTest, TestGetFlatSparseFromSparse) { // Insert flat index 5 index.at(0).push_back(1); index.at(1).push_back(2); - a.setSparse( index ); - ASSERT_EQ(a.getFlatSparse().at(0), 4ul); - ASSERT_EQ(a.getFlatSparse().at(1), 8ul); - ASSERT_EQ(a.getFlatSparse().at(2), 5ul); + a.setCoordinates( index ); + ASSERT_EQ(a.getSparse().at(0), 4ul); + ASSERT_EQ(a.getSparse().at(1), 8ul); + ASSERT_EQ(a.getSparse().at(2), 5ul); // Test zero'd SDR. - a.setSparse(SDR_sparse_t( {{}, {}} )); - ASSERT_EQ( a.getFlatSparse().size(), 0ul ); + a.setCoordinates(SDR_coordinate_t( {{}, {}} )); + ASSERT_EQ( a.getSparse().size(), 0ul ); } -TEST(SdrTest, TestGetSparseFromFlat) { +TEST(SdrTest, TestGetCoordinatesFromSparse) { // Test simple 2-D SDR. SDR a({3, 3}); a.zero(); - auto& index = a.getSparse(); + auto& index = a.getCoordinates(); ASSERT_EQ( index.size(), 2ul ); ASSERT_EQ( index[0].size(), 0ul ); ASSERT_EQ( index[1].size(), 0ul ); - a.setFlatSparse(SDR_flatSparse_t({ 4, 8, 5 })); - ASSERT_EQ( a.getSparse(), vector>({ + a.setSparse(SDR_sparse_t({ 4, 8, 5 })); + ASSERT_EQ( a.getCoordinates(), vector>({ { 1, 2, 1 }, { 1, 2, 2 } }) ); // Test zero'd SDR. - a.setFlatSparse(SDR_flatSparse_t( { } )); - ASSERT_EQ( a.getSparse(), vector>({{}, {}}) ); + a.setSparse(SDR_sparse_t( { } )); + ASSERT_EQ( a.getCoordinates(), vector>({{}, {}}) ); } -TEST(SdrTest, TestGetSparseFromDense) { +TEST(SdrTest, TestGetCoordinatesFromDense) { // Test simple 2-D SDR. SDR a({3, 3}); a.zero(); auto dense = a.getDense(); dense[5] = 1; dense[8] = 1; a.setDense(dense); - ASSERT_EQ( a.getSparse(), vector>({ + ASSERT_EQ( a.getCoordinates(), vector>({ { 1, 2 }, { 2, 2 }}) ); // Test zero'd SDR. a.setDense( vector(a.size, 0) ); - ASSERT_EQ( a.getSparse()[0].size(), 0ul ); - ASSERT_EQ( a.getSparse()[1].size(), 0ul ); + ASSERT_EQ( a.getCoordinates()[0].size(), 0ul ); + ASSERT_EQ( a.getCoordinates()[1].size(), 0ul ); } TEST(SdrTest, TestAt) { SDR a({3, 3}); - a.setFlatSparse(SDR_flatSparse_t( {4, 5, 8} )); + a.setSparse(SDR_sparse_t( {4, 5, 8} )); ASSERT_TRUE( a.at( {1, 1} )); ASSERT_TRUE( a.at( {1, 2} )); ASSERT_TRUE( a.at( {2, 2} )); @@ -523,7 +523,7 @@ TEST(SdrTest, TestRandomize) { vector af( af_test.size, 0 ); for( UInt i = 0; i < iterations; i++ ) { af_test.randomize( sparsity ); - for( auto idx : af_test.getFlatSparse() ) + for( auto idx : af_test.getSparse() ) af[ idx ] += 1; } for( auto f : af ) { @@ -593,9 +593,9 @@ TEST(SdrTest, TestEquality) { test_cases.push_back( new SDR({ 3, 3 })); test_cases.back()->setDense(SDR_dense_t({0, 1, 0, 0, 1, 0, 0, 0, 1})); test_cases.push_back( new SDR({ 3, 3 })); - test_cases.back()->setFlatSparse(SDR_flatSparse_t({0,})); + test_cases.back()->setSparse(SDR_sparse_t({0,})); test_cases.push_back( new SDR({ 3, 3 })); - test_cases.back()->setFlatSparse(SDR_flatSparse_t({3, 4, 6})); + test_cases.back()->setSparse(SDR_sparse_t({3, 4, 6})); // Check that SDRs equal themselves for(UInt x = 0; x < test_cases.size(); x++) { @@ -633,12 +633,12 @@ TEST(SdrTest, TestSaveLoad) { // Test flat data SDR flat({ 3, 3 }); - flat.setFlatSparse(SDR_flatSparse_t({ 1, 4, 8 })); + flat.setSparse(SDR_sparse_t({ 1, 4, 8 })); flat.save( outfile ); // Test index data SDR index({ 3, 3 }); - index.setSparse(SDR_sparse_t({ + index.setCoordinates(SDR_coordinate_t({ { 0, 1, 2 }, { 1, 1, 2 }})); index.save( outfile ); @@ -754,12 +754,12 @@ TEST(SdrTest, TestIntersectionExampleUsage) { // Setup 2 SDRs to hold the inputs. SDR A({ 10u }); SDR B({ 10u }); - A.setFlatSparse(SDR_flatSparse_t( {2, 3, 4, 5})); - B.setFlatSparse(SDR_flatSparse_t({0, 1, 2, 3})); + A.setSparse(SDR_sparse_t( {2, 3, 4, 5})); + B.setSparse(SDR_sparse_t({0, 1, 2, 3})); // Calculate the logical intersection SDR_Intersection X(A, B); - ASSERT_EQ(X.getFlatSparse(), SDR_flatSparse_t({2, 3})); + ASSERT_EQ(X.getSparse(), SDR_sparse_t({2, 3})); // Assignments to the input SDRs are propigated to the SDR_Intersection B.zero();