From e66928c00081e63dd001bb8089b74e4175172aea Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Mon, 1 Jul 2019 19:10:23 +0200 Subject: [PATCH 1/8] Connections: limit SegmentIdx, SynapseIdx to char this is for memory footprint, using unsigned char (upto 255) instead of uint_16_t --- src/htm/algorithms/Connections.hpp | 6 +++--- src/htm/algorithms/TemporalMemory.hpp | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/htm/algorithms/Connections.hpp b/src/htm/algorithms/Connections.hpp index 26243bb83b..b1c1d6d6d0 100644 --- a/src/htm/algorithms/Connections.hpp +++ b/src/htm/algorithms/Connections.hpp @@ -22,7 +22,6 @@ #ifndef NTA_CONNECTIONS_HPP #define NTA_CONNECTIONS_HPP -#include #include #include #include @@ -36,9 +35,10 @@ namespace htm { //TODO instead of typedefs, use templates for proper type-checking? +//TODO profile to use better (smaller?) types using CellIdx = htm::ElemSparse; // CellIdx must match with ElemSparse, defined in Sdr.hpp -using SegmentIdx= UInt16; /** Index of segment in cell. */ -using SynapseIdx= UInt16; /** Index of synapse in segment. */ //TODO profile to use better (smaller?) types +using SegmentIdx= unsigned char; /** Index of segment in cell. */ +using SynapseIdx= unsigned char; /** Index of synapse in segment. */ using Segment = UInt32; /** Index of segment's data. */ using Synapse = UInt32; /** Index of synapse's data. */ using Permanence= Real32; //TODO experiment with half aka float16 diff --git a/src/htm/algorithms/TemporalMemory.hpp b/src/htm/algorithms/TemporalMemory.hpp index 4c77045d2a..bf37c4de62 100644 --- a/src/htm/algorithms/TemporalMemory.hpp +++ b/src/htm/algorithms/TemporalMemory.hpp @@ -104,9 +104,13 @@ class TemporalMemory : public Serializable * * @param maxSegmentsPerCell * The maximum number of segments per cell. + * The value you can choose here is limited by the type SegmentIdx + * in Connections.hpp, change it if you need larger values. * * @param maxSynapsesPerSegment * The maximum number of synapses per segment. + * The value you can choose here is limited by the type SynapseIdx + * in Connections.hpp, change it there if you needed to use large values. * * @param checkInputs * Whether to check that the activeColumns are sorted without From 493ad2410431c5066a845bcbe41e3976e6f713c7 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Tue, 2 Jul 2019 20:19:14 +0200 Subject: [PATCH 2/8] SP: remove tieBreakers as those are not needed, and make memory & CPU footprint --- src/htm/algorithms/SpatialPooler.cpp | 21 ++++++--------------- src/htm/algorithms/SpatialPooler.hpp | 3 --- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 8b83b79e08..d9eedd1595 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -398,7 +398,7 @@ void SpatialPooler::initialize( NTA_CHECK(numColumns_ > 0); NTA_CHECK(numInputs_ > 0); - // 1D input produces 1D output; 2D => 2D, etc. + // 1D input produces 1D output; 2D => 2D, etc. //TODO allow nD -> mD conversion NTA_CHECK(inputDimensions_.size() == columnDimensions_.size()); NTA_CHECK((numActiveColumnsPerInhArea > 0 && localAreaDensity < 0) || @@ -429,12 +429,7 @@ void SpatialPooler::initialize( iterationNum_ = 0u; iterationLearnNum_ = 0u; - tieBreaker_.resize(numColumns_); - for (Size i = 0; i < numColumns_; i++) { - tieBreaker_[i] = (Real)(0.01 * rng_.getReal64()); - } - - overlapDutyCycles_.assign(numColumns_, 0); + overlapDutyCycles_.assign(numColumns_, 0); //TODO make all these sparse or rm to reduce footprint activeDutyCycles_.assign(numColumns_, 0); minOverlapDutyCycles_.assign(numColumns_, 0.0); boostFactors_.assign(numColumns_, 1); @@ -854,11 +849,6 @@ void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, NTA_ASSERT(!overlaps.empty()); NTA_ASSERT(density > 0.0f && density <= 1.0f); - // Add a tiebreaker to the overlaps so that the output is deterministic. - vector overlaps_(overlaps.begin(), overlaps.end()); - for(UInt i = 0; i < numColumns_; i++) - overlaps_[i] += tieBreaker_[i]; - activeColumns.clear(); const UInt numDesired = (UInt)(density * numColumns_); NTA_CHECK(numDesired > 0) << "Not enough columns (" << numColumns_ << ") " @@ -869,8 +859,10 @@ void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, for(UInt i = 0; i < numColumns_; i++) activeColumns.push_back(i); // Compare the column indexes by their overlap. - auto compare = [&overlaps_](const UInt &a, const UInt &b) -> bool - {return (overlaps_[a] == overlaps_[b]) ? a > b : overlaps_[a] > overlaps_[b];}; + auto compare = [&overlaps](const UInt &a, const UInt &b) -> bool + {return (overlaps[a] == overlaps[b]) ? a > b : overlaps[a] > overlaps[b];}; //for determinism if overlaps match (tieBreaker does not solve that), + //otherwise we'd return just `return overlaps[a] > overlaps[b]`. + // 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 // elements about the Nth element, with all elements on their correct side of @@ -1043,7 +1035,6 @@ bool SpatialPooler::operator==(const SpatialPooler& o) const{ if (overlapDutyCycles_ != o.overlapDutyCycles_) return false; if (activeDutyCycles_ != o.activeDutyCycles_) return false; if (minOverlapDutyCycles_ != o.minOverlapDutyCycles_) return false; - if (tieBreaker_ != o.tieBreaker_) return false; // compare connections if (connections_ != o.connections_) return false; diff --git a/src/htm/algorithms/SpatialPooler.hpp b/src/htm/algorithms/SpatialPooler.hpp index dc3d41571c..2aa9340613 100644 --- a/src/htm/algorithms/SpatialPooler.hpp +++ b/src/htm/algorithms/SpatialPooler.hpp @@ -287,7 +287,6 @@ class SpatialPooler : public Serializable ar(CEREAL_NVP(overlapDutyCycles_)); ar(CEREAL_NVP(activeDutyCycles_)); ar(CEREAL_NVP(minOverlapDutyCycles_)); - ar(CEREAL_NVP(tieBreaker_)); ar(CEREAL_NVP(connections_)); ar(CEREAL_NVP(rng_)); } @@ -322,7 +321,6 @@ class SpatialPooler : public Serializable ar(CEREAL_NVP(overlapDutyCycles_)); ar(CEREAL_NVP(activeDutyCycles_)); ar(CEREAL_NVP(minOverlapDutyCycles_)); - ar(CEREAL_NVP(tieBreaker_)); ar(CEREAL_NVP(connections_)); ar(CEREAL_NVP(rng_)); @@ -1233,7 +1231,6 @@ class SpatialPooler : public Serializable vector overlaps_; vector overlapsPct_; vector boostedOverlaps_; - vector tieBreaker_; UInt version_; From 0bd49058b259b73207dc2d1849180dee13449efe Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Wed, 3 Jul 2019 05:33:36 +0200 Subject: [PATCH 3/8] Hotgym: change seed so that TM (already wrong params) produces some! output at least some, not empty --- src/examples/hotgym/HelloSPTP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/examples/hotgym/HelloSPTP.cpp b/src/examples/hotgym/HelloSPTP.cpp index 50883c70ff..85dc3b86f8 100644 --- a/src/examples/hotgym/HelloSPTP.cpp +++ b/src/examples/hotgym/HelloSPTP.cpp @@ -64,7 +64,7 @@ Real64 BenchmarkHotgym::run(UInt EPOCHS, bool useSPlocal, bool useSPglobal, bool SpatialPooler spLocal(enc.dimensions, vector{COLS}); // Spatial pooler with local inh spGlobal.setGlobalInhibition(true); spLocal.setGlobalInhibition(false); - Random rnd(1); //uses fixed seed for deterministic output checks + Random rnd(42); //uses fixed seed for deterministic output checks TemporalMemory tm(vector{COLS}, CELLS); From b918db2a2b0f8020b52d6af2b22438ee72635ac9 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Wed, 3 Jul 2019 06:54:43 +0200 Subject: [PATCH 4/8] fixed test to reflect removed tieBreakers also chaged Encoder gold, because in Hotgym I needed to change seed to get reasonable (other problem) representation from TM --- src/examples/hotgym/HelloSPTP.cpp | 12 +++---- src/htm/algorithms/SpatialPooler.cpp | 2 +- .../unit/algorithms/SpatialPoolerTest.cpp | 8 +++-- src/test/unit/engine/CppRegionTest.cpp | 6 ++-- src/test/unit/regions/TMRegionTest.cpp | 32 +++++++++++-------- 5 files changed, 34 insertions(+), 26 deletions(-) diff --git a/src/examples/hotgym/HelloSPTP.cpp b/src/examples/hotgym/HelloSPTP.cpp index 85dc3b86f8..c123ba55bc 100644 --- a/src/examples/hotgym/HelloSPTP.cpp +++ b/src/examples/hotgym/HelloSPTP.cpp @@ -166,29 +166,29 @@ Real64 BenchmarkHotgym::run(UInt EPOCHS, bool useSPlocal, bool useSPglobal, bool // check deterministic SP, TM output SDR goldEnc({DIM_INPUT}); const SDR_sparse_t deterministicEnc{ - 0, 4, 13, 21, 24, 30, 32, 37, 40, 46, 47, 48, 50, 51, 64, 68, 79, 81, 89, 97, 99, 114, 120, 135, 136, 140, 141, 143, 144, 147, 151, 155, 161, 162, 164, 165, 169, 172, 174, 179, 181, 192, 201, 204, 205, 210, 213, 226, 237, 242, 247, 249, 254, 255, 262, 268, 271, 282, 283, 295, 302, 306, 307, 317, 330, 349, 353, 366, 368, 380, 393, 399, 404, 409, 410, 420, 422, 441,446, 447, 456, 458, 464, 468, 476, 497, 499, 512, 521, 528, 531, 534, 538, 539, 541, 545, 550, 557, 562, 565, 575, 581, 589, 592, 599, 613, 617, 622, 647, 652, 686, 687, 691, 699, 704, 710, 713, 716, 722, 729, 736, 740, 747, 749, 753, 754, 758, 766, 778, 790, 791, 797, 800, 808, 809, 812, 815, 826, 828, 830, 837, 838, 852, 853, 856, 863, 864, 873, 878, 882, 885, 893, 894, 895, 905, 906, 914, 915, 920, 924, 927, 937, 939, 944, 947, 951, 954, 956, 967, 968, 969, 973, 975, 976, 981, 991, 998 + 0, 4, 13, 21, 24, 30, 32, 37, 40, 46, 47, 48, 50, 51, 64, 68, 79, 81, 89, 97, 99, 114, 120, 135, 136, 140, 141, 143, 144, 147, 151, 155, 161, 162, 164, 165, 169, 172, 174, 179, 181, 192, 201, 204, 205, 210, 213, 226, 227, 237, 242, 247, 249, 254, 255, 262, 268, 271, 282, 283, 295, 302, 306, 307, 317, 330, 349, 353, 366, 380, 383, 393, 404, 409, 410, 420, 422, 441,446, 447, 456, 458, 464, 468, 476, 497, 499, 512, 521, 528, 531, 534, 538, 539, 541, 545, 550, 557, 562, 565, 575, 581, 589, 592, 599, 613, 617, 622, 647, 652, 686, 687, 691, 699, 704, 710, 713, 716, 722, 729, 736, 740, 747, 749, 753, 754, 758, 766, 778, 790, 791, 797, 800, 808, 809, 812, 815, 826, 828, 830, 837, 852, 853, 856, 863, 864, 873, 878, 882, 885, 893, 894, 895, 905, 906, 914, 915, 920, 924, 927, 937, 939, 944, 947, 951, 954, 956, 967, 968, 969, 973, 975, 976, 979, 981, 991, 998 }; goldEnc.setSparse(deterministicEnc); SDR goldSP({COLS}); const SDR_sparse_t deterministicSP{ - 72, 75, 284, 303, 305, 317, 329, 525, 1095, 2027 + 72, 308, 337, 1512, 1518, 1956, 1965, 1975, 1994, 2008 }; goldSP.setSparse(deterministicSP); SDR goldSPlocal({COLS}); const SDR_sparse_t deterministicSPlocal{ - 6, 12, 26, 57, 63, 72, 75, 76, 77, 80, 82, 103, 105, 124, 135, 154, 171, 174, 175, 185, 192, 193, 195, 198, 263, 284, 296, 302, 303, 305, 313, 317, 319, 320, 356, 363, 364, 401, 403, 404, 410, 413, 425, 426, 428, 449, 491, 496, 511, 515, 516, 518, 520, 525, 529, 536, 550, 556, 574, 583, 592, 597, 598, 603, 609, 622, 626, 636, 645, 652, 704, 706, 722, 726, 727, 728, 729, 747, 751, 766, 779, 808, 833, 837, 838, 840, 848, 850, 853, 860, 908, 912, 918, 919, 923, 927, 929, 930, 931, 932, 970, 989, 1006, 1038, 1066, 1082, 1085, 1087, 1092, 1094, 1095, 1113, 1115, 1125, 1128, 1174, 1179, 1180, 1182, 1185, 1205, 1206, 1232, 1236, 1238, 1239, 1240, 1245, 1271, 1292, 1295, 1300, 1303, 1307, 1311, 1319, 1320, 1322, 1382, 1401, 1412, 1415, 1421, 1426, 1431, 1434, 1438, 1470, 1474, 1492, 1501, 1511, 1521, 1524, 1525, 1530, 1532, 1537, 1540, 1600, 1617, 1620, 1622, 1632, 1638, 1641, 1667, 1672, 1680, 1684, 1686, 1690, 1699, 1702, 1742, 1744, 1745, 1746, 1765, 1770, 1774, 1801, 1807, 1808, 1816, 1830, 1834, 1849, 1861, 1867, 1871, 1882, 1902, 1907, 1943, 1945, 1955, 1956, 1966, 1968, 1969, 1971, 1986, 2018, 2025, 2027 + 12, 17, 36, 39, 62, 71, 72, 74, 75, 82, 83, 85, 93, 102, 131, 147, 171, 179, 186, 188, 189, 192, 194, 201, 260, 263, 277, 287, 298, 308, 319, 322, 323, 326, 334, 337, 340, 355, 365, 407, 422, 423, 425, 427, 429, 432, 434, 443, 445, 493, 494, 498, 502, 508, 513, 523, 534, 540, 542, 554, 559, 580, 585, 586, 610, 611, 612, 629, 631, 637, 644, 645, 646, 647, 691, 697, 698, 702, 703, 707, 709, 746, 749, 767, 806, 809, 810, 811, 825, 832, 833, 838, 839, 847, 889, 906, 920, 923, 928, 929, 931, 934, 935, 936, 952, 989, 1003, 1005, 1018, 1073, 1076, 1078, 1089, 1094, 1095, 1100, 1102, 1114, 1115, 1133, 1134, 1147, 1168, 1169, 1184, 1193, 1196, 1203, 1204, 1209, 1232, 1233, 1236, 1244, 1253, 1254, 1268, 1278, 1284, 1294, 1297, 1298, 1303, 1306, 1310, 1331, 1342, 1402, 1410, 1415, 1423, 1427, 1428, 1430, 1434, 1463, 1487, 1488, 1494, 1507, 1508, 1512, 1515, 1518, 1532, 1547, 1550, 1561, 1563, 1564, 1612, 1622, 1623, 1624, 1626, 1627, 1630, 1640, 1647, 1651, 1689, 1691, 1694, 1703, 1711, 1714, 1729, 1745, 1746, 1760, 1771, 1797, 1803, 1804, 1805, 1812, 1827, 1828, 1831, 1858, 1859, 1860, 1861, 1862, 1880, 1918, 1929, 1937, 1956, 1961, 1965, 1967, 1971, 1980, 1985, 1994, 2008, 2011, 2013 }; goldSPlocal.setSparse(deterministicSPlocal); SDR goldTM({COLS}); const SDR_sparse_t deterministicTM{ - 26, 75 //FIXME this is a really bad representation -> improve the params + 1965 //FIXME this is a really bad representation -> improve the params }; goldTM.setSparse(deterministicTM); - const float goldAn = 0.8f; + const float goldAn = 1.0f; if(EPOCHS == 5000) { //these hand-written values are only valid for EPOCHS = 5000 (default), but not for debug and custom runs. NTA_CHECK(input == goldEnc) << "Deterministic output of Encoder failed!\n" << input << "should be:\n" << goldEnc; @@ -197,7 +197,7 @@ Real64 BenchmarkHotgym::run(UInt EPOCHS, bool useSPlocal, bool useSPglobal, bool NTA_CHECK(outTM == goldTM) << "Deterministic output of TM failed!\n" << outTM << "should be:\n" << goldTM; NTA_CHECK(static_cast(an *10000.0f) == static_cast(goldAn *10000.0f)) //compare to 4 decimal places << "Deterministic output of Anomaly failed! " << an << "should be: " << goldAn; - NTA_CHECK(avgAnom10.getCurrentAvg() <= 0.82f) << "Deterministic average anom score failed:" << avgAnom10.getCurrentAvg(); + NTA_CHECK(avgAnom10.getCurrentAvg() <= 0.8f) << "Deterministic average anom score failed:" << avgAnom10.getCurrentAvg(); } // check runtime speed diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index d9eedd1595..4c96ba5085 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -363,7 +363,7 @@ void SpatialPooler::getConnectedSynapses(UInt column, void SpatialPooler::getConnectedCounts(UInt connectedCounts[]) const { for(UInt seg = 0; seg < numColumns_; seg++) { const auto &segment = connections_.dataForSegment( seg ); - connectedCounts[ seg ] = segment.numConnected; + connectedCounts[ seg ] = segment.numConnected; //TODO numConnected only used here, rm from SegmentData and compute for each segment.synapses? } } diff --git a/src/test/unit/algorithms/SpatialPoolerTest.cpp b/src/test/unit/algorithms/SpatialPoolerTest.cpp index e92cb73ef8..e19b85560f 100644 --- a/src/test/unit/algorithms/SpatialPoolerTest.cpp +++ b/src/test/unit/algorithms/SpatialPoolerTest.cpp @@ -1816,7 +1816,7 @@ TEST(SpatialPoolerTest, ZeroOverlap_NoStimulusThreshold_LocalInhibition) { SDR activeColumns( {nColumns} ); sp.compute(input, true, activeColumns); - EXPECT_EQ(activeColumns.getSum(), 4u); + EXPECT_EQ(activeColumns.getSum(), 3u); } TEST(SpatialPoolerTest, ZeroOverlap_StimulusThreshold_LocalInhibition) { @@ -2079,14 +2079,16 @@ TEST(SpatialPoolerTest, testConstructorVsInitialize) { TEST(SpatialPoolerTest, ExactOutput) { // Silver is an SDR that is loaded by direct initalization from a vector. SDR silver_sdr({ 200 }); - SDR_sparse_t data = {23, 71, 113, 118, 129, 172, 178, 182, 185, 190}; + SDR_sparse_t data = { + 4, 64, 74, 78, 85, 113, 125, 126, 127, 153 + }; silver_sdr.setSparse(data); // Gold tests initalizing an SDR from a manually created string in JSON format. // hint: you can generate this string using // silver_sdr.save(std::cout, JSON); - string gold = "{\"dimensions\": [200],\"sparse\": [23,71,113,118,129,172,178,182,185,190]}"; + string gold = "{\"dimensions\": [200],\"sparse\": [4, 64, 74, 78, 85, 113, 125, 126, 127, 153]}"; std::stringstream gold_stream( gold ); SDR gold_sdr; gold_sdr.load( gold_stream, JSON ); diff --git a/src/test/unit/engine/CppRegionTest.cpp b/src/test/unit/engine/CppRegionTest.cpp index 756c0462ff..dca65d27a1 100644 --- a/src/test/unit/engine/CppRegionTest.cpp +++ b/src/test/unit/engine/CppRegionTest.cpp @@ -149,11 +149,11 @@ TEST(CppRegionTest, testCppLinkingSDR) { const Array r2OutputArray = region2->getOutputData("bottomUpOut"); EXPECT_EQ(r2OutputArray.getType(), NTA_BasicType_SDR); - EXPECT_TRUE(r2OutputArray.getSDR().dimensions == r2dims) + EXPECT_EQ(r2OutputArray.getSDR().dimensions, r2dims) << "Expected dimensions on the output to match dimensions on the buffer."; VERBOSE << r2OutputArray << "\n"; - std::vector expected_output = {0, 1, 0, 1, 0, 1}; - EXPECT_TRUE(r2OutputArray == expected_output); + std::vector expected_output = {1, 0, 1, 0, 1, 0}; + EXPECT_TRUE(r2OutputArray == expected_output) << "expected " << r2OutputArray; } diff --git a/src/test/unit/regions/TMRegionTest.cpp b/src/test/unit/regions/TMRegionTest.cpp index 2660a36431..b223dbe914 100644 --- a/src/test/unit/regions/TMRegionTest.cpp +++ b/src/test/unit/regions/TMRegionTest.cpp @@ -272,8 +272,10 @@ TEST(TMRegionTest, testLinking) { EXPECT_TRUE(r3InputArray.getType() == NTA_BasicType_SDR); VERBOSE << " " << r3InputArray << "\n"; std::vector expected3in = VectorHelpers::sparseToBinary( - { 1, 2, 3, 5, 6, 8, 11, 13, 17, 19 }, (UInt32)r3InputArray.getCount()); - EXPECT_TRUE(r3InputArray == expected3in); + { + 0, 2, 3, 4, 6, 7, 10, 11, 14, 17 + }, (UInt32)r3InputArray.getCount()); + EXPECT_TRUE(r3InputArray == expected3in) << r3InputArray; VERBOSE << " TMRegion output " << region3->getOutputDimensions("bottomUpOut") << "\n"; @@ -288,11 +290,14 @@ TEST(TMRegionTest, testLinking) { EXPECT_TRUE(r3OutputArray.getType() == NTA_BasicType_SDR); VERBOSE << " " << r3OutputArray << "\n"; std::vector expected3out = VectorHelpers::sparseToBinary( - { 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u, - 25u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 40u, 41u, 42u, 43u, - 44u, 55u, 56u, 57u, 58u, 59u, 65u, 66u, 67u, 68u, 69u, 85u, 86u, 87u, - 88u, 89u, 95u, 96u, 97u, 98u, 99u }, (UInt32)r3OutputArray.getCount()); - EXPECT_TRUE(r3OutputArray == expected3out); + { + 0, 1, 2, 3, 4, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 70, + 71, 72, 73, 74, 85, 86, 87, 88, 890, 1, 2, 3, 4, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 70, 71, 72, 73, 74, 85, 86, 87, 88, 89 + }, (UInt32)r3OutputArray.getCount()); + EXPECT_TRUE(r3OutputArray == expected3out) << r3OutputArray; EXPECT_EQ(r3OutputArray.getSDR().getSparse().size(), 50u); // execute TMRegion several more times and check that it has output. @@ -308,11 +313,12 @@ TEST(TMRegionTest, testLinking) { << numberOfCols << " * " << cellsPerColumn; VERBOSE << " " << r3OutputArray << ")\n"; std::vector expected3outa = VectorHelpers::sparseToBinary( - {20u, 21u, 22u, 23u, 24u, 25u, 26u, 27u, 28u, 29u, 35u, 36u, 37u, 38u, - 39u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 52u, 53u, 54u, 60u, 61u, 62u, - 63u, 64u, 70u, 71u, 72u, 73u, 74u, 80u, 81u, 82u, 83u, 84u, 90u, 91u, - 92u, 93u, 94u, 95u, 96u, 97u, 98u, 99u}, (UInt32)r3OutputArray.getCount()); - EXPECT_TRUE(r3OutputArray == expected3outa); + { + 10, 11, 12, 13, 14, 30, 31, 32, 33, 34, 45, 46, 47, 48, 49, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92,93, 94, 95, 96, 97, 98, 99 + }, (UInt32)r3OutputArray.getCount()); + EXPECT_TRUE(r3OutputArray == expected3outa) << r3OutputArray; VERBOSE << " Input to VectorFileEffector " @@ -320,7 +326,7 @@ TEST(TMRegionTest, testLinking) { Array r4InputArray = region4->getInputData("dataIn"); EXPECT_TRUE(r4InputArray.getType() == NTA_BasicType_Real32); VERBOSE << " " << r4InputArray << "\n"; - EXPECT_TRUE(r4InputArray == expected3outa); + EXPECT_TRUE(r4InputArray == expected3outa) << r4InputArray; // cleanup region3->executeCommand({"closeFile"}); From 091fb3c5f538085cab3b21f9084d077810bdeedd Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Wed, 3 Jul 2019 07:03:48 +0200 Subject: [PATCH 5/8] comments --- src/htm/algorithms/Connections.cpp | 2 +- src/htm/algorithms/Connections.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/htm/algorithms/Connections.cpp b/src/htm/algorithms/Connections.cpp index c3deb5d2cc..15f3fd4032 100644 --- a/src/htm/algorithms/Connections.cpp +++ b/src/htm/algorithms/Connections.cpp @@ -199,7 +199,7 @@ void Connections::destroySegment(Segment segment) { const auto segmentOnCell = std::lower_bound(cellData.segments.begin(), cellData.segments.end(), segment, [&](Segment a, Segment b) { - return segmentOrdinals_[a] < segmentOrdinals_[b]; + return segmentOrdinals_[a] < segmentOrdinals_[b]; //TODO will this be slow if ordinals moved to SegmentData? }); NTA_ASSERT(segmentOnCell != cellData.segments.end()); diff --git a/src/htm/algorithms/Connections.hpp b/src/htm/algorithms/Connections.hpp index b1c1d6d6d0..5d033c6d44 100644 --- a/src/htm/algorithms/Connections.hpp +++ b/src/htm/algorithms/Connections.hpp @@ -631,7 +631,7 @@ class Connections : public Serializable Permanence connectedThreshold_; //TODO make const // Extra bookkeeping for faster computing of segment activity. - std::map> potentialSynapsesForPresynapticCell_; + std::map> potentialSynapsesForPresynapticCell_; //TODO use unordered_map std::map> connectedSynapsesForPresynapticCell_; std::map> potentialSegmentsForPresynapticCell_; std::map> connectedSegmentsForPresynapticCell_; From cbea67fe2b5217cbdbedd247b8bf83ec00526d59 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Wed, 3 Jul 2019 15:57:29 +0200 Subject: [PATCH 6/8] Fix segfault in test, thanks @dkeeney! --- src/test/unit/regions/TMRegionTest.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/unit/regions/TMRegionTest.cpp b/src/test/unit/regions/TMRegionTest.cpp index b223dbe914..1363ae20ed 100644 --- a/src/test/unit/regions/TMRegionTest.cpp +++ b/src/test/unit/regions/TMRegionTest.cpp @@ -289,13 +289,11 @@ TEST(TMRegionTest, testLinking) { << r3InputArray.getCount(); EXPECT_TRUE(r3OutputArray.getType() == NTA_BasicType_SDR); VERBOSE << " " << r3OutputArray << "\n"; - std::vector expected3out = VectorHelpers::sparseToBinary( + std::vector expected3out = VectorHelpers::sparseToBinary( //TODO replace with SDR { 0, 1, 2, 3, 4, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 70, - 71, 72, 73, 74, 85, 86, 87, 88, 890, 1, 2, 3, 4, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 70, 71, 72, 73, 74, 85, 86, 87, 88, 89 + 71, 72, 73, 74, 85, 86, 87, 88, 89 }, (UInt32)r3OutputArray.getCount()); EXPECT_TRUE(r3OutputArray == expected3out) << r3OutputArray; EXPECT_EQ(r3OutputArray.getSDR().getSparse().size(), 50u); From 2d1b7093b56ae33bdfa13acc08000c6adfe51067 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Wed, 3 Jul 2019 16:00:06 +0200 Subject: [PATCH 7/8] VectorHelpers:sparseToBinary add check for out of bounds --- src/htm/utils/VectorHelpers.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/htm/utils/VectorHelpers.hpp b/src/htm/utils/VectorHelpers.hpp index 37cd30044f..16a175f9c5 100644 --- a/src/htm/utils/VectorHelpers.hpp +++ b/src/htm/utils/VectorHelpers.hpp @@ -26,6 +26,7 @@ class VectorHelpers { std::vector binary(width); for (auto sparseIdx: sparseVector) { + NTA_ASSERT(sparseIdx < binary.size()) << "attemping to insert out of bounds element! " << sparseIdx; binary[sparseIdx] = (T)1; } return binary; From 869dbe30ac93bf773855551b21225e423e5e9828 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 20:15:26 +0200 Subject: [PATCH 8/8] Connections: revert back to UInt16 for SynapseIdx, SegmentIdx as there may be cases where 255 would be too small. UInt16 actually performs faster. --- src/htm/algorithms/Connections.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/htm/algorithms/Connections.hpp b/src/htm/algorithms/Connections.hpp index 5d033c6d44..cb0a6ef8ab 100644 --- a/src/htm/algorithms/Connections.hpp +++ b/src/htm/algorithms/Connections.hpp @@ -35,10 +35,9 @@ namespace htm { //TODO instead of typedefs, use templates for proper type-checking? -//TODO profile to use better (smaller?) types using CellIdx = htm::ElemSparse; // CellIdx must match with ElemSparse, defined in Sdr.hpp -using SegmentIdx= unsigned char; /** Index of segment in cell. */ -using SynapseIdx= unsigned char; /** Index of synapse in segment. */ +using SegmentIdx= UInt16; /** Index of segment in cell. */ +using SynapseIdx= UInt16; /** Index of synapse in segment. */ using Segment = UInt32; /** Index of segment's data. */ using Synapse = UInt32; /** Index of synapse's data. */ using Permanence= Real32; //TODO experiment with half aka float16