Working vb.net version of spatial pooler (pasted below)


#1

I was planning to try out an idea with the spatial pooler and the temporal pooler, and in the process I wrote a version of the spatial pooler in dot-net (vb.net). It does seem to work, the SDRs are different for the various inputs and related inputs have more similar SDRs than non-related inputs. I’m pasting the classes below, if anyone wants the full program I can post it on GitHub.
It does have limitations - I just wrote it for a the global neighborhood case, and to try it out I use a scalar encoder where the number 7 might consist (for example) of 20 bits and the number 8 might also be 20 bits, but shifted to the right by 1.
Anyway, since the idea I’m planning to try out has difficulties (trying to recreate the input of the SDR by looking at the active columns and the projections to them is unlikely to work), at least I’ve produced some working code, for anyone who wants to carry it further. Here it is:

' c:\MakeSDR\MakeSDR\SpatialPoolClass.vb
Public Class SpatialPoolClass
    Structure TwoMaxStruct
        Dim colindexMax As Integer
        Dim MaxAverageOfOverlap As Double
        Dim colindexSecondToMax As Integer
        Dim SecondToMaxAverageOfOverlap As Double
        Dim colindexMin As Integer
        Dim MinAverageOfOverlap As Double
    End Structure
    Public columns() As spColumn
    Public activeColumnIndices As List(Of Integer)


    Public Sub New()
        ' every dendrite should have synapses connected to the input encoder.   Their permanences should be set.

        Dim HowManySynapses As Integer
        Dim i As Integer
        Dim j As Integer
        Dim r As New Random

        If ClassConstants.pEncoderType = ClassConstants.EnumEncoderType.GlobalEncode Then
            ClassConstants.PotentialAreaMagnitude = Math.Round(ClassConstants.PotentialFraction * ClassConstants.pEncoderLength)
            ClassConstants.PotentialStartIndexMax = ClassConstants.pEncoderLength - ClassConstants.PotentialAreaMagnitude
            HowManySynapses = ClassConstants.bitsPerPattern
            ReDim columns(ClassConstants.columnCount - 1)

            For i = 0 To ClassConstants.columnCount - 1
                Dim c As New spColumn(i, r)
                For j = 0 To HowManySynapses - 1
                    c.addNewSynapse(r)
                Next
                c.initPermanences(r)
                c.pDendrite.Sort()
                columns(i) = c
            Next

            '  columns(0).ClampDendriteForPatternZero() ' diagnostic!!!!
        Else
            Throw New Exception("Spatial Pooler 'Initialize' routine has not been implemented for non-scalar input-encodings")
        End If


    End Sub
    Sub ComputeOverlapWithInput()
        Dim c As spColumn
        Dim s As Synapse
        Dim numones As Integer

        For Each c In columns
            numones = 0
            For Each s In c.pDendrite
                If s.permanence >= ClassConstants.connectedPerm Then
                    If s.active Then
                        numones = numones + 1
                    End If
                End If
            Next

            c.pOverlap = numones * c.pBoost

        Next
    End Sub


    Sub UpdateSynapsePermanenceAndMore()
        Dim index As Integer
        Dim c As spColumn
        Dim minMovingAverageOfOverlaps As Double
        Dim s As Synapse
        Dim maxesStruct As New TwoMaxStruct
        Dim MovingAverageOfOverlaps As Double
        Dim MovingAverageOfActivityOfNeighbors As Double
        Dim sumMovingAveragesOfActiveCols As Double = 0

        For Each index In activeColumnIndices
            c = columns(index)
            For Each s In c.pDendrite
                If s.active Then
                    s.permanence = s.permanence + ClassConstants.synPermActiveInc
                    If s.permanence > 1 Then
                        s.permanence = 1
                    End If
                Else
                    s.permanence = s.permanence - ClassConstants.synPermInactiveDec
                    If s.permanence < 0 Then
                        s.permanence = 0
                    End If
                End If
            Next
            c.AddActiveValueToMemoryBuffer()
            c.AddOverlapValueToMemoryBuffer()
        Next

        If ClassConstants.pEncoderType = ClassConstants.EnumEncoderType.GlobalEncode Then
            GetSumActivesAndMovingAveragesOfOverlap(sumMovingAveragesOfActiveCols, maxesStruct)
        End If

        For Each c In columns

            If ClassConstants.pEncoderType = ClassConstants.EnumEncoderType.GlobalEncode Then
                MovingAverageOfActivityOfNeighbors = (sumMovingAveragesOfActiveCols - c.pMovingAverageOfActivity) / (columns.Length - 1)
                minMovingAverageOfOverlaps = maxesStruct.MinAverageOfOverlap
            Else
                MovingAverageOfActivityOfNeighbors = getActiveMovingAverageOfNeighbors(c.pColindex)
                minMovingAverageOfOverlaps = 0.01 * maxMovingAverageOfOverlap(getNeighbors(c.pNeighborIndices))
            End If



            c.pBoost = c.boostFunction(MovingAverageOfActivityOfNeighbors)

            If MovingAverageOfOverlaps <= minMovingAverageOfOverlaps Then
                c.increasePermanences(0.1 * ClassConstants.connectedPerm)
            End If
        Next
        If ClassConstants.pEncoderType = ClassConstants.EnumEncoderType.GlobalEncode Then
            ClassConstants.inhibitionRadius = ClassConstants.pEncoderLength
        Else
            ClassConstants.inhibitionRadius = averageReceptiveFieldSize()
        End If

    End Sub
    Function getActiveMovingAverageOfNeighbors(ByVal cColindex As Integer) As Double
        Dim i As Integer
        Dim sum = 0
        For i = 0 To columns.Count - 1
            If i = cColindex Then
                Continue For
            End If
            sum = sum + columns(i).pMovingAverageOfActivity
        Next
        Return sum / (columns.Length - 1)
    End Function

    Sub GetSumActivesAndMovingAveragesOfOverlap(ByRef sum As Double, ByRef thestruct As TwoMaxStruct)
        Dim i As Integer
        With thestruct
            .colindexMax = 0
            .MaxAverageOfOverlap = 0
            .colindexSecondToMax = 0
            .SecondToMaxAverageOfOverlap = 0
            .colindexMin = 0
            .MinAverageOfOverlap = 0
        End With
        sum = 0
        thestruct.MaxAverageOfOverlap = columns(0).pMovingAverageOfOverlap
        thestruct.MinAverageOfOverlap = columns(0).pMovingAverageOfOverlap
        For i = 1 To columns.Count - 1
            If columns(i).pMovingAverageOfOverlap > thestruct.MaxAverageOfOverlap Then
                thestruct.MaxAverageOfOverlap = columns(i).pMovingAverageOfOverlap
                thestruct.colindexMax = i
            End If
            If columns(i).pMovingAverageOfOverlap < thestruct.MinAverageOfOverlap Then
                thestruct.MinAverageOfOverlap = columns(i).pMovingAverageOfOverlap
                thestruct.colindexMin = i
            End If
        Next

        For i = 0 To columns.Count - 1
            If columns(i).pMovingAverageOfOverlap > thestruct.SecondToMaxAverageOfOverlap And
                columns(i).pMovingAverageOfOverlap <> thestruct.MaxAverageOfOverlap Then
                thestruct.SecondToMaxAverageOfOverlap = columns(i).pMovingAverageOfOverlap
                thestruct.colindexSecondToMax = i
            End If
        Next

        For i = 0 To columns.Count - 1
            sum = sum + columns(i).pMovingAverageOfOverlap
        Next
    End Sub
    Function getNeighbors(ByRef neighborindices As List(Of Integer)) As List(Of spColumn)
        Dim nc As New List(Of spColumn)
        Dim i As Integer
        For i = 0 To neighborindices.Count - 1
            nc.Add(columns(i))
        Next
        Return nc
    End Function
    Public Sub ComputeOnce(ByVal train As Boolean)
        ComputeOverlapWithInput()
        '  MessageBox.Show(classPrint.printOverlaps(15))
        ComputeWinningColumns()
        If train Then
            UpdateSynapsePermanenceAndMore()
        End If
    End Sub


    Function kthScore(ByRef cols As List(Of spColumn), ByVal k As Integer, ByVal colindex As Integer) As Double
        ' return k'th highest overlap value.  
        ' this assumes that overlap was calculated earlier for each column in the list
        ' it assumes k starts at 1
        ' it assumes columns are sorted by activity in increasing order
        Dim i As Integer
        Dim j As Integer

        If ClassConstants.pEncoderType = ClassConstants.EnumEncoderType.GlobalEncode Then

            If cols.Count = 0 Then
                Return 0
            End If
            i = cols.Count - k
            If i < 0 Then
                Return 0
            End If
            If colindex > -1 Then
                For j = i To cols.Count - 1
                    If cols(j).pColindex = colindex Then
                        i = i - 1
                        Exit For
                    End If
                Next
            End If
        Else
            Throw New Exception("kth score not implemented for non global case")
        End If

        Return cols(i).pOverlap
    End Function


    Public Function getMinimumOverlapOfActiveCols() As Integer
        Dim collist As List(Of spColumn)
        collist = columns.ToList
        collist.Sort()
        Dim li As List(Of Integer)
        Dim colindex As Integer
        li = GetActiveColumnsUsingkthScoreGlobal(collist)
        If li.Count = 0 Then
            Throw New Exception("no active columns in getMinimumOverlapOfActiveCols")
        End If
        colindex = li(0)
        Return columns(colindex).pOverlap
    End Function
    Public Function GetActiveColumnsUsingkthScoreGlobal(collist As List(Of spColumn)) As List(Of Integer)
        Dim activelist As New List(Of Integer)
        Dim startI As Integer
        Dim i As Integer

        If collist.Count = 0 Then
            Return activelist
        End If
        startI = collist.Count - ClassConstants.numActiveColumnsPerinhArea
        If startI < 0 Then
            startI = 0
        End If
        For i = startI To collist.Count - 1
            activelist.Add(collist(i).pColindex)
        Next
        Return activelist
    End Function
    Sub ComputeWinningColumns()
        ' assuming global inhibition area.
        Dim c As spColumn
        Dim minLocalActivity As Double
        Dim collist As List(Of spColumn)
        Dim index As Integer
        Dim locallist As New List(Of Integer)

        activeColumnIndices = New List(Of Integer)
        If ClassConstants.pEncoderType = ClassConstants.EnumEncoderType.GlobalEncode Then
            collist = columns.ToList
            collist.Sort()
            locallist = GetActiveColumnsUsingkthScoreGlobal(collist)
            ' the above gets the top 10 columns (in overlap)

            For Each c In columns
                c.pActive = False
            Next
            For Each index In locallist
                c = columns(index)

                If c.pOverlap > ClassConstants.stimulusThreshold And c.pOverlap >= minLocalActivity Then
                    c.pActive = True
                    activeColumnIndices.Add(c.pColindex)
                End If
            Next
        Else
            Throw New Exception("'ComputeWinningColumns' is not implemented for non-global case.")
        End If
    End Sub


    Public Function averageReceptiveFieldSize() As Double
        Dim c As spColumn
        Dim sum As Double

        For Each c In columns
            sum = sum + c.pReceptiveFieldSize
        Next
        Return (sum / columns.Count)
    End Function
    Function maxMovingAverageOfOverlap(ByVal cols As List(Of spColumn)) As Double
        Dim i As Integer

        Dim maxdc As Double = 0
        For i = 0 To cols.Count - 1
            If maxdc < cols(i).pMovingAverageOfOverlap Then
                maxdc = cols(i).pMovingAverageOfOverlap
            End If
        Next
        Return maxdc
    End Function
