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); }