public void StableOutputOnSameInputTest()
        {
            var parameters = GetDefaultParams();

            parameters.Set(KEY.POTENTIAL_RADIUS, 64 * 64);
            parameters.Set(KEY.POTENTIAL_PCT, 1.0);
            parameters.Set(KEY.GLOBAL_INHIBITION, false);
            parameters.Set(KEY.STIMULUS_THRESHOLD, 0.5);
            parameters.Set(KEY.INHIBITION_RADIUS, (int)0.25 * 64 * 64);
            parameters.Set(KEY.LOCAL_AREA_DENSITY, -1);
            parameters.Set(KEY.NUM_ACTIVE_COLUMNS_PER_INH_AREA, 0.1 * 64 * 64);
            parameters.Set(KEY.DUTY_CYCLE_PERIOD, 1000000);
            parameters.Set(KEY.MAX_BOOST, 5);

            parameters.setInputDimensions(new int[] { 32, 32 });
            parameters.setColumnDimensions(new int[] { 64, 64 });
            parameters.setNumActiveColumnsPerInhArea(0.02 * 64 * 64);
            var sp  = new SpatialPooler();
            var mem = new Connections();

            //List<int> intList = ArrayUtils.ReadCsvFileTest("TestFiles\\digit1_binary_32bit.txt");
            //intList.Clear();

            //List<int> intList = new List<int>();


            int[] inputVector = new int[1024];

            for (int i = 0; i < 31; i++)
            {
                for (int j = 0; j < 32; j++)
                {
                    if (i > 2 && i < 5 && j > 2 && j < 8)
                    {
                        inputVector[i * 32 + j] = 1;
                    }
                    else
                    {
                        inputVector[i * 32 + j] = 0;
                    }
                }
            }

            parameters.apply(mem);
            sp.Init(mem);

            //int[] activeArray = new int[64 * 64];

            for (int i = 0; i < 10; i++)
            {
                //sp.compute( inputVector, activeArray, true);
                var activeArray = sp.Compute(inputVector, true) as int[];

                //var activeCols = ArrayUtils.IndexWhere(activeArray, (el) => el == 1);

                var str = Helpers.StringifyVector(activeArray);

                Debug.WriteLine(str);
            }
        }
Beispiel #2
0
        public void CollSynapsesToInput()
        {
            var parameters = GetDefaultParams();

            parameters.setInputDimensions(new int[] { 32 });
            parameters.setColumnDimensions(new int[] { 128 });
            parameters.setNumActiveColumnsPerInhArea(0.02 * 128);

            var sp = new SpatialPooler();

            var mem = new Connections();

            parameters.apply(mem);
            sp.Init(mem);

            int[] activeArray = new int[128];

            int[] inputVector = Helpers.GetRandomVector(32, parameters.Get <Random>(KEY.RANDOM));

            for (int i = 0; i < 100; i++)
            {
                sp.compute(inputVector, activeArray, true);

                var activeCols = ArrayUtils.IndexWhere(activeArray, (el) => el == 1);

                var str = Helpers.StringifyVector(activeCols);

                Debug.WriteLine(str);
            }
        }
        public void SPTutorialTest()
        {
            var parameters = GetDefaultParams();

            parameters.setInputDimensions(new int[] { 1000 });
            parameters.setColumnDimensions(new int[] { 2048 });
            parameters.setNumActiveColumnsPerInhArea(0.02 * 2048);
            parameters.setGlobalInhibition(false);

            var sp = new SpatialPooler();

            var mem = new Connections();

            parameters.apply(mem);
            sp.Init(mem);

            int[] activeArray = new int[2048];

            int[] inputVector = Helpers.GetRandomVector(1000, parameters.Get <Random>(KEY.RANDOM));

            sp.compute(inputVector, activeArray, true);

            var activeCols = ArrayUtils.IndexWhere(activeArray, (el) => el == 1);

            var str = Helpers.StringifyVector(activeCols);

            Debug.WriteLine(str);
        }
 private void InitSp()
 {
     sp  = new SpatialPooler();
     mem = new Connections();
     parameters.Apply(mem);
     sp.Init(mem);
 }
Beispiel #5
0
        public HtmModuleNet(Parameters[] parametersList)
        {
            foreach (var prms in parametersList)
            {
                var mem = new Connections();
                prms.apply(mem);

                var colDims = prms.Get <int[]>(KEY.COLUMN_DIMENSIONS);
                int numCols = 1;
                for (int i = 0; i < colDims.Length; i++)
                {
                    numCols *= colDims[i];
                }

                this.m_ActiveArrays.Add(new int[numCols]);

                this.m_Connections.Add(mem);

                SpatialPooler sp = new SpatialPooler();

                sp.Init(mem, null);

                m_Poolers.Add(sp);
            }
        }
