2424#include < iostream>
2525#include < htm/algorithms/Connections.hpp>
2626
27- namespace testing {
28-
2927using namespace std ;
3028using namespace htm ;
3129
32- #define EPSILON 0.0000001
33-
3430
3531void setupSampleConnections (Connections &connections) {
3632 // Cell with 1 segment.
@@ -122,11 +118,11 @@ TEST(ConnectionsTest, testCreateSynapse) {
122118
123119 SynapseData synapseData1 = connections.dataForSynapse (synapses[0 ]);
124120 ASSERT_EQ (50ul , synapseData1.presynapticCell );
125- ASSERT_NEAR ((Permanence)0.34 , synapseData1.permanence , EPSILON );
121+ ASSERT_NEAR ((Permanence)0.34 , synapseData1.permanence , htm::Epsilon );
126122
127123 SynapseData synapseData2 = connections.dataForSynapse (synapses[1 ]);
128124 ASSERT_EQ (synapseData2.presynapticCell , 150ul );
129- ASSERT_NEAR ((Permanence)0.48 , synapseData2.permanence , EPSILON );
125+ ASSERT_NEAR ((Permanence)0.48 , synapseData2.permanence , htm::Epsilon );
130126}
131127
132128/* *
@@ -293,14 +289,14 @@ TEST(ConnectionsTest, testUpdateSynapsePermanence) {
293289 connections.updateSynapsePermanence (synapse, 0 .21f );
294290
295291 SynapseData synapseData = connections.dataForSynapse (synapse);
296- ASSERT_NEAR (synapseData.permanence , (Real)0.21 , EPSILON );
292+ ASSERT_NEAR (synapseData.permanence , (Real)0.21 , htm::Epsilon );
297293
298294 // Test permanence floor
299295 connections.updateSynapsePermanence (synapse, -0 .02f );
300296 synapseData = connections.dataForSynapse (synapse);
301297 ASSERT_EQ (synapseData.permanence , (Real)0 .0f );
302298
303- connections.updateSynapsePermanence (synapse, (Real)(-EPSILON / 10.0 ));
299+ connections.updateSynapsePermanence (synapse, (Real)(-htm::Epsilon / 10.0 ));
304300 synapseData = connections.dataForSynapse (synapse);
305301 ASSERT_EQ (synapseData.permanence , (Real)0 .0f );
306302
@@ -309,7 +305,7 @@ TEST(ConnectionsTest, testUpdateSynapsePermanence) {
309305 synapseData = connections.dataForSynapse (synapse);
310306 ASSERT_EQ (synapseData.permanence , (Real)1 .0f );
311307
312- connections.updateSynapsePermanence (synapse, 1 .0f + (Real)(EPSILON / 10.0 ));
308+ connections.updateSynapsePermanence (synapse, 1 .0f + (Real)(htm::Epsilon / 10.0 ));
313309 synapseData = connections.dataForSynapse (synapse);
314310 ASSERT_EQ (synapseData.permanence , (Real)1 .0f );
315311}
@@ -407,7 +403,7 @@ TEST(ConnectionsTest, testAdaptSynapses) {
407403 perms[ synData.presynapticCell ] = synData.permanence ;
408404 }
409405 for (UInt i = 0 ; i < numInputs; i++)
410- ASSERT_NEAR ( truePerms[cell][i], perms[i], EPSILON );
406+ ASSERT_NEAR ( truePerms[cell][i], perms[i], htm::Epsilon );
411407 }
412408}
413409
@@ -480,6 +476,139 @@ TEST(ConnectionsTest, testRaisePermanencesToThresholdOutOfBounds) {
480476 << " raisePermanence fails when lower number of available synapses than requested by threshold" ;
481477}
482478
479+ TEST (ConnectionsTest, testSynapseCompetition) {
480+
481+ struct testCase {
482+ UInt nsyn; // Total number of potential synapses on segment
483+ UInt ncon; // Number of connected synapses, before calling synapseCompetition
484+ UInt min; // Bounds of synapseCompetition
485+ UInt max; // Bounds of synapseCompetition
486+ // The target number of synapses can't be met, just make sure it does not crash.
487+ bool expect_fail = false ;
488+ };
489+
490+ testCase emptySegment;
491+ emptySegment.nsyn = 0 ;
492+ emptySegment.ncon = 0 ;
493+ emptySegment.min = 3 ;
494+ emptySegment.max = 100 ;
495+ emptySegment.expect_fail = true ;
496+
497+ testCase fullSegment;
498+ fullSegment.nsyn = 100 ;
499+ fullSegment.ncon = 100 ;
500+ fullSegment.min = 3 ;
501+ fullSegment.max = 100 ;
502+
503+ testCase disconnect1;
504+ disconnect1.nsyn = 100 ;
505+ disconnect1.ncon = 100 ;
506+ disconnect1.min = 3 ;
507+ disconnect1.max = 99 ;
508+
509+ testCase minimum;
510+ minimum.nsyn = 100 ;
511+ minimum.ncon = 5 ;
512+ minimum.min = 10 ;
513+ minimum.max = 30 ;
514+
515+ testCase maximum;
516+ maximum.nsyn = 100 ;
517+ maximum.ncon = 77 ;
518+ maximum.min = 10 ;
519+ maximum.max = 30 ;
520+
521+ testCase no_change1;
522+ no_change1.nsyn = 100 ;
523+ no_change1.ncon = 10 ;
524+ no_change1.min = 10 ;
525+ no_change1.max = 30 ;
526+
527+ testCase no_change2;
528+ no_change2.nsyn = 100 ;
529+ no_change2.ncon = 20 ;
530+ no_change2.min = 10 ;
531+ no_change2.max = 30 ;
532+
533+ testCase no_change3;
534+ no_change3.nsyn = 100 ;
535+ no_change3.ncon = 30 ;
536+ no_change3.min = 10 ;
537+ no_change3.max = 30 ;
538+
539+ testCase exact1;
540+ exact1.nsyn = 100 ;
541+ exact1.ncon = 33 ;
542+ exact1.min = 33 ;
543+ exact1.max = 33 ;
544+
545+ testCase exact2;
546+ exact2.nsyn = 100 ;
547+ exact2.ncon = 0 ;
548+ exact2.min = 33 ;
549+ exact2.max = 33 ;
550+
551+ testCase exact3;
552+ exact3.nsyn = 100 ;
553+ exact3.ncon = 88 ;
554+ exact3.min = 33 ;
555+ exact3.max = 33 ;
556+
557+ testCase corner1;
558+ corner1.nsyn = 100 ;
559+ corner1.ncon = 30 ;
560+ corner1.min = 200 ;
561+ corner1.max = 300 ;
562+ corner1.expect_fail = true ;
563+
564+ const Permanence thresh = 0 .5f ;
565+ Connections con (1u , thresh);
566+ Random rnd ( 42u );
567+ CellIdx presyn = 0u ;
568+ for (const testCase &test : {
569+ emptySegment, fullSegment, disconnect1, minimum, maximum, no_change1,
570+ no_change2, no_change3, exact1, exact2, exact3, corner1, })
571+ {
572+ const auto segment = con.createSegment ( 0 );
573+ UInt ncon_done = 0 ;
574+ for (UInt i = test.nsyn ; i > 0 ; --i) {
575+ // Randomly sample which synapses will connected.
576+ if ( rnd.getReal64 () <= Real64 (test.ncon - ncon_done) / i ) {
577+ ncon_done++;
578+ con.createSynapse ( segment, presyn++, rnd.realRange (thresh, 1 .0f ) );
579+ }
580+ else {
581+ con.createSynapse ( segment, presyn++, rnd.realRange (0 .0f , thresh) );
582+ }
583+ }
584+ // Check test setup is good.
585+ const auto &segData = con.dataForSegment ( segment );
586+ ASSERT_EQ ( test.nsyn , segData.synapses .size () );
587+ ASSERT_EQ ( test.ncon , segData.numConnected );
588+
589+ con.synapseCompetition ( segment, test.min , test.max );
590+
591+ // Check synapse data "numConnected" is accurate.
592+ int real_ncon = 0 ;
593+ for ( const auto syn : segData.synapses ) {
594+ const auto &synData = con.dataForSynapse ( syn );
595+ if ( synData.permanence >= thresh - htm::Epsilon ) {
596+ real_ncon++;
597+ }
598+ }
599+ EXPECT_EQ ( segData.numConnected , real_ncon );
600+
601+ // Check results of synapse competition.
602+ if ( not test.expect_fail ) {
603+ EXPECT_GE ( segData.numConnected , test.min );
604+ EXPECT_LE ( segData.numConnected , test.max );
605+ if ( test.ncon >= test.min and test.ncon <= test.max ) {
606+ EXPECT_EQ ( segData.numConnected , test.ncon );
607+ }
608+ }
609+ }
610+ }
611+
483612TEST (ConnectionsTest, testBumpSegment) {
484613 UInt numInputs = 8 ;
485614 UInt numSegments = 5 ;
@@ -737,5 +866,3 @@ TEST(ConnectionsTest, testTimeseries) {
737866 ASSERT_TRUE ( (synData.permanence == 0 .0f ) or (synData.permanence == 1 .0f ) );
738867 }
739868}
740-
741- } // namespace
0 commit comments