Open BryceBeagle opened 5 years ago
This is what was used for my AlphaGo reimplementation:
func RotateBoard(board []float32, m, n int) ([]float32, error) {
if m != n {
return nil, errors.Errorf("Cannot handle m %d, n %d. This function only takes square boards", m, n)
}
copied := make([]float32, len(board))
copy(copied, board)
it := MakeIterator(copied, m, n)
for i := 0; i < m/2; i++ {
mi1 := m - i - 1
for j := i; j < mi1; j++ {
mj1 := m - j - 1
tmp := it[i][j]
// right to top
it[i][j] = it[j][mi1]
// bottom to right
it[j][mi1] = it[mi1][mj1]
// left to bottom
it[mi1][mj1] = it[mj1][i]
// tmp is left
it[mj1][i] = tmp
}
}
ReturnIterator(m, n, it)
return copied, nil
}
func ReturnIterator(m, n int, it [][]float32) {
if d, ok := iterPool[m]; ok {
if _, ok := d[n]; ok {
iterPool[m][n].Put(it)
} else {
iterPool[m][n] = &sync.Pool{
New: func() interface{} {
retVal := make([][]float32, m)
for i := range retVal {
retVal[i] = make([]float32, n)
}
return retVal
},
}
iterPool[m][n].Put(it)
}
} else {
iterPool[m] = make(map[int]*sync.Pool)
iterPool[m][n] = &sync.Pool{
New: func() interface{} {
retVal := make([][]float32, m)
for i := range retVal {
retVal[i] = make([]float32, n)
}
return retVal
},
}
iterPool[m][n].Put(it)
}
}
func MakeIterator(board []float32, m, n int) (retVal [][]float32) {
retVal = borrowIterator(m, n)
for i := range retVal {
start := i * int(m)
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&retVal[i]))
hdr.Data = uintptr(unsafe.Pointer(&board[start]))
hdr.Len = int(n)
hdr.Cap = int(n)
}
return
}
func borrowIterator(m, n int) [][]float32 {
if d, ok := iterPool[m]; ok {
if d2, ok := d[n]; ok {
return d2.Get().([][]float32)
}
}
retVal := make([][]float32, m)
for i := range retVal {
retVal[i] = make([]float32, n)
}
return retVal
}
I agree it needs to be added. I don't quite have the bandwidth right now but these two snippets may be useful
I can take this issue. I am a newbie in terms of open-source collaboration so please bear with me :)
I might start with dense matrices first and then move on to tensors.
The rotate function can be implemented in dense_matop_memmove.go and/or dense_matop.go by allocating a new matrix and/or performing an "in-place" transformation, respectively.
Which implementation should I aim for first?
Note: The use of the term "in-place" is a slight abuse of notation
safety first, so memmove
- i.e. allocating a new matrix fist. then a unsafe version (i.e. in place).
Send PR :)
Numpy has a way to rotate matrices by increments of 90 degrees using their rot90 method that uses transposes and flips.
There is a transpose method for Tensors, but no way of flipping the Tensor that I see.
Is there a way of properly rotating a Tensor/Dense currently, other than through manual iteration over the data? If not, should this be added?