Beispiel #6
0
        public HtmModuleNet(Parameters parameters, int[] levels)
        {
            for (int levelIndx = 0; levelIndx < levels.Length; levelIndx++)
            {
                int levelIn;
                int levelOut;

                if (levelIndx == 0)
                {
                    levelIn = levelOut = levels[levelIndx];
                }
                else
                {
                    levelIn  = m_Connections[levelIndx - 1].HtmConfig.ColumnDimensions[0];
                    levelOut = levels[levelIndx];
                }

                parameters.setInputDimensions(new int[] { levelIn, levelIn });
                parameters.setColumnDimensions(new int[] { levelOut, levelOut });
                parameters.Set(KEY.NUM_ACTIVE_COLUMNS_PER_INH_AREA, 0.1 * levelOut * levelOut);

                var mem = new Connections();
                parameters.apply(mem);

                this.m_ActiveArrays.Add(new int[levelOut * levelOut]);

                this.m_Connections.Add(mem);

                SpatialPooler sp = new SpatialPooler();
                sp.Init(mem, null);

                m_Poolers.Add(sp);
            }
        }
        public void StableOutputWithPersistence()
        {
            var parameters = GetDefaultParams();

            parameters.setInputDimensions(new int[] { 32, 32 });
            parameters.setColumnDimensions(new int[] { 64, 64 });
            parameters.setNumActiveColumnsPerInhArea(0.02 * 64 * 64);

            var mem = new Connections();

            parameters.apply(mem);

            var sp = new SpatialPooler();

            sp.Init(mem);


            int[] activeArray = new int[64 * 64];

            int[] inputVector = Helpers.GetRandomVector(32 * 32, parameters.Get <Random>(KEY.RANDOM));

            string str1 = String.Empty;

            for (int i = 0; i < 2; i++)
            {
                sp.compute(inputVector, activeArray, true);

                var activeCols = ArrayUtils.IndexWhere(activeArray, (el) => el == 1);

                str1 = Helpers.StringifyVector(activeCols);

                Debug.WriteLine(str1);
            }

            var settings = new JsonSerializerSettings {
                ContractResolver = new ContractResolver(), Formatting = Formatting.Indented
            };

            var jsonSp = JsonConvert.SerializeObject(sp, settings);

            var sp2 = JsonConvert.DeserializeObject <SpatialPooler>(jsonSp, settings);

            activeArray = new int[activeArray.Length];

            for (int i = 10; i < 20; i++)
            {
                sp2.compute(inputVector, activeArray, true);

                var activeCols = ArrayUtils.IndexWhere(activeArray, (el) => el == 1);

                var str2 = Helpers.StringifyVector(activeCols);

                Debug.WriteLine(str2);

                Assert.IsTrue(str1.SequenceEqual(str2));
            }
        }
        private void RunSpStabilityExperiment_1(int inputBits, Parameters p, EncoderBase encoder, List <double> inputValues)
        {
            string path = nameof(SpatialPooler_Stability_Experiment_1);

            if (Directory.Exists(path))
            {
                Directory.Delete(path, true);
            }

            while (true)
            {
                Directory.CreateDirectory(path);
                if (Directory.Exists(path) == false)
                {
                    Thread.Sleep(300);
                }
                else
                {
                    break;
                }
            }

            Stopwatch sw = new Stopwatch();

            sw.Start();

            bool learn = true;

            CortexNetwork       net     = new CortexNetwork("my cortex");
            List <CortexRegion> regions = new List <CortexRegion>();
            CortexRegion        region0 = new CortexRegion("1st Region");

            regions.Add(region0);

            SpatialPooler sp1 = new SpatialPooler();
            var           mem = new Connections();

            p.apply(mem);
            sp1.Init(mem, UnitTestHelpers.GetMemory());

            CortexLayer <object, object> layer1 = new CortexLayer <object, object>("L1");

            //
            // NewBorn learning stage.
            region0.AddLayer(layer1);
            layer1.HtmModules.Add("encoder", encoder);
            layer1.HtmModules.Add("sp", sp1);

            HtmClassifier <double, ComputeCycle> cls = new HtmClassifier <double, ComputeCycle>();

            double[] inputs         = inputValues.ToArray();
            int[]    prevActiveCols = new int[0];

            int maxSPLearningCycles = 10000;

            List <(double Element, (int Cycle, double Similarity)[] Oscilations)> oscilationResult = new List <(double Element, (int Cycle, double Similarity)[] Oscilations)>();
        public void SPInhibitionTest()
        {
            var parameters = GetDefaultParams();

            parameters.setInputDimensions(new int[] { 10 });
            parameters.setColumnDimensions(new int[] { 1024 });
            parameters.setNumActiveColumnsPerInhArea(0.2 * 32 * 32);
            parameters.setGlobalInhibition(false);

            var sp = new SpatialPooler();

            var mem = new Connections();

            parameters.apply(mem);
            sp.Init(mem);
            //int[] inputVector = NeoCortexUtils.ReadCsvFileTest("Testfiles\\digit8_binary_32bit.txt").ToArray();
            // var inputString = Helpers.StringifyVector(inputVector);
            //Debug.WriteLine("Input Array: " + inputString);
            int[] inputVector = new int[] { 1, 0, 0, 0, 1, 1, 1, 0, 1, 1 };
            int[] activeArray = new int[32 * 32];
            //int iteration = -1;
            String str = "";

            for (int i = 0; i < 10; i++)
            {
                var overlaps    = sp.CalculateOverlap(mem, inputVector);
                var strOverlaps = Helpers.StringifyVector(overlaps);

                var inhibitions    = sp.InhibitColumns(mem, ArrayUtils.ToDoubleArray(overlaps));
                var strInhibitions = Helpers.StringifyVector(inhibitions);

                activeArray = sp.Compute(inputVector, true) as int[];

                //Debug.WriteLine(result);
                //sp.compute( inputVector, activeArray, true);

                var activeCols   = ArrayUtils.IndexWhere(activeArray, (el) => el == 1);
                var strActiveArr = Helpers.StringifyVector(activeArray);
                Debug.WriteLine("Active array: " + strActiveArr);
                var strActiveCols = Helpers.StringifyVector(activeCols);
                Debug.WriteLine("Number of Active Column: " + activeCols.Length);
                str = strActiveCols;
                Debug.WriteLine($"{i} - {strActiveCols}");
            }
            var strOutput = Helpers.StringifyVector(activeArray);

            Debug.WriteLine("Output: " + strOutput);
        }
Beispiel #10
0
        public void TestMaxDims()
        {
            var parameters = SpatialPoolerResearchTests.GetDefaultParams();

            parameters.Set(KEY.POTENTIAL_RADIUS, 64 * 64);
            parameters.Set(KEY.POTENTIAL_PCT, 1.0);
            parameters.Set(KEY.GLOBAL_INHIBITION, false);
            parameters.Set(KEY.STIMULUS_THRESHOLD, 0.5);
            parameters.Set(KEY.INHIBITION_RADIUS, (int)0.25 * 64 * 64);
            parameters.Set(KEY.LOCAL_AREA_DENSITY, -1);
            parameters.Set(KEY.NUM_ACTIVE_COLUMNS_PER_INH_AREA, 0.1 * 64 * 64);
            parameters.Set(KEY.DUTY_CYCLE_PERIOD, 1000000);
            parameters.Set(KEY.MAX_BOOST, 5);

            parameters.setInputDimensions(new int[] { 320, 320 });
            parameters.setColumnDimensions(new int[] { 2048, 2048 });
            parameters.setNumActiveColumnsPerInhArea(0.02 * 64 * 64);
            var sp  = new SpatialPooler();
            var mem = new Connections();

            //List<int> intList = ArrayUtils.ReadCsvFileTest("TestFiles\\digit1_binary_32bit.txt");
            //intList.Clear();

            //List<int> intList = new List<int>();


            int[] inputVector = new int[1024];

            for (int i = 0; i < 31; i++)
            {
                for (int j = 0; j < 32; j++)
                {
                    if (i > 2 && i < 5 && j > 2 && j < 8)
                    {
                        inputVector[i * 32 + j] = 1;
                    }
                    else
                    {
                        inputVector[i * 32 + j] = 0;
                    }
                }
            }

            parameters.apply(mem);
            sp.Init(mem, null);
        }
        public void NeighborhoodTest()
        {
            var parameters = GetDefaultParams();

            int cellsDim1 = 64;
            int cellsDim2 = 64;

            parameters.setInputDimensions(new int[] { 32 });
            parameters.setColumnDimensions(new int[] { cellsDim1 });

            var sp = new SpatialPooler();

            var mem = new Connections();

            parameters.apply(mem);
            sp.Init(mem);

            for (int rad = 1; rad < 10; rad++)
            {
                using (StreamWriter sw = new StreamWriter($"neighborhood-test-rad{rad}-center-from-{cellsDim1}-to-{0}.csv"))
                {
                    sw.WriteLine($"{cellsDim1}|{cellsDim2}|{rad}|First column defines center of neiborhood. All other columns define indicies of neiborhood columns");

                    for (int center = 0; center < 64; center++)
                    {
                        var nbs = HtmCompute.GetNeighborhood(center, rad, mem.HtmConfig.ColumnTopology.HtmTopology);

                        StringBuilder sb = new StringBuilder();

                        sb.Append(center);
                        sb.Append('|');

                        foreach (var neighobordCellIndex in nbs)
                        {
                            sb.Append(neighobordCellIndex);
                            sb.Append('|');
                        }

                        string str = sb.ToString();

                        sw.WriteLine(str.TrimEnd('|'));
                    }
                }
            }
        }
Beispiel #12
0
        /// <summary>
        ///
        /// </summary>
        private void RunSpStabilityExperiment(int inputBits, Parameters p, EncoderBase encoder, List <double> inputValues)
        {
            Stopwatch sw = new Stopwatch();

            sw.Start();

            bool learn = true;

            CortexNetwork       net     = new CortexNetwork("my cortex");
            List <CortexRegion> regions = new List <CortexRegion>();
            CortexRegion        region0 = new CortexRegion("1st Region");

            regions.Add(region0);

            SpatialPooler sp1 = new SpatialPooler();
            var           mem = new Connections();

            p.apply(mem);
            sp1.Init(mem, UnitTestHelpers.GetMemory());

            CortexLayer <object, object> layer1 = new CortexLayer <object, object>("L1");

            //
            // NewBorn learning stage.
            region0.AddLayer(layer1);
            layer1.HtmModules.Add("encoder", encoder);
            layer1.HtmModules.Add("sp", sp1);

            HtmClassifier <double, ComputeCycle> cls = new HtmClassifier <double, ComputeCycle>();

            double[] inputs         = inputValues.ToArray();
            int[]    prevActiveCols = new int[0];

            int maxSPLearningCycles = 25000;


            List <(double Element, (int Cycle, double Similarity)[] Oscilations)> oscilationResult = new List <(double Element, (int Cycle, double Similarity)[] Oscilations)>();
        public void ExperimentTest(string inputBinarizedFile)
        {
            var parameters = SetupParameters(32, 64, 4096, true);

            parameters.Set(KEY.DUTY_CYCLE_PERIOD, 100000);
            parameters.Set(KEY.MAX_BOOST, 1.0);
            parameters.Set(KEY.IS_BUMPUP_WEAKCOLUMNS_DISABLED, true);

            var sp  = new SpatialPooler();
            var mem = new Connections();

            int[] inputVector = NeoCortexUtils.ReadCsvFileTest(inputBinarizedFile).ToArray();
            int[] activeArray = new int[4096];
            parameters.apply(mem);
            sp.Init(mem);

            for (int i = 0; i < 1000; i++)
            {
                sp.compute(inputVector, activeArray, true);
                var activeCols = activeArray.IndexWhere((el) => el == 1);
                var str        = Helpers.StringifyVector(activeCols);
                Debug.WriteLine(str);
            }
        }
        public void SerializationTestWithTrainedData()
        {
            // TODO: see SpatialPooler_Stability_Experiment_3()
            // use it here.

            var parameters = GetDefaultParams();

            parameters.setInputDimensions(new int[] { 16 * 16 });
            parameters.setColumnDimensions(new int[] { 32 * 32 });
            parameters.setNumActiveColumnsPerInhArea(0.02 * 32 * 32);
            parameters.setMinPctOverlapDutyCycles(0.01);

            var mem = new Connections();

            parameters.apply(mem);

            var sp1 = new SpatialPooler();

            sp1.Init(mem);


            int[] output = new int[32 * 32];

            int[] inputVector = Helpers.GetRandomVector(16 * 16, parameters.Get <Random>(KEY.RANDOM));

            /*  int [] inputVector =  {
             *                               1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
             *                               0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
             *                               1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
             *                               0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,
             *                               1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
             *                               1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
             *                               0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
             *                               1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
             *                               0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,
             *                               1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
             *                               0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,
             *                               1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
             *                               1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
             *                               0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
             *                               0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
             *                               1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0 };
             *
             */
            string str1 = String.Empty;

            for (int i = 0; i < 5; i++)
            {
                sp1.compute(inputVector, output, true);

                var activeCols1 = ArrayUtils.IndexWhere(output, (el) => el == 1);

                // Remember SDR for every input.
                // if(i >= 4)
                // sdrs.Add(output)

                str1 = Helpers.StringifyVector(activeCols1);

                Debug.WriteLine(str1);
            }


            // if stable
            //  HtmSerializer ser = new HtmSerializer();
            // ser.Serialize(sp, "sp.json");

            //  var sp2 = HtmSerializer.Load("sp.json");
            // Implement a code to compare sdrs of sp2 that have been learned with sp1.


            string ser1 = File.ReadAllText("spTrain1.json");

            //var sp2 = SpatialPooler.Deserializer("spTrain1.json");

            //sp2.Serializer("spTrainDes1.json");

            //string des1 = File.ReadAllText("spTrainDes1.json");

            //Assert.IsTrue(ser1.SequenceEqual(des1));

            //for (int i = 5; i < 10; i++)
            //{
            //    sp1.compute(inputVector, sdrArray, false);

            //    var sdr2 = ArrayUtils.IndexWhere(sdrArray, (el) => el == 1);

            //    // Compare sdr with sdr1 of the same input
            //    var str2 = Helpers.StringifyVector(sdr2);

            //    Debug.WriteLine(str2);
            //    Assert.IsTrue(str1.SequenceEqual(str2));

            //}
        }
        private void RunSerializationExperiment(double maxBoost, double minOverlapCycles, int inputBits, Parameters p, EncoderBase encoder, List <double> inputValues)
        {
            string path = nameof(RunSerializationExperiment);

            if (Directory.Exists(path))
            {
                Directory.Delete(path, true);
            }

            Directory.CreateDirectory(path);

            Stopwatch sw = new Stopwatch();

            sw.Start();

            bool learn = true;

            CortexNetwork       net     = new CortexNetwork("my cortex");
            List <CortexRegion> regions = new List <CortexRegion>();
            CortexRegion        region0 = new CortexRegion("1st Region");

            regions.Add(region0);

            var mem = new Connections();

            bool isInStableState = false;

            HomeostaticPlasticityController hpa = new HomeostaticPlasticityController(mem, inputValues.Count * 15, (isStable, numPatterns, actColAvg, seenInputs) =>
            {
                Assert.IsTrue(numPatterns == inputValues.Count);

                // Event should only be fired when entering the stable state.
                // Ideal SP should never enter unstable state after stable state.
                if (isStable == false)
                {
                    isInStableState = false;
                    Debug.WriteLine($"UNSTABLE!: Patterns: {numPatterns}, Inputs: {seenInputs}, iteration: {seenInputs / numPatterns}");
                }
                else
                {
                    //Assert.IsTrue(isStable);

                    isInStableState = true;
                    Debug.WriteLine($"STABLE: Patterns: {numPatterns}, Inputs: {seenInputs}, iteration: {seenInputs / numPatterns}");
                }
            });

            SpatialPooler sp1 = new SpatialPooler(hpa);

            p.apply(mem);
            sp1.Init(mem, UnitTestHelpers.GetMemory());

            CortexLayer <object, object> layer1 = new CortexLayer <object, object>("L1");

            region0.AddLayer(layer1);
            layer1.HtmModules.Add("encoder", encoder);
            layer1.HtmModules.Add("sp", sp1);

            HtmClassifier <double, ComputeCycle> cls = new HtmClassifier <double, ComputeCycle>();

            double[] inputs = inputValues.ToArray();
            Dictionary <double, int[]>  prevActiveCols = new Dictionary <double, int[]>();
            Dictionary <double, double> prevSimilarity = new Dictionary <double, double>();

            foreach (var input in inputs)
            {
                prevSimilarity.Add(input, 0.0);
                prevActiveCols.Add(input, new int[0]);
            }

            int maxSPLearningCycles = 5000;

            List <(double Element, (int Cycle, double Similarity)[] Oscilations)> oscilationResult = new List <(double Element, (int Cycle, double Similarity)[] Oscilations)>();
        // [DataRow("MnistTestImages\\digit7.png", 128, 30)]
        public void LearningimageDoubleShiftStble(string mnistImage, string shiftedImage, int[] imageSize, int[] topologies)
        {
            var path        = Path.Combine(Directory.GetParent(Environment.CurrentDirectory).Parent.Parent.FullName, mnistImage);
            var pathShifted = Path.Combine(Directory.GetParent(Environment.CurrentDirectory).Parent.Parent.FullName, shiftedImage);

            Console.WriteLine("Test started");
            Console.WriteLine(mnistImage);
            Console.WriteLine(shiftedImage);
            const int OutImgSize = 1024;

            int    index1 = mnistImage.IndexOf("\\") + 1;
            int    index2 = mnistImage.IndexOf(".");
            string sub1   = mnistImage.Substring(0, index2);
            string sub2   = mnistImage.Substring(0, index1);
            string name   = mnistImage.Substring(index1, sub1.Length - sub2.Length);

            int    index1Shift = shiftedImage.IndexOf("\\") + 1;
            int    index2Shift = shiftedImage.IndexOf(".");
            string sub1Shift   = shiftedImage.Substring(0, index2Shift);
            string sub2Shift   = shiftedImage.Substring(0, index1Shift);
            string nameShift   = shiftedImage.Substring(index1Shift, sub1Shift.Length - sub2Shift.Length);

            for (int imSizeIndx = 0; imSizeIndx < imageSize.Length; imSizeIndx++)
            {
                Console.WriteLine(String.Format("Image Size: \t{0}", imageSize[imSizeIndx]));

                string testName        = $"{name}_{imageSize[imSizeIndx]}";
                string outputSpeedFile = $"Output\\{testName}_speed.txt";

                string testNameShifted        = $"{nameShift}_{imageSize[imSizeIndx]}";
                string outputSpeedFileShifted = $"Output\\{testNameShifted}_speed.txt";

                string inputBinaryImageFile        = BinarizeImage(path, imageSize[imSizeIndx], testName);
                string inputBinaryImageShiftedFile = BinarizeImage(pathShifted, imageSize[imSizeIndx], testNameShifted);

                //string inputBinaryImageFile = BinarizeImage("Output\\" + mnistImage, imageSize[imSizeIndx], testName);
                for (int topologyIndx = 0; topologyIndx < topologies.Length; topologyIndx++)
                {
                    Console.WriteLine(String.Format("Topology: \t{0}", topologies[topologyIndx]));

                    string finalName         = $"{testName}_{topologies[topologyIndx]}";
                    string outputHamDistFile = $"Output\\{finalName}_hamming.txt";
                    string outputActColFile  = $"Output\\{finalName}_activeCol.txt";

                    string outputImage = $"Output\\{finalName}.png";

                    string finalNameShifted         = $"{testNameShifted}_{topologies[topologyIndx]}";
                    string outputHamDistFileShifted = $"Output\\{finalNameShifted}_hamming.txt";
                    string outputActColFileShifted  = $"Output\\{finalNameShifted}_activeCol.txt";

                    string outputImageShifted = $"Output\\{finalNameShifted}.png";


                    //File.Create(finalName);
                    //Directory.CreateDirectory("Output");
                    //File.Create(outputHamDistFile);
                    //File.Create(outputActColFile);

                    int numOfActCols = 0;
                    var sw           = new Stopwatch();
                    using (StreamWriter swHam = new StreamWriter(outputHamDistFile))
                    {
                        using (StreamWriter swSpeed = new StreamWriter(outputSpeedFile, true))
                        {
                            using (StreamWriter swActCol = new StreamWriter(outputActColFile))
                            {
                                numOfActCols = topologies[topologyIndx] * topologies[topologyIndx];
                                var parameters = GetDefaultParams();
                                parameters.setInputDimensions(new int[] { imageSize[imSizeIndx], imageSize[imSizeIndx] });
                                parameters.setColumnDimensions(new int[] { topologies[topologyIndx], topologies[topologyIndx] });
                                parameters.setNumActiveColumnsPerInhArea(0.02 * numOfActCols);

                                var sp  = new SpatialPooler();
                                var mem = new Connections();

                                parameters.apply(mem);
                                sw.Start();

                                sp.Init(mem);

                                sw.Stop();
                                swSpeed.WriteLine($"{topologies[topologyIndx]}|{(double)sw.ElapsedMilliseconds / (double)1000}");

                                int   actiColLen  = numOfActCols;
                                int[] activeArray = new int[actiColLen];

                                //Read input csv file into array
                                int[] inputVector = NeoCortexUtils.ReadCsvIntegers(inputBinaryImageFile).ToArray();

                                var inputOverlap  = new List <double>();
                                var outputOverlap = new List <double>();

                                int[]      newActiveArray       = new int[topologies[topologyIndx] * topologies[topologyIndx]];
                                double[][] newActiveArrayDouble = new double[1][];
                                newActiveArrayDouble[0] = new double[newActiveArray.Length];

                                //Training
                                sp.compute(inputVector, activeArray, true);

                                var activeCols = ArrayUtils.IndexWhere(activeArray, (el) => el == 1);

                                double[][] oldActiveArray = new double[1][];
                                oldActiveArray[0] = new double[activeArray.Length];
                                for (int a = 0; a < activeArray.Length; a++)
                                {
                                    oldActiveArray[0][a] = activeArray[a];
                                }

                                int isTrained = 0;

                                while (isTrained == 0)
                                {
                                    sp.compute(inputVector, newActiveArray, true);

                                    activeCols = ArrayUtils.IndexWhere(newActiveArray, (el) => el == 1);



                                    for (int a = 0; a < newActiveArray.Length; a++)
                                    {
                                        newActiveArrayDouble[0][a] = newActiveArray[a];
                                    }

                                    if (MathHelpers.GetHammingDistance(oldActiveArray, newActiveArrayDouble, true)[0] == 100)
                                    {
                                        isTrained = 1;
                                    }
                                    else
                                    {
                                        isTrained      = 0;
                                        oldActiveArray = newActiveArrayDouble;
                                    }
                                }

                                var str = Helpers.StringifyVector(activeCols);


                                int[] oldInputVector = NeoCortexUtils.ReadCsvIntegers(inputBinaryImageFile).ToArray();

                                int[] inputVectorShifted = NeoCortexUtils.ReadCsvIntegers(inputBinaryImageShiftedFile).ToArray();

                                int[]      activeArrayShifted       = new int[topologies[topologyIndx] * topologies[topologyIndx]];
                                double[][] activeArrayShiftedDouble = new double[1][];
                                activeArrayShiftedDouble[0] = new double[activeArrayShifted.Length];

                                sw.Restart();

                                //Prediction
                                sp.compute(inputVectorShifted, activeArrayShifted, false);

                                var resActiveColsPercent = ArrayUtils.IndexWhere(activeArrayShifted, (el) => el == 1);

                                var resStrPercent = Helpers.StringifyVector(activeArrayShifted);


                                for (int a = 0; a < activeArrayShifted.Length; a++)
                                {
                                    activeArrayShiftedDouble[0][a] = activeArrayShifted[a];
                                }



                                var distance    = MathHelpers.GetHammingDistance(newActiveArrayDouble, activeArrayShiftedDouble, false)[0];
                                var distPercent = ((100 - distance) * 100) / (topologies[topologyIndx] * topologies[topologyIndx]);
                                swHam.WriteLine(distance + "\t" + (100 - distance) + "\t" + distPercent + "\t" + (1 - (distPercent / 100.0)) + "\n");

                                outputOverlap.Add(1 - (distPercent / 100.0));

                                swActCol.WriteLine(String.Format(@"Active Cols: {0}", Helpers.StringifyVector(resActiveColsPercent)));

                                Console.WriteLine(resStrPercent);
                                swActCol.WriteLine("Active Array: " + resStrPercent);

                                sw.Stop();

                                int[,] twoDimenArray = ArrayUtils.Make2DArray <int>(activeArrayShifted, topologies[topologyIndx], topologies[topologyIndx]);
                                twoDimenArray        = ArrayUtils.Transpose(twoDimenArray);

                                NeoCortexUtils.DrawBitmap(twoDimenArray, OutImgSize, OutImgSize, outputImage);
                                //NeoCortexUtils.DrawBitmap(twoDimenArray, OutImgSize, OutImgSize, "D:\\Project_Latest\\FromGit\\se-dystsys-2018-2019-softwareengineering\\outputs\\eight");


                                swActCol.WriteLine("inputOverlaps: " + Helpers.StringifyVector(inputOverlap.ToArray()));

                                swActCol.WriteLine("outputOverlaps: " + Helpers.StringifyVector(outputOverlap.ToArray()));
                            }
                        }
                    }
                }
            }
        }
        private void RunExperiment(int inputBits, HtmConfig cfgL4, EncoderBase encoder, List <double> inputValues, HtmConfig cfgL2)
        {
            Stopwatch swL2 = new Stopwatch();

            int  maxMatchCnt = 0;
            bool learn       = true;
            bool isSP4Stable = false;
            bool isSP2STable = false;

            Connections memL4 = new Connections(cfgL4);
            Connections memL2 = new Connections(cfgL2);

            int numInputs = inputValues.Distinct <double>().ToList().Count;
            HtmClassifier <string, ComputeCycle> cls = new HtmClassifier <string, ComputeCycle>();

            layerL4 = new CortexLayer <object, object>("L4");
            layerL2 = new CortexLayer <object, object>("L2");
            //tm4 = new TemporalMemoryMT();
            //tm2 = new TemporalMemoryMT();
            tm4 = new TemporalMemory();
            tm2 = new TemporalMemory();

            //
            // HPC for Layer 4 SP
            HomeostaticPlasticityController hpa_sp_L4 = new HomeostaticPlasticityController(memL4, numInputs * 50, (isStable, numPatterns, actColAvg, seenInputs) =>
            {
                if (isStable)
                {
                    Debug.WriteLine($"SP L4 STABLE: Patterns: {numPatterns}, Inputs: {seenInputs}, iteration: {seenInputs / numPatterns}");
                }
                else
                {
                    Debug.WriteLine($"SP L4 INSTABLE: Patterns: {numPatterns}, Inputs: {seenInputs}, iteration: {seenInputs / numPatterns}");
                }
                learn = isSP4Stable = isStable;
                cls.ClearState();
            }, numOfCyclesToWaitOnChange: 50);


            //
            // HPC for Layer 2 SP
            HomeostaticPlasticityController hpa_sp_L2 = new HomeostaticPlasticityController(memL2, numInputs * 50, (isStable, numPatterns, actColAvg, seenInputs) =>
            {
                if (isStable)
                {
                    Debug.WriteLine($"SP L2 STABLE: Patterns: {numPatterns}, Inputs: {seenInputs}, iteration: {seenInputs / numPatterns}");
                }
                else
                {
                    Debug.WriteLine($"SP L2 INSTABLE: Patterns: {numPatterns}, Inputs: {seenInputs}, iteration: {seenInputs / numPatterns}");
                }

                learn = isSP2STable = isStable;
                cls.ClearState();
            }, numOfCyclesToWaitOnChange: 50);

            SpatialPooler sp4 = new SpatialPooler(hpa_sp_L4);

            SpatialPooler sp2 = new SpatialPooler(hpa_sp_L2);

            sp4.Init(memL4);
            sp2.Init(memL2);

            // memL2.TraceInputPotential();

            tm4.Init(memL4);
            tm2.Init(memL2);

            layerL4.HtmModules.Add("encoder", encoder);
            layerL4.HtmModules.Add("sp", sp4);
            layerL4.HtmModules.Add("tm", tm4);

            layerL2.HtmModules.Add("sp", sp2);
            layerL2.HtmModules.Add("tm", tm2);

            int[] inpCellsL4ToL2 = new int[cfgL4.CellsPerColumn * cfgL4.NumColumns];

            double[]      inputs             = inputValues.ToArray();
            int[]         prevActiveCols     = new int[0];
            int           cycle              = 0;
            int           matches            = 0;
            string        lastPredictedValue = "0";
            int           maxCycles          = 3500;
            int           maxPrevInputs      = inputValues.Count - 1;
            List <string> previousInputs     = new List <string>();


            //
            // Training SP at Layer 4 to get stable. New-born stage.
            //
            using (StreamWriter swL4Sdrs = new StreamWriter($"L4-SDRs-in_{cfgL2.NumInputs}-col_{cfgL2.NumColumns}-r_{cfgL2.PotentialRadius}.txt"))
            {
                using (StreamWriter sw = new StreamWriter($"in_{cfgL2.NumInputs}-col_{cfgL2.NumColumns}-r_{cfgL2.PotentialRadius}.txt"))
                {
                    for (int i = 0; i < maxCycles; i++)
                    {
                        matches = 0;
                        cycle   = i;
                        Debug.WriteLine($"-------------- Newborn Cycle {cycle} at L4 SP region  ---------------");

                        foreach (double input in inputs)
                        {
                            Debug.WriteLine($" INPUT: '{input}'\t Cycle:{cycle}");
                            Debug.Write("L4: ");
                            object lyrOut           = layerL4.Compute(input, learn);
                            int[]  activeColumns    = layerL4.GetResult("sp") as int[];
                            int[]  cellSdrL4Indexes = memL4.ActiveCells.Select(c => c.Index).ToArray();
                            Debug.WriteLine($"L4out Active Coloumn for input: {input}: {Helpers.StringifyVector(activeColumns)}");
                            Debug.WriteLine($"L4out SDR for input: {input}: {Helpers.StringifyVector(cellSdrL4Indexes)}");


                            if (isSP4Stable)
                            {
                                /// <summary>
                                /// Checking Layer4 SP is giving similar or different
                                /// Active Cell Sdr Indexes After it reaches to stable state.
                                /// This portion is actuallly to hold all acive cell sdr
                                /// indexes after Layer 4 SP reaches at stable state via HPC.
                                ///
                                /// But why we have done this?
                                ///
                                /// Actually, In Necortex api we have obeserved during severel
                                /// experiments that whenvever Layer4 SP reaches to STABLE sate
                                /// it doesnt give us smilar pattern of Active Cell SDR Indexes
                                /// for each particular input data.
                                ///
                                /// Instead active cell sdr patern of L4 varried  though it has reached
                                /// to stable sate!
                                ///
                                /// So we want to obeserve whether Layer 4 SP is giving similar active cell sdr indexes
                                /// or different acrive cell sdr indexes after it reaches to stable state.
                                ///
                                /// If we receive similar acrive cell sdr indexes from Layer 4 sp after it reaches
                                /// to stable state then do train Layer 2 sp by as usual process in NeocortexApi by
                                /// calling Layer4.Compute().
                                ///
                                /// But if we receive different active cell sdr indexes then we will train Layer 2 sp
                                /// from L4_ActiveCell_sdr_log so that during training
                                /// Layer 2 SP gets similar stable active cell sdr indexes of layer4
                                /// from that dictionary. As a result, L2 SP will get similar sequence
                                /// of active cell sdr indexes during SP Tarining and reach to STABLE state
                                /// </summary>

                                Array.Sort(cellSdrL4Indexes);
                                if (!L4_ActiveCell_sdr_log.ContainsKey(input))
                                {
                                    L4_ActiveCell_sdr_log.Add(input, cellSdrL4Indexes);
                                }
                                else
                                {
                                    if (L4_ActiveCell_sdr_log[input].SequenceEqual(cellSdrL4Indexes))
                                    {
                                        Debug.WriteLine($"Layer4.Compute() is giving similar cell sdr indexes for input : {input} after reaching to stable state");
                                        isSimilar_L4_active_cell_sdr = true;
                                    }
                                    else
                                    {
                                        isSimilar_L4_active_cell_sdr = false;
                                        Debug.WriteLine($"Layer4.Compute() is giving different cell sdr indexes for input : {input} after reaching to stable state");
                                        Debug.WriteLine($"Sdr Mismatch with L4_ActiveCell_sdr_log after reaching to stable state");
                                        Debug.WriteLine($" L4_ActiveCell_sdr_log output for input {input}: { Helpers.StringifyVector(L4_ActiveCell_sdr_log[input])}");
                                        Debug.WriteLine($"L4 out sdr input:{input} {Helpers.StringifyVector(cellSdrL4Indexes)}");
                                        //Debug.WriteLine($"L4 out ac input: {input}: {Helpers.StringifyVector(activeColumns)}");
                                    }
                                }


                                if (!isSimilar_L4_active_cell_sdr)
                                {
                                    cellSdrL4Indexes = L4_ActiveCell_sdr_log[input];
                                }


                                //
                                // Training SP at Layer 2 to get stable. New-born stage.
                                //

                                // Write SDR as output of L4 and input of L2
                                // swL4Sdrs.WriteLine($"{input} - {Helpers.StringifyVector(cellSdrL4Indexes)}");
                                // Set the output active cell array

                                InitArray(inpCellsL4ToL2, 0);
                                ArrayUtils.SetIndexesTo(inpCellsL4ToL2, cellSdrL4Indexes, 1);
                                Debug.WriteLine($"L4 cell sdr to L2 SP Train for Input {input}: ");
                                layerL2.Compute(inpCellsL4ToL2, true);
                                int[]  overlaps    = ArrayUtils.IndexWhere(memL2.Overlaps, o => o > 0);
                                string strOverlaps = Helpers.StringifyVector(overlaps);
                                Debug.WriteLine($"Potential columns: {overlaps.Length}, overlaps: {strOverlaps}");
                            }
                        }


                        if (isSP4Stable && isSP2STable)
                        {
                            break;
                        }
                    }
                }
            }


            //
            // SP+TM at L2
            for (int i = 0; i < maxCycles; i++)
            {
                matches = 0;

                cycle = i;

                Debug.WriteLine($"-------------- L2 TM Train region Cycle {cycle} ---------------");

                foreach (double input in inputs)
                {
                    Debug.WriteLine($"-------------- {input} ---------------");

                    // Reset tha array

                    //var cellSdrL4Indexes = L4_ActiveCell_sdr_log[input];
                    object layerL4Out = layerL4.Compute(input, learn);
                    previousInputs.Add(input.ToString());

                    if (previousInputs.Count > (maxPrevInputs + 1))
                    {
                        previousInputs.RemoveAt(0);
                    }
                    if (previousInputs.Count < maxPrevInputs)
                    {
                        continue;
                    }

                    key = GetKey(previousInputs, input);

                    List <Cell> actCells;
                    InitArray(inpCellsL4ToL2, 0);
                    int[] cellSdrL4Indexes;

                    if (!isSimilar_L4_active_cell_sdr)
                    {
                        cellSdrL4Indexes = L4_ActiveCell_sdr_log[input];
                    }
                    else
                    {
                        cellSdrL4Indexes = memL4.ActiveCells.Select(c => c.Index).ToArray();
                    }


                    // Set the output active cell array
                    ArrayUtils.SetIndexesTo(inpCellsL4ToL2, cellSdrL4Indexes, 1);

                    ComputeCycle layerL2Out = layerL2.Compute(inpCellsL4ToL2, true) as ComputeCycle;


                    if (layerL2Out.ActiveCells.Count == layerL2Out.WinnerCells.Count)
                    {
                        actCells = layerL2Out.ActiveCells;
                    }
                    else
                    {
                        actCells = layerL2Out.WinnerCells;
                    }

                    /// <summary>
                    /// HTM Classifier has added for Layer 2
                    /// </summary>

                    cls.Learn(key, actCells.ToArray());

                    if (key == lastPredictedValue)
                    {
                        matches++;
                        Debug.WriteLine($"Match. Actual  Sequence: {key} - Last Predicted Sequence: {lastPredictedValue}");
                    }
                    else
                    {
                        Debug.WriteLine($"Missmatch! Actual Sequence: {key} - Last Predicted Sequence: {lastPredictedValue}");
                    }


                    /// <summary>
                    /// Classifier is taking Predictive Cells from Layer 2
                    /// </summary>

                    if (layerL2Out.PredictiveCells.Count > 0)
                    {
                        string predictedInputValue = cls.GetPredictedInputValue(layerL2Out.PredictiveCells.ToArray());

                        Debug.WriteLine($"Current Input: {input} \t| New Predicted Input Sequence: {predictedInputValue}");

                        lastPredictedValue = predictedInputValue;
                    }
                    else
                    {
                        Debug.WriteLine($"NO CELLS PREDICTED for next cycle.");
                        lastPredictedValue = String.Empty;
                    }
                }

                double accuracy = (double)matches / (double)inputs.Length * 100.0;

                Debug.WriteLine($"Cycle: {cycle}\tMatches={matches} of {inputs.Length}\t {accuracy}%");

                if (accuracy >= 100.0)
                {
                    maxMatchCnt++;
                    Debug.WriteLine($"100% accuracy reched {maxMatchCnt} times.");
                    //
                    // Experiment is completed if we are 20 cycles long at the 100% accuracy.
                    if (maxMatchCnt >= 20)
                    {
                        Debug.WriteLine($"Exit experiment in the stable state after 20 repeats with 100% of accuracy.");
                        learn = false;
                        break;
                    }
                }
                else if (maxMatchCnt > 0)
                {
                    Debug.WriteLine($"At 100% accuracy after {maxMatchCnt} repeats we get a drop of accuracy with {accuracy}. This indicates instable state. Learning will be continued.");
                }
            }
        }
        /// <summary>
        /// This function train the input image and write result to text files in folder @"/Output"
        /// The result text files include speed comparison between global inhibition and local inhibition,
        /// the stable of the out put array (by comparing hamming distance arrays).
        /// Finally this method draw an image of active column as .png file.
        /// </summary>
        /// <param name="imageSize">Size of the image (image has same width and height)</param>
        /// <param name="columnDimension">List of sparse space size.(with same width and height)</param>
        /// <param name="inputBinarizedFile">input image after binarized</param>
        /// <param name="hammingFile">Path to hamming distance output file </param>
        /// <param name="outputSpeedFile">Path to speed comparison output file</param>
        /// <param name="activeColumnFile">Path to active column after training output file (as array text)</param>
        /// <param name="outputImage">Path to active column after training output file (as .png image file)</param>
        /// <param name="isGlobalInhibition">is using Global inhibition algorithms or not (if false using local inhibition)</param>
        private static void Training(int imageSize, int columnDimension, string inputBinarizedFile, string hammingFile, string outputSpeedFile, string activeColumnFile, string outputImage, bool isGlobalInhibition)
        {
            int outputImageSize = 1024;
            int activeColumn    = columnDimension * columnDimension;
            var stopwatch       = new Stopwatch();

            using (StreamWriter swHamming = new StreamWriter(hammingFile))
            {
                using (StreamWriter swSpeed = new StreamWriter(outputSpeedFile, true))
                {
                    using (StreamWriter swActiveColumn = new StreamWriter(activeColumnFile))
                    {
                        var parameters = SetupParameters(imageSize, columnDimension, isGlobalInhibition);
                        var sp         = new SpatialPooler();
                        var mem        = new Connections();

                        parameters.apply(mem);

                        stopwatch.Start();
                        sp.Init(mem);
                        stopwatch.Stop();

                        int   actiColumnLength = activeColumn;
                        int[] activeArray      = new int[actiColumnLength];

                        // Read input csv file into array
                        int[] inputVector = NeoCortexUtils.ReadCsvFileTest(inputBinarizedFile).ToArray();

                        stopwatch.Restart();

                        int   iterations = 300;
                        int[] oldArray   = new int[activeArray.Length];

                        for (int k = 0; k < iterations; k++)
                        {
                            sp.compute(inputVector, activeArray, true);

                            var activeCols = activeArray.IndexWhere((el) => el == 1);
                            var distance   = MathHelpers.GetHammingDistance(oldArray, activeArray);
                            var similarity = MathHelpers.CalcArraySimilarity(oldArray, activeArray);
                            swHamming.WriteLine($"{distance} | {similarity}");
                            var str = Helpers.StringifyVector(activeCols);
                            Debug.WriteLine(str);
                            oldArray = new int[actiColumnLength];
                            activeArray.CopyTo(oldArray, 0);
                        }

                        stopwatch.Stop();
                        var activeArrayString = Helpers.StringifyVector(activeArray);
                        swActiveColumn.WriteLine("Active Array: " + activeArrayString);

                        string inhibition   = isGlobalInhibition ? "Global" : "Local";
                        double milliseconds = stopwatch.ElapsedMilliseconds;
                        double seconds      = milliseconds / 1000;
                        swSpeed.WriteLine($"Topology: {columnDimension.ToString().PadRight(5)} | Inhibition type: {inhibition.PadRight(7)} | Total time: {milliseconds:N0} milliseconds ({seconds:N2} seconds).");

                        int[,] twoDimenArray = ArrayUtils.Make2DArray(activeArray, columnDimension, columnDimension);
                        twoDimenArray        = ArrayUtils.Transpose(twoDimenArray);

                        NeoCortexUtils.DrawBitmap(twoDimenArray, outputImageSize, outputImageSize, outputImage);
                    }
                }
            }
        }
        public void SchemaImageClassificationTest()
        {
            var imagesFolder = "..\\..\\..\\TestFiles\\SchemaImageClassification\\image";
            var csvPath      = "..\\..\\..\\TestFiles\\SchemaImageClassification\\csv";

            string[] files = Directory.GetFiles(imagesFolder, "*", SearchOption.AllDirectories);

            string path, name;

            (path, name) = GetPathAndName(files[0]);

            int activeColumn   = 60;
            int inputDimension = 32;

            string[] imageNames = new string[files.Length];

            SpatialPooler sp     = new SpatialPooler();
            Connections   mem    = new Connections();
            Parameters    config = GetParam(inputDimension, activeColumn);

            config.apply(mem);
            sp.Init(mem);

            List <int[]> activeArray = new List <int[]>();// to store n active sequences for n images

            // For each image in this directory
            for (int i = 0; i < files.Length; i++)
            {
                // TODO: activeArray: is a buffer to store active column sequence from spatial pooler
                activeArray.Add(new int[activeColumn * activeColumn]);
                (path, name)  = GetPathAndName(files[i]);
                imageNames[i] = name;

                string binaryImagePath = BinarizeImage(path, inputDimension, inputDimension, csvPath, name);

                int[] inputVector = ReadCsvFileTest(binaryImagePath).ToArray(); // 1D binary of a image

                List <int[]> tempArr = new List <int[]>();
                tempArr.Add(new int[activeColumn * activeColumn]);
                tempArr.Add(new int[activeColumn * activeColumn]);
                int iter = -1;
                int id   = 0;

                while (true) // Train spatial pooler with a single image until stable active column sequence is achieve
                {
                    id = (++iter & 1) == 0 ? 0 : 1;
                    for (int i_x = 0; i_x < tempArr[id].Length; i_x++)
                    {
                        tempArr[id][i_x] = 0;
                    }


                    sp.compute(inputVector, tempArr[id], true);
                    if (iter == 1)
                    {
                        continue;
                    }

                    var d = GetHammingDistance(tempArr[id], tempArr[id ^ 1], false);
                    if (d != double.NegativeInfinity)
                    {
                        Console.WriteLine(d);
                    }

                    /*Note: GetHamming distance will return  a distance between 0 and 100.
                     * if two sequences are the same the return value will be 100. Therefore, the similarity is (100==distance).
                     * To give a four digit precision, < is used instead of ==.
                     */
                    if ((100.0 - d) < 0.00001)
                    {
                        for (int i_x = 0; i_x < tempArr[id].Length; i_x++)
                        {
                            activeArray[i][i_x] = tempArr[id][i_x];
                        }

                        break;
                    }
                }

                Console.WriteLine("finished image : " + i);
            }

            int[]           parent    = new int[files.Length];
            bool[]          hasFolder = new bool[files.Length];
            List <double[]> distance  = new List <double[]>();

            for (int k = 0; k < files.Length; k++)
            {
                distance.Add(new double[files.Length]);
                for (int kk = 0; kk < files.Length; kk++)
                {
                    distance[k].Append(0);
                }
            }

            for (int k = 0; k < files.Length; k++)
            {
                parent[k] = k; hasFolder[k] = false;
            }

            for (int i = 0; i < activeArray.Count; i++)
            {
                for (int j = i; j < activeArray.Count; j++)
                {
                    double d = Math.Min(GetHammingDistance(activeArray[i], activeArray[j], true), GetHammingDistance(activeArray[j], activeArray[i], true));
                    //double d = GetHammingDistance(activeArray[i], activeArray[j], false);

                    distance[i][j] = d;
                    distance[j][i] = d;
                }
            }
            SaveOutput(activeArray, path, imageNames);
            Groupping(distance, imageNames, path);
            Report(distance, imageNames);
        }
        /// <summary>
        /// This function train the input image and write result to text files in folder @"/OutputDutyCycle"
        /// The result text files include speed comparison between global inhibition and local inhibition,
        /// the stable of the out put array (by comparing hamming distance arrays).
        /// Finally this method draw an image of active column as .png file.
        /// This training method is used for testing speed of training with different value of max boost and duty cycle
        /// </summary>
        /// <param name="inputBinarizedFile">input image after binarized</param>
        /// <param name="hammingFile">Path to hamming distance output file</param>
        /// <param name="outputSpeedFile">Path to speed comparison output file</param>
        /// <param name="outputImage">Path to active column after training output file (as .png image file)</param>
        /// <param name="parameters">Parameter setup</param>
        private static void Training(string inputBinarizedFile, string hammingFile, string outputSpeedFile, string outputImage, Parameters parameters)
        {
            int outputImageSize = 1024;
            int topology        = parameters.Get <int[]>(KEY.COLUMN_DIMENSIONS)[0];
            int activeColumn    = topology * topology;
            var stopwatch       = new Stopwatch();

            using (StreamWriter swHamming = new StreamWriter(hammingFile))
            {
                using (StreamWriter swSpeed = new StreamWriter(outputSpeedFile, true))
                {
                    var sp  = new SpatialPooler();
                    var mem = new Connections();

                    parameters.apply(mem);

                    stopwatch.Start();
                    sp.Init(mem);
                    stopwatch.Stop();

                    int   actiColumnLength = activeColumn;
                    int[] activeArray      = new int[actiColumnLength];

                    // Read input csv file into array
                    int[] inputVector = NeoCortexUtils.ReadCsvFileTest(inputBinarizedFile).ToArray();

                    stopwatch.Restart();

                    int   iterations = 1000;
                    int[] oldArray   = new int[activeArray.Length];

                    for (int k = 0; k < iterations; k++)
                    {
                        sp.compute(inputVector, activeArray, true);

                        var activeCols = activeArray.IndexWhere((el) => el == 1);
                        var distance   = MathHelpers.GetHammingDistance(oldArray, activeArray);
                        var similarity = MathHelpers.CalcArraySimilarity(oldArray, activeArray);
                        swHamming.WriteLine($"{distance} | {similarity}");
                        var str = Helpers.StringifyVector(activeCols);
                        Debug.WriteLine(str);
                        oldArray = new int[actiColumnLength];
                        activeArray.CopyTo(oldArray, 0);
                    }

                    var activeArrayString = Helpers.StringifyVector(activeArray);

                    stopwatch.Stop();

                    Debug.WriteLine("Active Array: " + activeArrayString);

                    int    potentialRadius    = parameters.Get <int>(KEY.POTENTIAL_RADIUS);
                    bool   isGlobalInhibition = parameters.Get <bool>(KEY.GLOBAL_INHIBITION);
                    string inhibition         = isGlobalInhibition ? "Global" : "Local";
                    double milliseconds       = stopwatch.ElapsedMilliseconds;
                    double seconds            = milliseconds / 1000;
                    swSpeed.WriteLine($"Column dimension: {topology.ToString().PadRight(5)} |Potential Radius: {potentialRadius}| Inhibition type: {inhibition.PadRight(7)} | Total time: {milliseconds:N0} milliseconds ({seconds:N2} seconds).");

                    int[,] twoDimenArray = ArrayUtils.Make2DArray(activeArray, topology, topology);
                    twoDimenArray        = ArrayUtils.Transpose(twoDimenArray);

                    NeoCortexUtils.DrawBitmap(twoDimenArray, outputImageSize, outputImageSize, outputImage);
                }
            }
        }
        /// <summary>
        /// Implements the experiment.
        /// </summary>
        /// <param name="cfg"></param>
        /// <param name="encoder"></param>
        /// <param name="inputValues"></param>
        private static void RunExperiment(HtmConfig cfg, EncoderBase encoder, List <double> inputValues)
        {
            // Creates the htm memory.
            var mem = new Connections(cfg);

            bool isInStableState = false;

            //
            // HPC extends the default Spatial Pooler algorithm.
            // The purpose of HPC is to set the SP in the new-born stage at the begining of the learning process.
            // In this stage the boosting is very active, but the SP behaves instable. After this stage is over
            // (defined by the second argument) the HPC is controlling the learning process of the SP.
            // Once the SDR generated for every input gets stable, the HPC will fire event that notifies your code
            // that SP is stable now.
            HomeostaticPlasticityController hpa = new HomeostaticPlasticityController(mem, inputValues.Count * 40,
                                                                                      (isStable, numPatterns, actColAvg, seenInputs) =>
            {
                // Event should only be fired when entering the stable state.
                // Ideal SP should never enter unstable state after stable state.
                if (isStable == false)
                {
                    Debug.WriteLine($"INSTABLE STATE");
                    // This should usually not happen.
                    isInStableState = false;
                }
                else
                {
                    Debug.WriteLine($"STABLE STATE");
                    // Here you can perform any action if required.
                    isInStableState = true;
                }
            });

            // It creates the instance of Spatial Pooler Multithreaded version.
            SpatialPooler sp = new SpatialPooler(hpa);

            // Initializes the
            sp.Init(mem, new DistributedMemory()
            {
                ColumnDictionary = new InMemoryDistributedDictionary <int, NeoCortexApi.Entities.Column>(1)
            });

            // mem.TraceProximalDendritePotential(true);

            // It creates the instance of the neo-cortex layer.
            // Algorithm will be performed inside of that layer.
            CortexLayer <object, object> cortexLayer = new CortexLayer <object, object>("L1");

            // Add encoder as the very first module. This model is connected to the sensory input cells
            // that receive the input. Encoder will receive the input and forward the encoded signal
            // to the next module.
            cortexLayer.HtmModules.Add("encoder", encoder);

            // The next module in the layer is Spatial Pooler. This module will receive the output of the
            // encoder.
            cortexLayer.HtmModules.Add("sp", sp);

            double[] inputs = inputValues.ToArray();

            // Will hold the SDR of every inputs.
            Dictionary <double, int[]> prevActiveCols = new Dictionary <double, int[]>();

            // Will hold the similarity of SDKk and SDRk-1 fro every input.
            Dictionary <double, double> prevSimilarity = new Dictionary <double, double>();

            //
            // Initiaize start similarity to zero.
            foreach (var input in inputs)
            {
                prevSimilarity.Add(input, 0.0);
                prevActiveCols.Add(input, new int[0]);
            }

            // Learning process will take 1000 iterations (cycles)
            int maxSPLearningCycles = 1000;

            for (int cycle = 0; cycle < maxSPLearningCycles; cycle++)
            {
                Debug.WriteLine($"Cycle  ** {cycle} ** Stability: {isInStableState}");

                //
                // This trains the layer on input pattern.
                foreach (var input in inputs)
                {
                    double similarity;

                    // Learn the input pattern.
                    // Output lyrOut is the output of the last module in the layer.
                    //
                    var lyrOut = cortexLayer.Compute((object)input, true) as int[];

                    // This is a general way to get the SpatialPooler result from the layer.
                    var activeColumns = cortexLayer.GetResult("sp") as int[];

                    var actCols = activeColumns.OrderBy(c => c).ToArray();

                    similarity = MathHelpers.CalcArraySimilarity(activeColumns, prevActiveCols[input]);

                    Debug.WriteLine($"[cycle={cycle.ToString("D4")}, i={input}, cols=:{actCols.Length} s={similarity}] SDR: {Helpers.StringifyVector(actCols)}");

                    prevActiveCols[input] = activeColumns;
                    prevSimilarity[input] = similarity;
                }
            }
        }
Beispiel #22
0
        //[TestMethod, DeploymentItem("Resources/DataSets/OCR/characters/cmr_all.xml")]
        public void TestVisionBench()
        {
            // Set some training paths
            string trainingDataset   = "cmr_all.xml";
            string testingDataset    = "Resources/DataSets/OCR/characters/cmr_all.xml";
            double minAccuracy       = 100.0; // force max training cycles
            int    maxTrainingCycles = 5;

            // Create spatial parameters
            Parameters p = Parameters.Empty();

            p.SetParameterByKey(Parameters.KEY.INPUT_DIMENSIONS, new[] { 32, 32 }); // Size of image patch
            p.SetParameterByKey(Parameters.KEY.COLUMN_DIMENSIONS, new[] { 32, 32 });
            p.SetParameterByKey(Parameters.KEY.POTENTIAL_RADIUS, 10000);            // Ensures 100% potential pool
            p.SetParameterByKey(Parameters.KEY.POTENTIAL_PCT, 0.8);
            p.SetParameterByKey(Parameters.KEY.GLOBAL_INHIBITION, true);
            p.SetParameterByKey(Parameters.KEY.LOCAL_AREA_DENSITY, -1.0); // Using numActiveColumnsPerInhArea
            p.SetParameterByKey(Parameters.KEY.NUM_ACTIVE_COLUMNS_PER_INH_AREA, 64.0);
            // All input activity can contribute to feature output
            p.SetParameterByKey(Parameters.KEY.STIMULUS_THRESHOLD, 0.0);
            p.SetParameterByKey(Parameters.KEY.SYN_PERM_INACTIVE_DEC, 0.001);
            p.SetParameterByKey(Parameters.KEY.SYN_PERM_ACTIVE_INC, 0.001);
            p.SetParameterByKey(Parameters.KEY.SYN_PERM_CONNECTED, 0.3);
            p.SetParameterByKey(Parameters.KEY.MIN_PCT_OVERLAP_DUTY_CYCLES, 0.001);
            p.SetParameterByKey(Parameters.KEY.MIN_PCT_ACTIVE_DUTY_CYCLES, 0.001);
            p.SetParameterByKey(Parameters.KEY.DUTY_CYCLE_PERIOD, 1000);
            p.SetParameterByKey(Parameters.KEY.MAX_BOOST, 1.0);
            p.SetParameterByKey(Parameters.KEY.SEED, 1956);                       // The seed that Grok uses
            p.SetParameterByKey(Parameters.KEY.RANDOM, new XorshiftRandom(1956)); // The seed that Grok uses
            p.SetParameterByKey(Parameters.KEY.SP_VERBOSITY, 1);
            p.SetParameterByKey(Parameters.KEY.SP_PARALLELMODE, true);

            Connections cn = new Connections();

            p.Apply(cn);

            // Instantiate our spatial pooler
            SpatialPooler sp = new SpatialPooler();

            sp.Init(cn);

            // Instantiate the spatial pooler test bench.
            VisionTestBench tb = new VisionTestBench(cn, sp);

            // Instantiate the classifier
            KNNClassifier clf = KNNClassifier.GetBuilder().Apply(p);

            // Get testing images and convert them to vectors.
            var tupleTraining   = DatasetReader.GetImagesAndTags(trainingDataset);
            var trainingImages  = (List <Bitmap>)tupleTraining.Get(0);
            var trainingTags    = tupleTraining.Get(1) as List <string>;
            var trainingVectors = trainingImages.Select((i, index) => new { index, vector = i.ToVector() })
                                  .ToDictionary(k => k.index, v => v.vector);

            // Train the spatial pooler on trainingVectors.
            int numcycles = tb.Train(trainingVectors, trainingTags, clf, maxTrainingCycles, minAccuracy);

            // Get testing images and convert them to vectors.
            var tupleTesting   = DatasetReader.GetImagesAndTags(trainingDataset);
            var testingImages  = (List <System.Drawing.Bitmap>)tupleTesting.Get(0);
            var testingTags    = tupleTesting.Get(1) as List <string>;
            var testingVectors = testingImages.Select((i, index) => new { index, vector = i.ToVector() })
                                 .ToDictionary(k => k.index, v => v.vector);

            // Reverse the order of the vectors and tags for testing
            testingTags.Reverse();
            testingVectors.Reverse();

            // Test the spatial pooler on testingVectors.
            var accurancy = tb.Test(testingVectors, testingTags, clf, learn: true);

            Debug.WriteLine("Number of training cycles : " + numcycles);
            Debug.WriteLine("Accurancy : " + accurancy);

            tb.SavePermsAndConns("C:\\temp\\permsAndConns.jpg");
        }
        //[DataRow("MnistTestImages\\digit7.png", 128, 30)]
        public void CalculateSpeedOfLearningTest(string mnistImage, int[] imageSize, int[] topologies)
        {
            int    index1 = mnistImage.IndexOf("\\") + 1;
            int    index2 = mnistImage.IndexOf(".");
            string sub1   = mnistImage.Substring(0, index2);
            string sub2   = mnistImage.Substring(0, index1);
            string name   = mnistImage.Substring(index1, sub1.Length - sub2.Length);

            for (int imSizeIndx = 0; imSizeIndx < imageSize.Length; imSizeIndx++)
            {
                string testName             = $"{name}_{imageSize[imSizeIndx]}";
                string outputSpeedFile      = $"Output\\{testName}_speed.txt";
                string inputBinaryImageFile = BinarizeImage("Output\\" + mnistImage, imageSize[imSizeIndx], testName);
                for (int topologyIndx = 0; topologyIndx < topologies.Length; topologyIndx++)
                {
                    string finalName         = $"{testName}_{topologies[topologyIndx]}";
                    string outputHamDistFile = $"Output\\{finalName}_hamming.txt";
                    string outputActColFile  = $"Output\\{finalName}_activeCol.txt";

                    string outputImage = $"Output\\{finalName}.png";

                    int numOfActCols = 0;
                    var sw           = new Stopwatch();
                    using (StreamWriter swHam = new StreamWriter(outputHamDistFile))
                    {
                        using (StreamWriter swSpeed = new StreamWriter(outputSpeedFile, true))
                        {
                            using (StreamWriter swActCol = new StreamWriter(outputActColFile))
                            {
                                numOfActCols = topologies[topologyIndx] * topologies[topologyIndx];
                                var parameters = GetDefaultParams();
                                parameters.setInputDimensions(new int[] { imageSize[imSizeIndx], imageSize[imSizeIndx] });
                                parameters.setColumnDimensions(new int[] { topologies[topologyIndx], topologies[topologyIndx] });
                                parameters.setNumActiveColumnsPerInhArea(0.02 * numOfActCols);

                                var sp  = new SpatialPooler();
                                var mem = new Connections();

                                parameters.apply(mem);
                                sw.Start();

                                sp.Init(mem);

                                sw.Stop();
                                swSpeed.WriteLine($"{topologies[topologyIndx]}|{(double)sw.ElapsedMilliseconds / (double)1000}");

                                int   actiColLen  = numOfActCols;
                                int[] activeArray = new int[actiColLen];

                                //Read input csv file into array
                                int[] inputVector = NeoCortexUtils.ReadCsvIntegers(inputBinaryImageFile).ToArray();
                                sw.Restart();

                                int   iterations = 2;
                                int[] oldArray   = new int[activeArray.Length];
                                for (int k = 0; k < iterations; k++)
                                {
                                    sp.compute(inputVector, activeArray, true);

                                    var activeCols = ArrayUtils.IndexWhere(activeArray, (el) => el == 1);
                                    var distance   = MathHelpers.GetHammingDistance(oldArray, activeArray);
                                    swHam.WriteLine(distance + "\n");
                                    var str = Helpers.StringifyVector(activeCols);

                                    oldArray = new int[actiColLen];
                                    activeArray.CopyTo(oldArray, 0);
                                }

                                var activeStr = Helpers.StringifyVector(activeArray);
                                swActCol.WriteLine("Active Array: " + activeStr);

                                sw.Stop();

                                int[,] twoDimenArray = ArrayUtils.Make2DArray <int>(activeArray, topologies[topologyIndx], topologies[topologyIndx]);
                                twoDimenArray        = ArrayUtils.Transpose(twoDimenArray);

                                NeoCortexUtils.DrawBitmap(twoDimenArray, OutImgSize, OutImgSize, outputImage);
                            }
                        }
                    }
                }
            }
        }
Beispiel #24
0
        public void Execute(string dataSet = TrainingDataSet, double minAccuracy = 100.0, int maxTrainingCycles = 5)
        {
            var tupleTraining = DatasetReader.GetImagesAndTags(dataSet);
            // Get training images and convert them to vectors.
            var trainingImages  = (List <Bitmap>)tupleTraining.Get(0);
            var trainingTags    = tupleTraining.Get(1) as List <string>;
            var trainingVectors = trainingImages.Select((i, index) => new { index, vector = i.ToVector() })
                                  .ToDictionary(k => k.index, v => v.vector);

            // Specify parameter values to search
            CombinationParameters parameters = new CombinationParameters();

            parameters.Define("synPermConn", new List <object> {
                0.5
            });
            parameters.Define("synPermDecFrac", new List <object> {
                1.0, 0.5, 0.1
            });
            parameters.Define("synPermIncFrac", new List <object> {
                1.0, 0.5, 0.1
            });

            // Run the model until all combinations have been tried
            while (parameters.GetNumResults() < parameters.GetNumCombinations())
            {
                // Pick a combination of parameter values
                parameters.NextCombination();

                double synPermConnected = (double)parameters.GetValue("synPermConn");
                var    synPermDec       = synPermConnected * (double)parameters.GetValue("synPermDecFrac");
                var    synPermInc       = synPermConnected * (double)parameters.GetValue("synPermIncFrac");

                // Instantiate our spatial pooler
                Parameters p = Parameters.GetAllDefaultParameters();
                p.SetParameterByKey(Parameters.KEY.INPUT_DIMENSIONS, new[] { 32, 32 }); // Size of image patch
                p.SetParameterByKey(Parameters.KEY.COLUMN_DIMENSIONS, new[] { 32, 32 });
                p.SetParameterByKey(Parameters.KEY.POTENTIAL_RADIUS, 10000);            // Ensures 100% potential pool
                p.SetParameterByKey(Parameters.KEY.POTENTIAL_PCT, 0.8);
                p.SetParameterByKey(Parameters.KEY.GLOBAL_INHIBITION, true);
                p.SetParameterByKey(Parameters.KEY.LOCAL_AREA_DENSITY, -1.0); // Using numActiveColumnsPerInhArea
                p.SetParameterByKey(Parameters.KEY.NUM_ACTIVE_COLUMNS_PER_INH_AREA, 64.0);
                // All input activity can contribute to feature output
                p.SetParameterByKey(Parameters.KEY.STIMULUS_THRESHOLD, 0.0);
                p.SetParameterByKey(Parameters.KEY.SYN_PERM_INACTIVE_DEC, synPermDec);
                p.SetParameterByKey(Parameters.KEY.SYN_PERM_ACTIVE_INC, synPermInc);
                p.SetParameterByKey(Parameters.KEY.SYN_PERM_CONNECTED, synPermConnected);
                p.SetParameterByKey(Parameters.KEY.DUTY_CYCLE_PERIOD, 1000);
                p.SetParameterByKey(Parameters.KEY.MAX_BOOST, 1.0);
                p.SetParameterByKey(Parameters.KEY.SEED, 1956);                       // The seed that Grok uses
                p.SetParameterByKey(Parameters.KEY.RANDOM, new XorshiftRandom(1956)); // The seed that Grok uses
                p.SetParameterByKey(Parameters.KEY.SP_VERBOSITY, 1);

                Connections cn = new Connections();
                p.Apply(cn);

                SpatialPooler sp = new SpatialPooler();
                sp.Init(cn);

                // Instantiate the spatial pooler test bench.
                VisionTestBench tb = new VisionTestBench(cn, sp);

                // Instantiate the classifier
                KNNClassifier clf = KNNClassifier.GetBuilder().Apply(p);

                int numCycles = tb.Train(trainingVectors, trainingTags, clf, maxTrainingCycles, minAccuracy);

                // Get testing images and convert them to vectors.
                var tupleTesting   = DatasetReader.GetImagesAndTags(dataSet);
                var testingImages  = (List <System.Drawing.Bitmap>)tupleTesting.Get(0);
                var testingTags    = tupleTesting.Get(1) as List <string>;
                var testingVectors = testingImages.Select((i, index) => new { index, vector = i.ToVector() })
                                     .ToDictionary(k => k.index, v => v.vector);

                // Reverse the order of the vectors and tags for testing
                testingTags.Reverse();
                testingVectors.Reverse();

                // Test the spatial pooler on testingVectors.
                var accurancy = tb.Test(testingVectors, testingTags, clf, learn: true);

                // Add results to the list
                parameters.AppendResults(new List <object> {
                    accurancy, numCycles
                });
            }
            parameters.PrintResults(new[] { "Percent Accuracy", "Training Cycles" }, new[] { "\t{0}", "\t{0}" });
            Console.WriteLine("The maximum number of training cycles is set to: {0}", maxTrainingCycles);
        }
        /// <summary>
        ///
        /// </summary>
        private void RunExperiment(int inputBits, HtmConfig cfg, EncoderBase encoder, List <double> inputValues)
        {
            Stopwatch sw = new Stopwatch();

            sw.Start();

            int  maxMatchCnt = 0;
            bool learn       = true;

            var mem = new Connections(cfg);

            bool isInStableState = false;

            HtmClassifier <string, ComputeCycle> cls = new HtmClassifier <string, ComputeCycle>();

            var numInputs = inputValues.Distinct <double>().ToList().Count;

            CortexLayer <object, object> layer1 = new CortexLayer <object, object>("L1");

            TemporalMemory tm = new TemporalMemory();

            HomeostaticPlasticityController hpa = new HomeostaticPlasticityController(mem, numInputs * 150, (isStable, numPatterns, actColAvg, seenInputs) =>
            {
                if (isStable)
                {
                    // Event should be fired when entering the stable state.
                    Debug.WriteLine($"STABLE: Patterns: {numPatterns}, Inputs: {seenInputs}, iteration: {seenInputs / numPatterns}");
                }
                else
                {
                    // Ideal SP should never enter unstable state after stable state.
                    Debug.WriteLine($"INSTABLE: Patterns: {numPatterns}, Inputs: {seenInputs}, iteration: {seenInputs / numPatterns}");
                }

                // We are not learning in instable state.
                learn = isInStableState = isStable;

                //if (isStable && layer1.HtmModules.ContainsKey("tm") == false)
                //    layer1.HtmModules.Add("tm", tm);

                // Clear all learned patterns in the classifier.
                cls.ClearState();

                // Clear active and predictive cells.
                //tm.Reset(mem);
            }, numOfCyclesToWaitOnChange: 50);


            SpatialPooler sp = new SpatialPooler(hpa);

            sp.Init(mem);
            tm.Init(mem);

            layer1.HtmModules.Add("encoder", encoder);
            layer1.HtmModules.Add("sp", sp);

            double[] inputs         = inputValues.ToArray();
            int[]    prevActiveCols = new int[0];

            int cycle   = 0;
            int matches = 0;

            string lastPredictedValue = "0";

            //Dictionary<double, List<List<int>>> activeColumnsLst = new Dictionary<double, List<List<int>>>();

            //foreach (var input in inputs)
            //{
            //    if (activeColumnsLst.ContainsKey(input) == false)
            //        activeColumnsLst.Add(input, new List<List<int>>());
            //}

            int           maxCycles      = 3500;
            int           maxPrevInputs  = inputValues.Count - 1;
            List <string> previousInputs = new List <string>();

            previousInputs.Add("-1.0");

            //
            // Training SP to get stable. New-born stage.
            //

            for (int i = 0; i < maxCycles; i++)
            {
                matches = 0;

                cycle++;

                Debug.WriteLine($"-------------- Newborn Cycle {cycle} ---------------");

                foreach (var input in inputs)
                {
                    Debug.WriteLine($" -- {input} --");

                    var lyrOut = layer1.Compute(input, learn);

                    if (isInStableState)
                    {
                        break;
                    }
                }

                if (isInStableState)
                {
                    break;
                }
            }

            layer1.HtmModules.Add("tm", tm);

            //
            // Now training with SP+TM. SP is pretrained on the given input pattern set.
            for (int i = 0; i < maxCycles; i++)
            {
                matches = 0;

                cycle++;

                Debug.WriteLine($"-------------- Cycle {cycle} ---------------");

                foreach (var input in inputs)
                {
                    Debug.WriteLine($"-------------- {input} ---------------");

                    var lyrOut = layer1.Compute(input, learn) as ComputeCycle;

                    // lyrOut is null when the TM is added to the layer inside of HPC callback by entering of the stable state.
                    //if (isInStableState && lyrOut != null)
                    {
                        var activeColumns = layer1.GetResult("sp") as int[];

                        //layer2.Compute(lyrOut.WinnerCells, true);
                        //activeColumnsLst[input].Add(activeColumns.ToList());

                        previousInputs.Add(input.ToString());
                        if (previousInputs.Count > (maxPrevInputs + 1))
                        {
                            previousInputs.RemoveAt(0);
                        }

                        // In the pretrained SP with HPC, the TM will quickly learn cells for patterns
                        // In that case the starting sequence 4-5-6 might have the sam SDR as 1-2-3-4-5-6,
                        // Which will result in returning of 4-5-6 instead of 1-2-3-4-5-6.
                        // HtmClassifier allways return the first matching sequence. Because 4-5-6 will be as first
                        // memorized, it will match as the first one.
                        if (previousInputs.Count < maxPrevInputs)
                        {
                            continue;
                        }

                        string key = GetKey(previousInputs, input);

                        List <Cell> actCells;

                        if (lyrOut.ActiveCells.Count == lyrOut.WinnerCells.Count)
                        {
                            actCells = lyrOut.ActiveCells;
                        }
                        else
                        {
                            actCells = lyrOut.WinnerCells;
                        }

                        cls.Learn(key, actCells.ToArray());

                        if (learn == false)
                        {
                            Debug.WriteLine($"Inference mode");
                        }

                        Debug.WriteLine($"Col  SDR: {Helpers.StringifyVector(lyrOut.ActivColumnIndicies)}");
                        Debug.WriteLine($"Cell SDR: {Helpers.StringifyVector(actCells.Select(c => c.Index).ToArray())}");

                        if (key == lastPredictedValue)
                        {
                            matches++;
                            Debug.WriteLine($"Match. Actual value: {key} - Predicted value: {lastPredictedValue}");
                        }
                        else
                        {
                            Debug.WriteLine($"Missmatch! Actual value: {key} - Predicted value: {lastPredictedValue}");
                        }

                        if (lyrOut.PredictiveCells.Count > 0)
                        {
                            //var predictedInputValue = cls.GetPredictedInputValue(lyrOut.PredictiveCells.ToArray());
                            var predictedInputValues = cls.GetPredictedInputValues(lyrOut.PredictiveCells.ToArray(), 3);

                            foreach (var item in predictedInputValues)
                            {
                                Debug.WriteLine($"Current Input: {input} \t| Predicted Input: {item}");
                            }

                            lastPredictedValue = predictedInputValues.First().PredictedInput;
                        }
                        else
                        {
                            Debug.WriteLine($"NO CELLS PREDICTED for next cycle.");
                            lastPredictedValue = String.Empty;
                        }
                    }
                }

                // The brain does not do that this way, so we don't use it.
                // tm1.reset(mem);

                double accuracy = (double)matches / (double)inputs.Length * 100.0;

                Debug.WriteLine($"Cycle: {cycle}\tMatches={matches} of {inputs.Length}\t {accuracy}%");

                if (accuracy == 100.0)
                {
                    maxMatchCnt++;
                    Debug.WriteLine($"100% accuracy reched {maxMatchCnt} times.");
                    //
                    // Experiment is completed if we are 30 cycles long at the 100% accuracy.
                    if (maxMatchCnt >= 30)
                    {
                        sw.Stop();
                        Debug.WriteLine($"Exit experiment in the stable state after 30 repeats with 100% of accuracy. Elapsed time: {sw.ElapsedMilliseconds / 1000 / 60} min.");
                        learn = false;
                        break;
                    }
                }
                else if (maxMatchCnt > 0)
                {
                    Debug.WriteLine($"At 100% accuracy after {maxMatchCnt} repeats we get a drop of accuracy with {accuracy}. This indicates instable state. Learning will be continued.");
                    maxMatchCnt = 0;
                }
            }

            Debug.WriteLine("------------ END ------------");
        }