public override void AdaptSynapses(Connections c, int[] inputVector, int[] activeColumns)
        {
            // Get all indicies of input vector, which are set on '1'.
            var inputIndices = ArrayUtils.IndexWhere(inputVector, inpBit => inpBit > 0);

            double[] permChanges = new double[c.HtmConfig.NumInputs];

            // First we initialize all permChanges to minimum decrement values,
            // which are used in a case of none-connections to input.
            ArrayUtils.InitArray(permChanges, -1 * c.HtmConfig.SynPermInactiveDec);

            // Then we update all connected permChanges to increment values for connected values.
            // Permanences are set in conencted input bits to default incremental value.
            ArrayUtils.SetIndexesTo(permChanges, inputIndices.ToArray(), c.HtmConfig.SynPermActiveInc);

            Parallel.For(0, activeColumns.Length, (i) =>
            {
                //Pool pool = c.getPotentialPools().get(activeColumns[i]);
                Pool pool     = c.GetColumn(activeColumns[i]).ProximalDendrite.RFPool;
                double[] perm = pool.GetDensePermanences(c.HtmConfig.NumInputs);
                int[] indexes = pool.GetSparsePotential();
                ArrayUtils.RaiseValuesBy(permChanges, perm);
                Column col = c.GetColumn(activeColumns[i]);
                HtmCompute.UpdatePermanencesForColumn(c.HtmConfig, perm, col, indexes, true);
            });
        }
        /// <summary>
        /// Returns a flat index computed from the specified coordinates.
        /// </summary>
        /// <param name="coordinates">  The index of the point</param>
        /// <param name="topology"></param>
        /// <returns>using the dimensions as a mixed radix definition.For example, in dimensions
        /// 42x10, the point [1, 4] is index 1*420 + 4*10 = 460.</returns>
        public static int GetFlatIndexFromCoordinates(int[] coordinates, HtmModuleTopology topology)
        {
            int[] localMults = topology.IsMajorOrdering ? HtmCompute.Reverse(topology.DimensionMultiplies) : topology.DimensionMultiplies;
            int   baseNum    = 0;

            for (int i = 0; i < coordinates.Length; i++)
            {
                baseNum += (localMults[i] * coordinates[i]);
            }
            return(baseNum);
        }
        /// <summary>
        /// Maps a column to its input bits. This method encapsulates the topology of the region. It takes the index of the column as an argument and determines
        /// what are the indices of the input vector that are located within the column's potential pool. The return value is a list containing the indices of
        /// the input bits. The current implementation of the base class only supports a 1 dimensional topology of columns with a 1 dimensional topology of inputs.
        /// To extend this class to support 2-D topology you will need to override this method. Examples of the expected output of this method:
        /// <list type="bullet">
        ///     <item>
        ///     If the potentialRadius is greater than or equal to the entire input space, (global visibility), then this method returns an array filled with
        ///     all the indices
        ///     </item>
        ///     <item>
        ///     If the topology is one dimensional, and the potentialRadius is 5, this method will return an array containing 5 consecutive values centered on
        ///     the index of the column (wrapping around if necessary).
        ///     </item>
        ///     <item>If the topology is two dimensional (not implemented), and the potentialRadius is 5, the method should return an array containing 25 '1's, where
        ///     the exact indices are to be determined by the mapping from 1-D index to 2-D position.
        ///     </item>
        /// </list>
        /// </summary>
        /// <param name="htmConfig">The configuration used in <see cref="Connections"/>.</param>
        /// <param name="columnIndex">The index identifying a column in the permanence, potential and connectivity matrices.</param>
        /// <param name="rnd"></param>
        /// <returns></returns>
        public static int[] MapPotential(HtmConfig htmConfig, int columnIndex, Random rnd)
        {
            int centerInput = MapColumn(columnIndex, htmConfig.ColumnModuleTopology, htmConfig.InputModuleTopology);

            // Here we have Receptive Field (RF)
            int[] columnInputs = HtmCompute.GetInputNeighborhood(htmConfig.WrapAround, htmConfig.InputModuleTopology, centerInput, htmConfig.PotentialRadius);

            // Select a subset of the receptive field to serve as the the potential pool.
            int numPotential = (int)(columnInputs.Length * htmConfig.PotentialPct + 0.5);

            int[] retVal = new int[numPotential];

            var data = ArrayUtils.Sample(columnInputs, retVal, rnd);

            return(data);
        }
        /// <summary>
        /// Gets indexes of neighborhood cells within centered radius
        /// </summary>
        /// <param name="centerIndex">The index of the point. The coordinates are expressed as a single index by
        /// using the dimensions as a mixed radix definition. For example, in dimensions 42x10, the point [1, 4] is index 1*420 + 4*10 = 460.
        /// </param>
        /// <param name="radius"></param>
        /// <param name="topology"></param>
        /// <returns>The points in the neighborhood, including centerIndex.</returns>
        public static int[] GetWrappingNeighborhood(int centerIndex, int radius, HtmModuleTopology topology)
        {
            int[] cp = HtmCompute.GetCoordinatesFromIndex(centerIndex, topology);

            // Dims of columns
            IntGenerator[] intGens = new IntGenerator[topology.Dimensions.Length];
            for (int i = 0; i < topology.Dimensions.Length; i++)
            {
                intGens[i] = new IntGenerator(cp[i] - radius, Math.Min((cp[i] - radius) + topology.Dimensions[i] - 1, cp[i] + radius) + 1);
            }

            List <List <int> > result = new List <List <int> >();

            result.Add(new List <int>());

            List <List <int> > interim = new List <List <int> >();

            int k = 0;

            foreach (IntGenerator gen in intGens)
            {
                interim.Clear();
                interim.AddRange(result);
                result.Clear();

                foreach (var lx in interim)
                {
                    gen.Reset();

                    for (int y = 0; y < gen.Size(); y++)
                    {
                        int py = ArrayUtils.Modulo(gen.Next(), topology.Dimensions[k]);
                        //int py = gen.next() % dimensions[k];

                        List <int> tl = new List <int>();
                        tl.AddRange(lx);
                        tl.Add(py);
                        result.Add(tl);
                    }
                }

                k++;
            }

            return(result.Select((tl) => GetFlatIndexFromCoordinates(tl.ToArray(), topology)).ToArray());
        }
        /// <summary>
        /// Gets the list of neighborhood columns around the centar with the given radius in the specified topology.
        /// </summary>
        /// <param name="centerIndex"></param>
        /// <param name="radius"></param>
        /// <param name="topology"></param>
        /// <returns></returns>
        public static int[] GetNeighborhood(int centerIndex, int radius, HtmModuleTopology topology)
        {
            var centerPosition = HtmCompute.GetCoordinatesFromIndex(centerIndex, topology);

            IntGenerator[] intGens = new IntGenerator[topology.Dimensions.Length];
            for (int i = 0; i < topology.Dimensions.Length; i++)
            {
                intGens[i] = new IntGenerator(Math.Max(0, centerPosition[i] - radius),
                                              Math.Min(topology.Dimensions[i] - 1, centerPosition[i] + radius) + 1);
            }

            List <List <int> > result = new List <List <int> >();

            result.Add(new List <int>());

            List <List <int> > interim = new List <List <int> >();

            foreach (IntGenerator gen in intGens)
            {
                interim.Clear();
                interim.AddRange(result);
                result.Clear();

                foreach (var lx in interim)
                {
                    gen.Reset();

                    for (int y = 0; y < gen.Size(); y++)
                    {
                        int        py = gen.Next();
                        List <int> tl = new List <int>();
                        tl.AddRange(lx);
                        tl.Add(py);
                        result.Add(tl);
                    }
                }
            }

            return(result.Select((tl) => GetFlatIndexFromCoordinates(tl.ToArray(), topology)).ToArray());
        }
        /// <summary>
        /// Implements muticore initialization of pooler.
        /// </summary>
        /// <param name="c"></param>
        protected override void ConnectAndConfigureInputs(Connections c)
        {
            List <KeyPair> colList = new List <KeyPair>();

            ConcurrentDictionary <int, KeyPair> colList2 = new ConcurrentDictionary <int, KeyPair>();

            int numColumns = c.HtmConfig.NumColumns;

            // Parallel implementation of initialization
            ParallelOptions opts = new ParallelOptions();

            //int synapseCounter = 0;

            Parallel.For(0, numColumns, opts, (indx) =>
            {
                Random rnd = new Random(42);

                int colIndex = (int)indx;
                var data     = new ProcessingData
                {
                    // Gets RF
                    Potential = HtmCompute.MapPotential(c.HtmConfig, colIndex, rnd /*(c.getRandom()*/),
                    Column    = c.GetColumn(colIndex)
                };

                // This line initializes all synases in the potential pool of synapses.
                // It creates the pool on proximal dendrite segment of the column.
                // After initialization permancences are set to zero.
                data.Column.CreatePotentialPool(c.HtmConfig, data.Potential, -1);
                //connectColumnToInputRF(c.HtmConfig, data.Potential, data.Column);

                //Interlocked.Add(ref synapseCounter, data.Column.ProximalDendrite.Synapses.Count);

                //colList.Add(new KeyPair() { Key = i, Value = column });

                data.Perm = HtmCompute.InitSynapsePermanences(c.HtmConfig, data.Potential, c.HtmConfig.Random);

                data.AvgConnected = GetAvgSpanOfConnectedSynapses(c, colIndex);

                HtmCompute.UpdatePermanencesForColumn(c.HtmConfig, data.Perm, data.Column, data.Potential, true);

                if (!colList2.TryAdd(colIndex, new KeyPair()
                {
                    Key = colIndex, Value = data
                }))
                {
                }
            });

            //c.setProximalSynapseCount(synapseCounter);

            List <double> avgSynapsesConnected = new List <double>();

            foreach (var item in colList2.Values)
            //for (int i = 0; i < numColumns; i++)
            {
                int i = (int)item.Key;

                ProcessingData data = (ProcessingData)item.Value;
                //ProcessingData data = new ProcessingData();

                // Debug.WriteLine(i);
                //data.Potential = mapPotential(c, i, c.isWrapAround());

                //var st = string.Join(",", data.Potential);
                //Debug.WriteLine($"{i} - [{st}]");

                //var counts = c.getConnectedCounts();

                //for (int h = 0; h < counts.getDimensions()[0]; h++)
                //{
                //    // Gets the synapse mapping between column-i with input vector.
                //    int[] slice = (int[])counts.getSlice(h);
                //    Debug.Write($"{slice.Count(y => y == 1)} - ");
                //}
                //Debug.WriteLine(" --- ");
                // Console.WriteLine($"{i} - [{String.Join(",", ((ProcessingData)item.Value).Potential)}]");

                // This line initializes all synases in the potential pool of synapses.
                // It creates the pool on proximal dendrite segment of the column.
                // After initialization permancences are set to zero.
                //var potPool = data.Column.createPotentialPool(c, data.Potential);
                //connectColumnToInputRF(c, data.Potential, data.Column);

                //data.Perm = initPermanence(c.getSynPermConnected(), c.getSynPermMax(),
                //      c.getRandom(), c.getSynPermTrimThreshold(), c, data.Potential, data.Column, c.getInitConnectedPct());

                //updatePermanencesForColumn(c, data.Perm, data.Column, data.Potential, true);

                avgSynapsesConnected.Add(data.AvgConnected);

                colList.Add(new KeyPair()
                {
                    Key = i, Value = data.Column
                });
            }

            SparseObjectMatrix <Column> mem = (SparseObjectMatrix <Column>)c.HtmConfig.Memory;

            if (mem.IsRemotelyDistributed)
            {
                // Pool is created and attached to the local instance of Column.
                // Here we need to update the pool on remote Column instance.
                mem.set(colList);
            }

            // The inhibition radius determines the size of a column's local
            // neighborhood.  A cortical column must overcome the overlap score of
            // columns in its neighborhood in order to become active. This radius is
            // updated every learning round. It grows and shrinks with the average
            // number of connected synapses per column.
            UpdateInhibitionRadius(c, avgSynapsesConnected);
        }