End Class

' c:\MakeSDR\MakeSDR\spColumn.vb
Imports MakeSDR
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.IO
Imports System.Text
<Serializable()>
Public Class spColumn
    Implements IComparable(Of spColumn)

    Private _boost As Double = 1 ' to start
    Private _overlap As Integer
    Private _movingAverageOfActivity As Double
    Private _movingAverageOfOverlap As Double
    Private _active As Boolean
    Private _activeCbuf As New CircularBufferBoolean(1000)
    Private _overlapCbuf As New CircularBufferInteger(1000)
    Private _dendrite As New List(Of Synapse)
    Private _colindex As Integer
    Private PotentialAreaStartIndex As Integer = 0

    '   Private _naturalCenter As Integer



    Public Sub New(ByVal colindex As Integer, ByRef theRandom As Random)


        ' Dim bitspercol As Double

        PotentialAreaStartIndex = theRandom.Next(0, ClassConstants.PotentialStartIndexMax + 1) ' have to add one because 'next' doesn't include upper bound
        _colindex = colindex

        ' comment out for now:
        'If ClassConstants.pEncoderType = ClassConstants.EnumEncoderType.GlobalEncode Then
        '    
        '    ' If ClassConstants.columnCount = ClassConstants.pEncoderLength Then
        '    '     _naturalCenter = colindex
        '    'Else
        '    ' bitspercol = ClassConstants.pEncoderLength / ClassConstants.columnCount
        '    '      _naturalCenter = bitspercol * colindex + bitspercol / 2.0 ' wait, not have PotentialAreaStartIndex and Area
        '    'End If

        'Else
        '    Throw New Exception("have not implemented 'natural center' for non-global case")
        'End If

    End Sub


    Public ReadOnly Property pMovingAverageOfActivity As Double
        Get
            _movingAverageOfActivity = _activeCbuf.MovingAverage
            Return _movingAverageOfActivity
        End Get

    End Property

    Public Sub addNewSynapse(ByRef r As Random)
        Dim se As New Synapse
        Dim sii As Integer

        With se
            Do While True
                sii = r.Next(PotentialAreaStartIndex, ClassConstants.PotentialAreaMagnitude + PotentialAreaStartIndex)
                If sii >= ClassConstants.pEncoderLength Then ' this would happen with a wrap-around encoder
                    sii = sii - ClassConstants.pEncoderLength
                End If
                If Not DendriteAlreadyContainsInput(sii) Then
                    Exit Do
                End If
            Loop
            .sourceInputIndex = sii
        End With
        _dendrite.Add(se)
    End Sub
    Public Function DendriteAlreadyContainsInput(ByVal sourceindex As Integer) As Boolean
        Dim i As Integer
        For i = 0 To pDendrite.Count - 1
            If pDendrite(i).sourceInputIndex = sourceindex Then
                Return True
            End If
        Next
        Return False
    End Function


    Public Function printDendrite() As String
        Dim sb As New StringBuilder("")
        Dim i As Integer
        For i = 0 To _dendrite.Count - 1

            sb.AppendLine(_dendrite(i).printself)
        Next
        Return sb.ToString
    End Function
    Public Sub initPermanences(ByRef r As Random)
        ' _naturalCenter = getNaturalCenter()
        Dim i As Integer
        Dim nd As Double
        Dim variance As Double

        variance = ClassConstants.connectedPerm * 0.7
        '  Dim distance As Double
        For i = 0 To _dendrite.Count - 1
            With _dendrite(i)
                ' distance = Math.Abs(.sourceInputIndex - _naturalCenter) / (ClassConstants.columnCount - 1)


                'distance = Math.Ceiling(distance * 10)
                'If distance > 10 Then
                '    distance = 10
                'End If
                nd = r.NextDouble() * variance * 2 - variance ' nextdouble >= 0, but less than 1.  Suppose variance is .2.   
                ' in that case, the maximum 'nd' can be is 1 * .2 * 2 - .2 or .2
                ' the least it can be is 0 - .2 or -.2


                .permanence = ClassConstants.connectedPerm + nd ' + 0.02 / distance
            End With
        Next
    End Sub


    Public ReadOnly Property pReceptiveFieldSize As Integer
        Get
            Dim i As Integer
            Dim sum As Integer = 0
            For i = 0 To _dendrite.Count - 1
                If _dendrite(i).permanence >= ClassConstants.connectedPerm Then
                    sum = sum + 1
                End If
            Next
            Return sum
        End Get
    End Property

    Public Sub increasePermanences(ByVal scalefactor As Double)
        Dim i As Integer
        For i = 0 To _dendrite.Count - 1
            With _dendrite(i)
                .permanence = .permanence * (1 + scalefactor)
            End With
        Next
    End Sub
    Public Function boostFunction(ByVal MovingAverageOfActivityOfNeighbors) As Double
        ' if activity of column equals activity of neighbors, return 1
        ' if activity of column is greater than activity of neighbors, return a number less than 1
        ' otherwise, return a number greater than 1. (at most it could be 'e' which is about 2.7183))
        If ClassConstants.pEncoderType <> ClassConstants.EnumEncoderType.GlobalEncode Then
            Throw New Exception("boostFunction is not implemented for columns that do not have global inputs")
        End If
        Dim diff As Double
        Dim expdiff As Double

        diff = pMovingAverageOfActivity - MovingAverageOfActivityOfNeighbors
        expdiff = Math.Exp(diff * ClassConstants.boostStrength * -1)

        Return expdiff
    End Function
    Public Property pBoost As Double
        Get
            Return _boost
        End Get
        Set(value As Double)
            _boost = value
        End Set
    End Property


    Public Function UpdateOverlapMovingAverage() As Double
        ' some routine before this must have set .poverlap, or this will not work
        AddOverlapValueToMemoryBuffer()
        Return pMovingAverageOfOverlap
    End Function

    Sub New()

    End Sub

    Public Function DeepCopyMe() As spColumn

        Dim m As MemoryStream = New MemoryStream()
        Dim b As BinaryFormatter = New BinaryFormatter()
        b.Serialize(m, Me)
        m.Position = 0
        Return CType(b.Deserialize(m), spColumn)
    End Function
    Public ReadOnly Property pDendrite As List(Of Synapse)
        Get
            Return _dendrite
        End Get
    End Property
    Public ReadOnly Property pColindex As Integer
        Get
            Return _colindex
        End Get
    End Property
    Public ReadOnly Property pNeighborIndices As List(Of Integer)
        Get
            Dim neighborindices As New List(Of Integer)
            If ClassConstants.pEncoderType = ClassConstants.EnumEncoderType.GlobalEncode Then
                Dim newlist As New List(Of Integer)
                Dim i As Integer
                For i = 0 To ClassConstants.columnCount - 1
                    If i = pColindex Then
                        Continue For
                    End If
                    newlist.Add(i)
                Next
                neighborindices = newlist
                Return neighborindices
            Else
                Throw New Exception("pNeighborIndices property has been coded only for scalar encodings (global)")
            End If

        End Get

    End Property
    Public Property pOverlap As Integer
        Get
            Return _overlap
        End Get
        Set(value As Integer)
            _overlap = value
        End Set
    End Property
    Public Property pActive As Boolean
        Get
            Return _active
        End Get
        Set(value As Boolean)
            _active = value
        End Set
    End Property


    Public ReadOnly Property pMovingAverageOfOverlap As Double
        Get
            _movingAverageOfOverlap = _overlapCbuf.MovingAverage(ClassConstants.stimulusThreshold)
            Return _movingAverageOfOverlap
        End Get

    End Property
    Public Sub AddActiveValueToMemoryBuffer()
        _activeCbuf.AddToBuffer(pActive)
    End Sub
    Public Sub AddOverlapValueToMemoryBuffer()
        _overlapCbuf.AddToBuffer(pOverlap)
    End Sub
    Public Function CompareTo(other As spColumn) As Integer Implements IComparable(Of spColumn).CompareTo
        If _overlap = other.pOverlap Then
            Return 0
        Else
            If _overlap < other.pOverlap Then
                Return -1
            Else
                Return 1
            End If
        End If

    End Function



    Private Function getNaturalCenter() As Integer
        Dim i As Integer
        Dim listindices As New List(Of Integer)
        For i = 0 To pDendrite.Count - 1
            listindices.Add(pDendrite(i).sourceInputIndex)
        Next
        Return utils.median(listindices)
    End Function
    Public Function showColumnFields() As String
        Dim sb As New StringBuilder("")

        sb.AppendLine("column # " & _colindex)
        sb.AppendLine("boost is " & Math.Round(_boost, 2))
        sb.AppendLine("overlap is " & _overlap)
        sb.AppendLine("movingAverageOfActivity is " & Math.Round(_movingAverageOfActivity, 2))
        sb.AppendLine("movingAverageOfOverlap is " & Math.Round(_movingAverageOfOverlap, 2))
        sb.AppendLine("_active is " & _active)
        sb.AppendLine("_activeCbuf is " & _activeCbuf.pMostRecentValues)
        sb.AppendLine("_overlapCbuf is " & _overlapCbuf.pMostRecentValues)
        sb.AppendLine("dendrite follows: ")
        sb.AppendLine(printDendrite())
        sb.AppendLine("PotentialAreaStartIndex is " & PotentialAreaStartIndex)

        Return sb.ToString
    End Function
    Public Sub ClampDendriteForPatternZero()
        Dim i As Integer
        For i = 0 To pDendrite.Count - 1
            If i < ClassConstants.bitsPerPattern Then
                pDendrite(i).sourceInputIndex = i
            Else
                pDendrite(i).sourceInputIndex = 0
                pDendrite(i).permanence = 0
            End If

        Next
    End Sub
