/// <summary> /// Invoked as the last step in learning of the SP. /// </summary> /// <param name="input">The input of the SP in the current cycle.</param> /// <param name="output">The output SDR of the Spatial Pooler compute cycle.</param> /// <returns></returns> public bool Compute(int[] input, int[] output) { bool res = false; double avgDerivation = -1; // We take the hash value of the input. var inpHash = GetHash(input); // // Here we track the number of active columns for every cycle for every input. // We want that this number for every input is approximately the same. if (m_NumOfActiveColsForInput.ContainsKey(inpHash)) { ArrayUtils.PushToInterval(m_NumOfActiveColsForInput[inpHash], m_MaxPreviousElements, output.Count(c => c == 1)); } // // If the pattern appears for the first time, add it to dictionary of seen patterns. if (!m_InOutMap.ContainsKey(inpHash)) { m_InOutMap.Add(inpHash, output); m_NumOfActiveColsForInput.Add(inpHash, new int[m_MaxPreviousElements]); m_NumOfStableCyclesForInput.Add(inpHash, 0); } else { if (m_Cycle >= this.m_MinCycles) { this.m_HtmMemory.HtmConfig.MaxBoost = 0.0; this.m_HtmMemory.HtmConfig.MinPctOverlapDutyCycles = 0.0; this.m_HtmMemory.HtmConfig.MinPctActiveDutyCycles = 0.0; } // If the input has been already seen, we calculate the similarity between already seen input // and the new input. The similarity is calculated as a correlation function. var similarity = CalcArraySimilarity(ArrayUtils.IndexWhere(m_InOutMap[inpHash], k => k == 1), ArrayUtils.IndexWhere(output, k => k == 1)); // We replace the existing value with the new one. m_InOutMap[inpHash] = output; // // We cannot expect the 100% for the entire learning cycle. Sometimes some // SDR appear with few more or less bits than in the previous cycle. // If this happen we take the new SDR (output) as the winner and put it in the map. if (similarity >= m_RequiredSimilarityThreshold) { // We calculate here the average change of the SDR for the given input. avgDerivation = ArrayUtils.AvgDelta(m_NumOfActiveColsForInput[inpHash]); // // If there is no change (SDR is stable) we count nuber of stable cycles. // If the average value is not 0, then we reset the number of stable cycles. if (avgDerivation == 0) { m_NumOfStableCyclesForInput[inpHash] = m_NumOfStableCyclesForInput[inpHash] + 1; } else { m_NumOfStableCyclesForInput[inpHash] = 0; } if (m_Cycle >= this.m_MinCycles) { if (m_NumOfStableCyclesForInput[inpHash] > m_RequiredNumOfStableCycles && IsInStableState(m_NumOfStableCyclesForInput, m_RequiredNumOfStableCycles)) { // We fire event when changed from instable to stable. if (!m_IsStable) { this.m_OnStabilityStatusChanged(true, m_InOutMap.Keys.Count, avgDerivation, m_Cycle); } m_IsStable = true; res = true; } } } else { m_NumOfStableCyclesForInput[inpHash] = 0; // If the new SDR output for the already seen input if (m_IsStable) { // THIS SHOULD NEVER HAPPEN! MEANS FROM STABLE TO INSTABLE! m_IsStable = false; this.m_OnStabilityStatusChanged(false, m_InOutMap.Keys.Count, avgDerivation, m_Cycle); } } } this.m_Cycle++; return(res); }