Example #1
0
        /// <summary>
        /// Uniform Column Mapping <br></br>
        /// Maps a column to its respective input index, keeping to the topology of the region. It takes the index of the column as an argument and determines
        /// what is the index of the flattened input vector that is to be the center of the column's potential pool. It distributes the columns over the inputs
        /// uniformly. The return value is an integer representing the index of the input bit. Examples of the expected output of this method:
        /// <list type="bullet">
        ///     <item>
        ///     If the topology is one dimensional, and the column index is 0, this method will return the input index 0. If the column index is 1, and there are
        ///     3 columns over 7 inputs, this method will return the input index 3.
        ///     </item>
        ///     <item>If the topology is two dimensional, with column dimensions [3, 5] and input dimensions [7, 11], and the column index is 3, the method returns
        ///     input index 8.
        ///     </item>
        /// </list>
        /// </summary>
        /// <param name="columnIndex">The index identifying a column in the permanence, potential and connectivity matrices.</param>
        /// <param name="colTop"></param>
        /// <param name="inpTop"></param>
        /// <returns>Flat index of mapped column.</returns>
        public static int MapColumn(int columnIndex, HtmModuleTopology colTop, HtmModuleTopology inpTop)
        {
            int[] columnCoords = AbstractFlatMatrix.ComputeCoordinates(colTop.NumDimensions,
                                                                       colTop.DimensionMultiplies, colTop.IsMajorOrdering, columnIndex);

            double[] colCoords = ArrayUtils.ToDoubleArray(columnCoords);

            double[] columnRatios = ArrayUtils.Divide(
                colCoords, ArrayUtils.ToDoubleArray(colTop.Dimensions), 0, 0);

            double[] inputCoords = ArrayUtils.Multiply(
                ArrayUtils.ToDoubleArray(inpTop.Dimensions), columnRatios, 0, 0);

            var colSpanOverInputs = ArrayUtils.Divide(
                ArrayUtils.ToDoubleArray(inpTop.Dimensions),
                ArrayUtils.ToDoubleArray(colTop.Dimensions), 0, 0);

            inputCoords = ArrayUtils.AddOffset(inputCoords, ArrayUtils.Multiply(colSpanOverInputs, 0.5));

            // Makes sure that inputCoords are in range [0, inpDims]
            int[] inputCoordInts = ArrayUtils.Clip(ArrayUtils.ToIntArray(inputCoords), inpTop.Dimensions, -1);

            return(AbstractFlatMatrix.ComputeIndex(inputCoordInts, inpTop.Dimensions, inpTop.NumDimensions,
                                                   inpTop.DimensionMultiplies, inpTop.IsMajorOrdering, true));
        }
