func (sp *SpatialPooler) getNeighborsND(columnIndex int, dimensions []int, radius int, wrapAround bool) []int { if len(dimensions) < 1 { panic("Dimensions empty") } bounds := append(dimensions[1:], 1) bounds = utils.RevCumProdInt(bounds) columnCoords := make([]int, len(bounds)) for j := 0; j < len(bounds); j++ { columnCoords[j] = utils.Mod(columnIndex/bounds[j], dimensions[j]) } rangeND := make([][]int, len(dimensions)) for i := 0; i < len(dimensions); i++ { if wrapAround { cRange := make([]int, (radius*2)+1) for j := 0; j < (2*radius)+1; j++ { cRange[j] = utils.Mod((columnCoords[i]-radius)+j, dimensions[i]) } rangeND[i] = cRange } else { var cRange []int for j := 0; j < (radius*2)+1; j++ { temp := columnCoords[i] - radius + j if temp >= 0 && temp < dimensions[i] { cRange = append(cRange, temp) } } rangeND[i] = cRange } } cp := utils.CartProductInt(rangeND) var neighbors []int for i := 0; i < len(cp); i++ { val := utils.DotInt(bounds, cp[i]) if val != columnIndex && !utils.ContainsInt(val, neighbors) { neighbors = append(neighbors, val) } } return neighbors }
func TestGetNeighborsND(t *testing.T) { sp := SpatialPooler{} dimensions := []int{5, 7, 2} var layout [5][7][2]int counter := 0 for i := range layout { for j := range layout[i] { for k := range layout[i][j] { layout[i][j][k] = counter counter++ } } } radius := 1 x := 1 y := 3 z := 2 columnIndex := layout[z][y][x] neighbors := sp.getNeighborsND(columnIndex, dimensions, radius, true) var expected []int for i := radius * -1; i <= radius; i++ { for j := radius * -1; j <= radius; j++ { for k := radius * -1; k <= radius; k++ { zprime := (z + i) % dimensions[0] yprime := (y + j) % dimensions[1] xprime := (x + k) % dimensions[2] if layout[zprime][yprime][xprime] != columnIndex && !utils.ContainsInt(layout[zprime][yprime][xprime], expected) { expected = append(expected, layout[zprime][yprime][xprime]) } } } } assert.Equal(t, expected, neighbors) dimensions = []int{5, 7, 9} var layoutb [5][7][9]int counter = 0 for i := range layoutb { for j := range layoutb[i] { for k := range layoutb[i][j] { layoutb[i][j][k] = counter counter++ } } } radius = 3 x = 0 y = 0 z = 3 columnIndex = layoutb[z][y][x] neighbors = sp.getNeighborsND(columnIndex, dimensions, radius, true) expected = []int{} for i := radius * -1; i <= radius; i++ { for j := radius * -1; j <= radius; j++ { for k := radius * -1; k <= radius; k++ { zprime := utils.Mod((z + i), (dimensions[0])) yprime := utils.Mod((y + j), (dimensions[1])) xprime := utils.Mod((x + k), (dimensions[2])) if layoutb[zprime][yprime][xprime] != columnIndex && !utils.ContainsInt(layoutb[zprime][yprime][xprime], expected) { expected = append(expected, layoutb[zprime][yprime][xprime]) } } } } assert.Equal(t, expected, neighbors) dimensions = []int{5, 10, 7, 6} var layoutc [5][10][7][6]int counter = 0 for i := range layoutc { for j := range layoutc[i] { for k := range layoutc[i][j] { for m := range layoutc[i][j][k] { layoutc[i][j][k][m] = counter counter++ } } } } radius = 4 w := 2 x = 5 y = 6 z = 2 columnIndex = layoutc[z][y][x][w] neighbors = sp.getNeighborsND(columnIndex, dimensions, radius, true) expected = []int{} for i := radius * -1; i <= radius; i++ { for j := radius * -1; j <= radius; j++ { for k := radius * -1; k <= radius; k++ { for m := radius * -1; m <= radius; m++ { zprime := utils.Mod((z + i), (dimensions[0])) yprime := utils.Mod((y + j), (dimensions[1])) xprime := utils.Mod((x + k), (dimensions[2])) wprime := utils.Mod((w + m), (dimensions[3])) if layoutc[zprime][yprime][xprime][wprime] != columnIndex && !utils.ContainsInt(layoutc[zprime][yprime][xprime][wprime], expected) { expected = append(expected, layoutc[zprime][yprime][xprime][wprime]) } } } } } assert.Equal(t, expected, neighbors) layoutd := []bool{false, false, true, false, true, false, false, false} columnIndex = 3 dimensions = []int{8} radius = 1 mask := sp.getNeighborsND(columnIndex, dimensions, radius, true) t.Log("mask", mask) for idx, val := range layoutd { if utils.ContainsInt(idx, mask) { assert.Equal(t, true, val) } else { assert.Equal(t, false, val) } } layoute := []bool{false, true, true, false, true, true, false, false} columnIndex = 3 dimensions = []int{8} radius = 2 mask = sp.getNeighborsND(columnIndex, dimensions, radius, true) t.Log("mask", mask) for idx, val := range layoute { if utils.ContainsInt(idx, mask) { assert.Equal(t, true, val) } else { assert.Equal(t, false, val) } } // Wrap around layoutf := []bool{false, true, true, false, false, false, true, true} columnIndex = 0 dimensions = []int{8} radius = 2 mask = sp.getNeighborsND(columnIndex, dimensions, radius, true) t.Log("mask", mask) for idx, val := range layoutf { if utils.ContainsInt(idx, mask) { assert.Equal(t, true, val) } else { assert.Equal(t, false, val) } } //Radius too big layoutg := []bool{true, true, true, true, true, true, false, true} columnIndex = 6 dimensions = []int{8} radius = 20 mask = sp.getNeighborsND(columnIndex, dimensions, radius, true) t.Log("mask", mask) for idx, val := range layoutg { if utils.ContainsInt(idx, mask) { assert.Equal(t, true, val) } else { assert.Equal(t, false, val) } } //These are all the same tests from 2D ints := [][]int{{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 1, 1, 1, 0}, {0, 1, 0, 1, 0}, {0, 1, 1, 1, 0}, {0, 0, 0, 0, 0}} layouth := NewDenseBinaryMatrixFromInts(ints) t.Log(layouth.ToString()) columnIndex = 3*5 + 2 dimensions = []int{6, 5} radius = 1 mask = sp.getNeighborsND(columnIndex, dimensions, radius, true) t.Log("mask", mask) t.Log("1d", layouth.Flatten()) for idx, val := range layouth.Flatten() { if utils.ContainsInt(idx, mask) { assert.Equal(t, true, val) } else { assert.Equal(t, false, val) } } ints = [][]int{{0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 0, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}} layoutj := NewDenseBinaryMatrixFromInts(ints) t.Log(layouth.ToString()) columnIndex = 3*5 + 2 radius = 2 mask = sp.getNeighborsND(columnIndex, dimensions, radius, true) t.Log("mask", mask) t.Log("1d", layouth.Flatten()) for idx, val := range layoutj.Flatten() { if utils.ContainsInt(idx, mask) { assert.Equal(t, true, val) } else { assert.Equal(t, false, val) } } //Radius too big ints = [][]int{{1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 0, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}} layoutk := NewDenseBinaryMatrixFromInts(ints) t.Log(layouth.ToString()) columnIndex = 3*5 + 2 radius = 7 mask = sp.getNeighborsND(columnIndex, dimensions, radius, true) t.Log("mask", mask) t.Log("1d", layoutk.Flatten()) for idx, val := range layoutk.Flatten() { if utils.ContainsInt(idx, mask) { assert.Equal(t, true, val) } else { assert.Equal(t, false, val) } } //Wrap-around ints = [][]int{{1, 0, 0, 1, 1}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {1, 0, 0, 1, 1}, {1, 0, 0, 1, 0}} layoutl := NewDenseBinaryMatrixFromInts(ints) t.Log(layoutl.ToString()) columnIndex = 29 radius = 1 mask = sp.getNeighborsND(columnIndex, dimensions, radius, true) t.Log("mask", mask) t.Log("1d", layoutl.Flatten()) for idx, val := range layoutl.Flatten() { if utils.ContainsInt(idx, mask) { assert.Equal(t, true, val) } else { assert.Equal(t, false, val) } } //No wrap around columnIndex = 8 radius = 2 dimensions = []int{10} neighbors = sp.getNeighborsND(columnIndex, dimensions, radius, false) expected = []int{6, 7, 9} assert.Equal(t, expected, neighbors) }