End Class


' c:\MakeSDR\MakeSDR\Synapse.vb
<Serializable()>
Public Class Synapse
    Implements IComparable(Of Synapse)

    Public permanence As Double
    Public sourceInputIndex As Integer

    Public Function active() As Boolean
        If ClassConstants.encodedinput(sourceInputIndex) Then
            Return True
        Else
            Return False
        End If
    End Function
    Public Function printself() As String
        Return ("input[" & sourceInputIndex & "] - permanence is " & Math.Round(permanence, 1) & " " & utils.ShowBoolAsAsterix(active))
    End Function
    Public Function CompareTo(other As Synapse) As Integer Implements IComparable(Of Synapse).CompareTo
        If sourceInputIndex = other.sourceInputIndex Then
            Return 0
        Else
            If sourceInputIndex < other.sourceInputIndex Then
                Return -1
            Else
                Return 1
            End If
        End If

    End Function

End Class


' c:\MakeSDR\MakeSDR\ClassConstants.vb
Imports System.Text
Public Class ClassConstants
    Private Shared _previousListOfAskIndices As New List(Of Integer)
    Private Shared _previousListOfAskIndices2 As New List(Of Integer)
    Private Shared _encoderType As EnumEncoderType
    Public Shared PotentialAreaMagnitude As Integer
    Public Shared CopyOfColumns() As spColumn = Nothing
    Public Shared PotentialStartIndexMax As Integer = 0
    Public Shared columnCount As Integer = 2048
    Public Shared numActiveColumnsPerinhArea As Integer = 40 ' dependent on inhibition radius
    Public Shared maxBoost As Double = 1 ' for simple scenarios
    Public Shared PotentialFraction As Double = 0.8 ' dependent on how many on-bits are in a input, and how many synapses are originally connected
    Public Shared connectedPerm As Double = 0.3
    Public Shared synPermActiveInc As Double = 0.03 ' data dependent
    Public Shared synPermInactiveDec As Double = 0.015 ' data dependent
    Public Shared excludeList As List(Of Double)
    Public Shared encoderDimensions As Integer = 1
    Public Shared encodedinput() As Boolean
    '   Public Shared reconstructedInput() As Boolean = Nothing
    Public Shared stimulusThreshold As Integer = 0
    Public Shared buckets As Integer = 100
    Public Shared MaxPattern As Double = 100
    Public Shared MinPattern As Double = 0
    Public Shared bitsPerPattern As Integer = 21
    Public Shared boostStrength As Double = 1
    Public Shared sp As SpatialPoolClass

    ' calculated values:
    Public Shared inhibitionRadius As Integer
    Private Shared _encoderlength As Integer = 0



    Public Enum EnumEncoderType
        Other = 0
        GlobalEncode = 1
        localEncode = 2
    End Enum
    Public Shared Property pPreviousListOfAskIndices2 As List(Of Integer)
        Get
            Return _previousListOfAskIndices2
        End Get
        Set(value As List(Of Integer))
            _previousListOfAskIndices2 = value
        End Set
    End Property
    Public Shared Property pPreviousListOfAskIndices As List(Of Integer)
        Get
            Return _previousListOfAskIndices
        End Get
        Set(value As List(Of Integer))
            _previousListOfAskIndices = value
        End Set
    End Property
    Public Shared Property pEncoderType As EnumEncoderType
        Get
            Return _encoderType
        End Get
        Set(value As EnumEncoderType)
            _encoderType = value
        End Set
    End Property
    Public Shared Property pEncoderLength As Integer
        Get
            Return _encoderlength
        End Get
        Set(value As Integer)
            _encoderlength = value
            inhibitionRadius = value
            ReDim encodedinput(_encoderlength)
        End Set
    End Property



