/* Encodes input to specified slice. Slice should be valid length */ func (se *ScalerEncoder) EncodeToSlice(input float64, learn bool, output []bool) { // Get the bucket index to use bucketIdx := se.getFirstOnBit(input) //if len(bucketIdx) { //This shouldn't get hit // panic("Missing input value") //TODO output[0:self.n] = 0 TODO: should all 1s, or random SDR be returned instead? //} else { // The bucket index is the index of the first bit to set in the output output = output[:se.N] minbin := bucketIdx maxbin := minbin + 2*se.halfWidth if se.Periodic { // Handle the edges by computing wrap-around if maxbin >= se.N { bottombins := maxbin - se.N + 1 utils.FillSliceRangeBool(output, true, 0, bottombins) maxbin = se.N - 1 } if minbin < 0 { topbins := -minbin utils.FillSliceRangeBool(output, true, se.N-topbins, (se.N - (se.N - topbins))) minbin = 0 } } if minbin < 0 { panic("invalid minbin") } if maxbin >= se.N { panic("invalid maxbin") } // set the output (except for periodic wraparound) utils.FillSliceRangeBool(output, true, minbin, (maxbin+1)-minbin) if se.Verbosity >= 2 { fmt.Println("input:", input) fmt.Printf("half width:%v \n", se.Width) fmt.Printf("range: %v - %v \n", se.MinVal, se.MaxVal) fmt.Printf("n: %v width: %v resolution: %v \n", se.N, se.Width, se.Resolution) fmt.Printf("radius: %v periodic: %v \n", se.Radius, se.Periodic) fmt.Printf("output: %v \n", output) } //} }
func BoostTest(t *testing.T) { bt := boostTest{} spParams := NewSpParams() spParams.InputDimensions = []int{90} spParams.ColumnDimensions = []int{600} spParams.PotentialRadius = 90 spParams.PotentialPct = 0.9 spParams.GlobalInhibition = true spParams.NumActiveColumnsPerInhArea = 60 spParams.MinPctActiveDutyCycle = 0.1 spParams.SynPermActiveInc = 0 spParams.SynPermInactiveDec = 0 spParams.DutyCyclePeriod = 10 bt.sp = NewSpatialPooler(spParams) // Create a set of input vectors, x // B,C,D don't overlap at all with other patterns bt.x = make([][]bool, 5) for i := range bt.x { bt.x[i] = make([]bool, bt.sp.numInputs) } utils.FillSliceRangeBool(bt.x[0], true, 0, 20) utils.FillSliceRangeBool(bt.x[1], true, 10, 30) utils.FillSliceRangeBool(bt.x[2], true, 30, 50) utils.FillSliceRangeBool(bt.x[3], true, 50, 70) utils.FillSliceRangeBool(bt.x[4], true, 70, 90) // For each column, this will contain the last iteration number where that // column was a winner bt.winningIteration = make([]int, bt.sp.numColumns) // For each input vector i, lastSDR[i] contains the most recent SDR output // by the SP. bt.lastSDR = make([][]bool, 5) phase1(t, &bt) phase2(t, &bt) phase3(t, &bt) phase4(t, &bt) }
/* Decode an encoded sequence. Returns range of values */ func (se *ScalerEncoder) Decode(encoded []bool) []utils.TupleFloat { if !utils.AnyTrue(encoded) { return []utils.TupleFloat{} } tmpOutput := encoded[:se.N] // First, assume the input pool is not sampled 100%, and fill in the // "holes" in the encoded representation (which are likely to be present // if this is a coincidence that was learned by the SP). // Search for portions of the output that have "holes" maxZerosInARow := se.halfWidth for i := 0; i < maxZerosInARow; i++ { searchSeq := make([]bool, i+3) subLen := len(searchSeq) searchSeq[0] = true searchSeq[subLen-1] = true if se.Periodic { for j := 0; j < se.N; j++ { outputIndices := make([]int, subLen) for idx, _ := range outputIndices { outputIndices[idx] = (j + idx) % se.N } if utils.BoolEq(searchSeq, utils.SubsetSliceBool(tmpOutput, outputIndices)) { utils.SetIdxBool(tmpOutput, outputIndices, true) } } } else { for j := 0; j < se.N-subLen+1; j++ { if utils.BoolEq(searchSeq, tmpOutput[j:j+subLen]) { utils.FillSliceRangeBool(tmpOutput, true, j, subLen) } } } } if se.Verbosity >= 2 { fmt.Println("raw output:", utils.Bool2Int(encoded[:se.N])) fmt.Println("filtered output:", utils.Bool2Int(tmpOutput)) } // ------------------------------------------------------------------------ // Find each run of 1's in sequence nz := utils.OnIndices(tmpOutput) //key = start index, value = run length runs := make([]utils.TupleInt, 0, len(nz)) runStart := -1 runLen := 0 for idx, val := range tmpOutput { if val { //increment or new idx if runStart == -1 { runStart = idx runLen = 0 } runLen++ } else { if runStart != -1 { runs = append(runs, utils.TupleInt{runStart, runLen}) runStart = -1 } } } if runStart != -1 { runs = append(runs, utils.TupleInt{runStart, runLen}) runStart = -1 } // If we have a periodic encoder, merge the first and last run if they // both go all the way to the edges if se.Periodic && len(runs) > 1 { if runs[0].A == 0 && runs[len(runs)-1].A+runs[len(runs)-1].B == se.N { runs[len(runs)-1].B += runs[0].B runs = runs[1:] } } // ------------------------------------------------------------------------ // Now, for each group of 1's, determine the "left" and "right" edges, where // the "left" edge is inset by halfwidth and the "right" edge is inset by // halfwidth. // For a group of width w or less, the "left" and "right" edge are both at // the center position of the group. ranges := make([]utils.TupleFloat, 0, len(runs)+2) for _, val := range runs { var left, right int start := val.A length := val.B if length <= se.Width { right = start + length/2 left = right } else { left = start + se.halfWidth right = start + length - 1 - se.halfWidth } var inMin, inMax float64 // Convert to input space. if !se.Periodic { inMin = float64(left-se.padding)*se.Resolution + se.MinVal inMax = float64(right-se.padding)*se.Resolution + se.MinVal } else { inMin = float64(left-se.padding)*se.Range/float64(se.nInternal) + se.MinVal inMax = float64(right-se.padding)*se.Range/float64(se.nInternal) + se.MinVal } // Handle wrap-around if periodic if se.Periodic { if inMin >= se.MaxVal { inMin -= se.Range inMax -= se.Range } } // Clip low end if inMin < se.MinVal { inMin = se.MinVal } if inMax < se.MinVal { inMax = se.MinVal } // If we have a periodic encoder, and the max is past the edge, break into // 2 separate ranges if se.Periodic && inMax >= se.MaxVal { ranges = append(ranges, utils.TupleFloat{inMin, se.MaxVal}) ranges = append(ranges, utils.TupleFloat{se.MinVal, inMax - se.Range}) } else { //clip high end if inMax > se.MaxVal { inMax = se.MaxVal } if inMin > se.MaxVal { inMin = se.MaxVal } ranges = append(ranges, utils.TupleFloat{inMin, inMax}) } } //desc := se.generateRangeDescription(ranges) return ranges }