Add functions transpose and transposeAssign #225

Merged
AlyaNovikova merged 1 commits from feature/tensor-algebra into feature/tensor-algebra 2021-03-12 00:09:09 +03:00
4 changed files with 104 additions and 2 deletions
Showing only changes of commit 723e0e458e - Show all commits

View File

@ -174,6 +174,11 @@ public interface Strides {
*/ */
public fun index(offset: Int): IntArray public fun index(offset: Int): IntArray
/**
* Get next multidimensional index from the current multidimensional index
*/
public fun nextIndex(index: IntArray): IntArray
/** /**
* The size of linear buffer to accommodate all elements of ND-structure corresponding to strides * The size of linear buffer to accommodate all elements of ND-structure corresponding to strides
*/ */
@ -232,6 +237,10 @@ public class DefaultStrides private constructor(override val shape: IntArray) :
return res return res
} }
override fun nextIndex(index: IntArray): IntArray {
TODO("Not yet implemented")
}
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other !is DefaultStrides) return false if (other !is DefaultStrides) return false

View File

@ -164,11 +164,33 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra<Double, RealTensor
} }
override fun RealTensor.transpose(i: Int, j: Int): RealTensor { override fun RealTensor.transpose(i: Int, j: Int): RealTensor {
TODO("Alya") val n = this.buffer.size
val resBuffer = DoubleArray(n)
val resShape = this.shape.copyOf()
resShape[i] = resShape[j].also { resShape[j] = resShape[i] }
val resTensor = RealTensor(resShape, resBuffer)
for (offset in 0 until n) {
val oldMultiIndex = this.strides.index(offset)
val newMultiIndex = oldMultiIndex.copyOf()
newMultiIndex[i] = newMultiIndex[j].also { newMultiIndex[j] = newMultiIndex[i] }
val linearIndex = resTensor.strides.offset(newMultiIndex)
resTensor.buffer.array[linearIndex] = this.buffer.array[offset]
}
return resTensor
} }
override fun RealTensor.transposeAssign(i: Int, j: Int) { override fun RealTensor.transposeAssign(i: Int, j: Int) {
TODO("Alya") val transposedTensor = this.transpose(i, j)
for (i in transposedTensor.shape.indices) {
this.shape[i] = transposedTensor.shape[i]
}
for (i in transposedTensor.buffer.array.indices) {
this.buffer.array[i] = transposedTensor.buffer.array[i]
}
} }
override fun RealTensor.view(shape: IntArray): RealTensor { override fun RealTensor.view(shape: IntArray): RealTensor {

View File

@ -35,6 +35,23 @@ public inline fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): In
return res return res
} }
public inline fun nextIndex(index: IntArray, shape: IntArray, nDim: Int): IntArray {
val res = index.copyOf()
var current = nDim - 1
var carry = 0
do {
res[current]++
if (res[current] >= shape[current]) {
carry = 1
res[current] = 0
}
current--
} while(carry != 0 && current >= 0)
return res
}
public class TensorStrides(override val shape: IntArray): Strides public class TensorStrides(override val shape: IntArray): Strides
@ -47,6 +64,9 @@ public class TensorStrides(override val shape: IntArray): Strides
override fun index(offset: Int): IntArray = override fun index(offset: Int): IntArray =
indexFromOffset(offset, strides, shape.size) indexFromOffset(offset, strides, shape.size)
override fun nextIndex(index: IntArray): IntArray =
nextIndex(index, shape, shape.size)
override val linearSize: Int override val linearSize: Int
get() = shape.reduce(Int::times) get() = shape.reduce(Int::times)
} }

View File

@ -13,4 +13,55 @@ class TestRealTensorAlgebra {
assertTrue(res.buffer.array contentEquals doubleArrayOf(11.0,12.0)) assertTrue(res.buffer.array contentEquals doubleArrayOf(11.0,12.0))
} }
@Test
fun transpose1x1() = RealTensorAlgebra {
val tensor = RealTensor(intArrayOf(1), doubleArrayOf(0.0))
val res = tensor.transpose(0, 0)
assertTrue(res.buffer.array contentEquals doubleArrayOf(0.0))
assertTrue(res.shape contentEquals intArrayOf(1))
}
@Test
fun transpose3x2() = RealTensorAlgebra {
val tensor = RealTensor(intArrayOf(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val res = tensor.transpose(1, 0)
assertTrue(res.buffer.array contentEquals doubleArrayOf(1.0, 3.0, 5.0, 2.0, 4.0, 6.0))
assertTrue(res.shape contentEquals intArrayOf(2, 3))
}
@Test
fun transpose1x2x3() = RealTensorAlgebra {
val tensor = RealTensor(intArrayOf(1, 2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val res01 = tensor.transpose(0, 1)
val res02 = tensor.transpose(0, 2)
val res12 = tensor.transpose(1, 2)
assertTrue(res01.shape contentEquals intArrayOf(2, 1, 3))
assertTrue(res02.shape contentEquals intArrayOf(3, 2, 1))
assertTrue(res12.shape contentEquals intArrayOf(1, 3, 2))
assertTrue(res01.buffer.array contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
assertTrue(res02.buffer.array contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0))
assertTrue(res12.buffer.array contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0))
}
@Test
fun transposeAssign1x2() = RealTensorAlgebra {
val tensor = RealTensor(intArrayOf(1,2), doubleArrayOf(1.0, 2.0))
tensor.transposeAssign(0, 1)
assertTrue(tensor.buffer.array contentEquals doubleArrayOf(1.0, 2.0))
assertTrue(tensor.shape contentEquals intArrayOf(2, 1))
}
@Test
fun transposeAssign2x3() = RealTensorAlgebra {
val tensor = RealTensor(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
tensor.transposeAssign(1, 0)
assertTrue(tensor.buffer.array contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0))
assertTrue(tensor.shape contentEquals intArrayOf(3, 2))
}
} }