End Class


' c:\MakeSDR\MakeSDR\encoder.vb
Imports System.Text
Public Class encoder
    Public Shared Function CalculateEncoderLength() As Integer
        Dim n As Integer

        n = ClassConstants.buckets + ClassConstants.bitsPerPattern - 1
        Return n
    End Function
    Public Shared Sub createglobalEncoderPattern(ByVal encodethis As Integer, ByRef encodedinput() As Boolean)
        Dim i As Integer
        Dim range As Double
        Dim startat As Integer

        range = ClassConstants.MaxPattern - ClassConstants.MinPattern
        startat = Math.Floor(ClassConstants.buckets * (encodethis - ClassConstants.MinPattern) / range)

        cleartheinputpattern(encodedinput)

        For i = startat To startat + ClassConstants.bitsPerPattern - 1
            encodedinput(i) = True
        Next

    End Sub

    Public Shared Sub cleartheinputpattern(ByRef encodedinput() As Boolean)
        Dim i As Integer
        For i = 0 To encodedinput.Length - 1
            encodedinput(i) = False
        Next
    End Sub
    Public Shared Sub DisplayEncodedInput()
        Dim sb As New StringBuilder("")
        For i = 0 To ClassConstants.encodedinput.Length - 1
            If i > 0 Then
                sb.Append(",")
            End If
            If ClassConstants.encodedinput(i) Then
                sb.Append("1")
            Else
                sb.Append("0")
            End If
        Next
        MessageBox.Show(sb.ToString)
    End Sub