Example #2
0
        /// <summary>
        /// Method computes the result after the data is provided by the temporal memory and encoder
        /// </summary>
        /// <param name="recordNum">Record number of this input pattern.
        /// Record numbers should normally increase sequentially by 1 each time unless there are missing records in the dataset.
        /// Knowing this information insures that we don't get confused by missing records.</param>
        /// <param name="classification">{@link Map} of the classification information:
        /// bucketIdx: index of the encoder bucket</param>
        /// <param name="patternNZ">list of the active indices from the output below</param>
        /// <param name="learn">if true, learn this sample</param>
        /// <param name="infer">if true, perform inference</param>
        /// <returns>ClassificationExperiment Object</returns>

        public ClassificationExperiment <T> Compute(int recordNum, Dictionary <string, object> classification, int[] patternNZ, bool learn, bool infer)
        {
            if (classification == null)
            {
                throw new ArgumentNullException(nameof(classification));
            }
            if (patternNZ == null)
            {
                throw new ArgumentNullException(nameof(patternNZ));
            }

            ClassificationExperiment <T> retVal = new ClassificationExperiment <T>();
            List <T> actualValues = (List <T>) this.actualValues;


            // Save the offset between recordNum and learnIteration if this is the first
            // compute
            if (recordNumMinusLearnIteration == -1)
            {
                recordNumMinusLearnIteration = recordNum - learnIteration;
            }

            // Update the learn iteration
            learnIteration = recordNum - recordNumMinusLearnIteration;


            if (patternNZHistory.Any(x => x.Item1 == learnIteration))
            {
                patternNZHistory.Add(Tuple.Create(learnIteration, patternNZ));
            }

            //-------------------------------------------------------------
            // For each active bit in the activationPattern, get the classification
            // votes
            //
            // Return value dict. For buckets which we don't have an actual value
            // for yet, just plug in any valid actual value. It doesn't matter what
            // we use because that bucket won't have non-zero likelihood anyways.
            if (infer)
            {
                // If doing 0-step prediction, we shouldn't use any knowledge
                // of the classification input during inference.
                object defaultValue = default(T);
                if (steps[0] == 0)
                {
                    defaultValue = 0;
                }
                else
                {
                    defaultValue = classification["actValue"];
                    if (defaultValue == null)
                    {
                        if (IsNumericType(default(T)))
                        {
                            defaultValue = ConversionExtensions.Convert <T>(-1);
                        }
                    }
                }

                T[] actValues = new T[this.actualValues.Count];

                for (int i = 0; i < actualValues.Count; i++)
                {
                    if (IsNumericType(default(T)))
                    {
                        actValues[i] = (T)(actualValues[i].Equals(ConversionExtensions.Convert <T>(-1)) ? ConversionExtensions.Convert <T>(defaultValue) : actualValues[i]);
                    }
                    else
                    {
                        actValues[i] = (T)(actualValues[i].Equals(default(T)) ? defaultValue : actualValues[i]);
                    }
                }

                retVal.setActualValues(actValues);

                // For each n-step prediction...
                foreach (int nSteps in steps)
                {
                    // Accumulate bucket index votes and actValues into these arrays
                    double[] sumVotes = new double[maxBucketIdx + 1];
                    double[] bitVotes = new double[maxBucketIdx + 1];

                    foreach (var bit in patternNZ)
                    {
                        var        key     = Tuple.Create(bit, nSteps);
                        BitHistory history = null;
                        activeBitHistory.TryGetValue(key, out history);
                        if (history == null)
                        {
                            continue;
                        }

                        history.Infer(bitVotes);

                        sumVotes = ArrayUtils.AddOffset(sumVotes, bitVotes);
                    }

                    // Return the votes for each bucket, normalized
                    double total = sumVotes.Sum();
                    if (total > 0)
                    {
                        sumVotes = ArrayUtils.Divide(sumVotes, total);
                    }
                    else
                    {
                        // If all buckets have zero probability then simply make all of the
                        // buckets equally likely. There is no actual prediction for this
                        // timestep so any of the possible predictions are just as good.
                        if (sumVotes.Length > 0)
                        {
                            double val = 1.0 / sumVotes.Length;
                            for (int i = 0; i < sumVotes.Length; i++)
                            {
                                sumVotes[i] = val;
                            }
                        }
                    }

                    retVal.setStats(nSteps, sumVotes);
                }
            }
            // ------------------------------------------------------------------------
            // Learning:
            // For each active bit in the activationPattern, store the classification
            // info. If the bucketIdx is None, we can't learn. This can happen when the
            // field is missing in a specific record.
            if (learn && classification["bucketIdx"] != null)
            {
                // Get classification info
                int    bucketIdx = (int)classification["bucketIdx"];
                object actValue  = null;
                if (classification["actValue"] == null)
                {
                    if (IsNumericType(default(T)))
                    {
                        actValue = ConversionExtensions.Convert <T>(-1);
                    }
                }
                else
                {
                    actValue = ConversionExtensions.Convert <T>(classification["actValue"]);
                }

                // Update maxBucketIndex
                maxBucketIdx = (int)Math.Max(maxBucketIdx, bucketIdx);

                // Update rolling average of actual values if it's a scalar. If it's
                // not, it must be a category, in which case each bucket only ever
                // sees one category so we don't need a running average.
                while (maxBucketIdx > actualValues.Count - 1)
                {
                    actualValues.Add(IsNumericType(default(T)) ? ConversionExtensions.Convert <T>(-1) : default(T));
                }
                if (actualValues[bucketIdx].Equals(IsNumericType(default(T)) ? ConversionExtensions.Convert <T>(-1) : default(T)))
                {
                    actualValues[bucketIdx] = (T)actValue;
                }
                else
                {
                    if (IsNumericType(actValue))
                    {
                        double val = ((1.0 - actValueAlpha) * Convert.ToDouble(actualValues[bucketIdx], enusFormatProvider)) +
                                     (actValueAlpha * (Convert.ToDouble(actValue, enusFormatProvider)));
                        actualValues[bucketIdx] = ConversionExtensions.Convert <T>(val);
                    }
                    else
                    {
                        actualValues[bucketIdx] = (T)actValue;
                    }
                }

                // Train each pattern that we have in our history that aligns with the
                // steps we have in steps
                int   nSteps         = -1;
                int   iteration      = 0;
                int[] learnPatternNZ = null;
                foreach (var n in steps)
                {
                    nSteps = n;
                    // Do we have the pattern that should be assigned to this classification
                    // in our pattern history? If not, skip it
                    bool found = false;
                    foreach (var t in patternNZHistory)
                    {
                        iteration      = t.Item1;
                        learnPatternNZ = t.Item2;
                        if (iteration == learnIteration - nSteps)
                        {
                            found = true;
                            break;
                        }
                        iteration++;
                    }
                    if (!found)
                    {
                        continue;
                    }

                    // Store classification info for each active bit from the pattern
                    // that we got nSteps time steps ago.
                    foreach (int bit in learnPatternNZ)
                    {
                        // Get the history structure for this bit and step
                        var        key     = Tuple.Create(bit, nSteps);
                        BitHistory history = null;
                        activeBitHistory.TryGetValue(key, out history);
                        if (history == null)
                        {
                            history = new BitHistory(alpha);
                            activeBitHistory.Add(key, history);
                        }
                        history.store(learnIteration, bucketIdx);
                    }
                }
            }

            return(retVal);
        }