End Class


' c:\MakeSDR\MakeSDR\utils.vb
Public Class utils
    Public Shared Function ShowBoolAsAsterix(ByVal inBool As Boolean) As String
        If inBool Then
            Return "*"
        Else
            Return ""
        End If
    End Function
    Public Shared Function median(ByVal thelist As List(Of Integer)) As Double
        thelist.Sort()
        Dim thecount As Double = thelist.Count
        thecount = thecount / 2
        If thecount = 1 Then
            Return thelist(0)
        End If

        If isEven(thecount) Then
            Return (thelist(thecount) + thelist(thecount - 1)) / 2
        Else
            Return thelist(Math.Floor(thecount))
        End If
    End Function
    Public Shared Function isEven(ByVal theCount As Double) As Boolean
        If theCount / 2 = Math.Floor(theCount / 2) Then
            Return True
        Else
            Return False
        End If
    End Function
End Class

#2

Two classes that I could not fit in the first post (there is a character-count limitation in these posts)

 ' c:\MakeSDR\MakeSDR\CircularBufferBoolean.vb
        <Serializable()>
        Public Class CircularBufferBoolean
            Private bufferlength As Integer
            Private buffer() As Boolean
            Private index As Integer
            Private reachedEndAtLeastOnce As Boolean
            Public Sub New()

            End Sub
            Public Sub New(ByVal blen As Integer)
                bufferlength = blen ' for a buffer of length 1, you would pass 1 (it has just one entry in it)
                ReDim buffer(bufferlength - 1)
                index = 0
                reachedEndAtLeastOnce = False
            End Sub
            Public Sub AddToBuffer(ByVal newval As Boolean)
                buffer(index) = newval
                index = index + 1
                If index >= bufferlength Then
                    index = 0
                    reachedEndAtLeastOnce = True
                End If
            End Sub
            Public Function MovingAverage() As Double
                Dim denom As Integer
                If reachedEndAtLeastOnce Then
                    denom = bufferlength
                Else
                    denom = index
                    If denom = 0 Then
                        Return 0
                    End If
                End If
                Dim sum As Integer = 0
                Dim i As Integer
                For i = 0 To denom - 1
                    If buffer(i) Then
                        sum = sum + 1
                    End If
                Next
                Return sum / denom
            End Function
            Public ReadOnly Property pNumEntries As Integer
                Get
                    If reachedEndAtLeastOnce Then
                        Return bufferlength
                    End If
                    Return index + 1
                End Get
            End Property
            Public ReadOnly Property pMostRecentValues() As String
                Get
                    If index = 0 And Not reachedEndAtLeastOnce Then
                        Return "None"
                    End If
                    Return "old to new: " & GetOneValue(2) & "," & GetOneValue(1) & "," & GetOneValue(0)
                End Get
            End Property

            Private Function GetOneValue(ByVal howfarback As Integer) As String
                If (index <= howfarback) And Not reachedEndAtLeastOnce Then
                    Return ""
                End If
                If (index <= howfarback) And reachedEndAtLeastOnce Then
                    Return translatebool(buffer(wrapBufferIndex(buffer.Length - howfarback)))
                End If

                Return translatebool(buffer(index - howfarback - 1))
            End Function
            Function wrapBufferIndex(ByVal inval As Integer) As Integer
                If inval < 0 Then
                    inval = inval + buffer.Length
                End If
                Return inval
            End Function
            Function translatebool(ByVal inval As Boolean) As String
                If inval Then
                    Return "T"
                Else
                    Return "F"
                End If
            End Function
        End Class


        ' c:\MakeSDR\MakeSDR\CircularBufferInteger.vb
        <Serializable()>
        Public Class CircularBufferInteger
            Private bufferlength As Integer
            Private buffer() As Integer
            Private index As Integer
            Private reachedEndAtLeastOnce As Boolean
            Public Sub New()

            End Sub
            Public Sub New(ByVal blen As Integer)
                bufferlength = blen ' for a buffer of length 1, you would pass 1 (it has just one entry in it)
                ReDim buffer(bufferlength - 1)
                index = 0
                reachedEndAtLeastOnce = False
            End Sub
            Public ReadOnly Property pNumEntries As Integer
                Get
                    If reachedEndAtLeastOnce Then
                        Return bufferlength
                    End If
                    Return index + 1
                End Get
            End Property
            Public ReadOnly Property pMostRecentValues() As String
                Get
                    If index = 0 And Not reachedEndAtLeastOnce Then
                        Return "None"
                    End If
                    Return GetOneValue(2) & "," & GetOneValue(1) & "," & GetOneValue(0)
                End Get
            End Property

            Private Function GetOneValue(ByVal howfarback As Integer) As String
                If (index <= howfarback) And Not reachedEndAtLeastOnce Then
                    Return ""
                End If
                If (index <= howfarback) And reachedEndAtLeastOnce Then
                    Return buffer(wrapBufferIndex(buffer.Length - howfarback))
                End If

                Return buffer(index - howfarback - 1)
            End Function
            Function wrapBufferIndex(ByVal inval As Integer) As Integer
                If inval < 0 Then
                    inval = inval + buffer.Length
                End If
                Return inval
            End Function
            Public Sub AddToBuffer(ByVal newval As Integer)
                buffer(index) = newval
                index = index + 1
                If index >= bufferlength Then
                    index = 0
                    reachedEndAtLeastOnce = True
                End If
            End Sub
            Public Function MovingAverage(ByVal threshold As Integer) As Double
                Dim denom As Integer
                If reachedEndAtLeastOnce Then
                    denom = bufferlength
                Else
                    denom = index
                    If denom = 0 Then
                        Return 0
                    End If
                End If
                Dim sum As Integer = 0
                Dim i As Integer
                For i = 0 To denom - 1
                    If buffer(i) >= threshold Then
                        sum = sum + 1
                    End If
                Next
                Return sum / denom
            End Function
        End Class