KMP library for tensors #300

Merged
grinisrit merged 215 commits from feature/tensor-algebra into dev 2021-05-08 09:48:04 +03:00
7 changed files with 48 additions and 45 deletions
Showing only changes of commit 39a0889123 - Show all commits

View File

@ -32,7 +32,7 @@ public interface LinearOpsTensorAlgebra<T, TensorType : TensorStructure<T>> :
public fun TensorType.lu(): Pair<TensorType, IntTensor>
//https://pytorch.org/docs/stable/generated/torch.lu_unpack.html
public fun luPivot(aLU: TensorType, pivots: IntTensor): Triple<TensorType, TensorType, TensorType>
public fun luPivot(lu: TensorType, pivots: IntTensor): Triple<TensorType, TensorType, TensorType>
//https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd
public fun TensorType.svd(): Triple<TensorType, TensorType, TensorType>

View File

@ -144,5 +144,7 @@ public class RealAnalyticTensorAlgebra:
TODO("Not yet implemented")
}
}
}
public inline fun <R> RealAnalyticTensorAlgebra(block: RealTensorAlgebra.() -> R): R =
RealAnalyticTensorAlgebra().block()

View File

@ -1,6 +1,7 @@
package space.kscience.kmath.tensors
import space.kscience.kmath.structures.array
import space.kscience.kmath.structures.toDoubleArray
import space.kscience.kmath.structures.toIntArray
public class RealLinearOpsTensorAlgebra :
LinearOpsTensorAlgebra<Double, RealTensor>,
@ -80,7 +81,7 @@ public class RealLinearOpsTensorAlgebra :
// todo checks
val n = lu.shape[0]
val p = lu.zeroesLike()
pivots.buffer.array.forEachIndexed { i, pivot ->
pivots.buffer.toIntArray().forEachIndexed { i, pivot ->
p[i, pivot] = 1.0
}
val l = lu.zeroesLike()
@ -130,4 +131,4 @@ public class RealLinearOpsTensorAlgebra :
}
public inline fun <R> RealLinearOpsTensorAlgebra(block: RealTensorAlgebra.() -> R): R =
RealTensorAlgebra().block()
RealLinearOpsTensorAlgebra().block()

View File

@ -1,6 +1,6 @@
package space.kscience.kmath.tensors
import space.kscience.kmath.structures.array
import space.kscience.kmath.structures.toDoubleArray
public open class RealTensorAlgebra : TensorPartialDivisionAlgebra<Double, RealTensor> {
@ -9,7 +9,7 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra<Double, RealT
check(this.shape contentEquals intArrayOf(1)) {
"Inconsistent value for tensor of shape ${shape.toList()}"
}
return this.buffer.array[0]
return this.buffer.toDoubleArray()[0]
}
override fun zeros(shape: IntArray): RealTensor {
@ -32,13 +32,13 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra<Double, RealT
override fun RealTensor.copy(): RealTensor {
// should be rework as soon as copy() method for NDBuffer will be available
return RealTensor(this.shape, this.buffer.array.copyOf())
return RealTensor(this.shape, this.buffer.toDoubleArray().copyOf())
}
override fun Double.plus(other: RealTensor): RealTensor {
val resBuffer = DoubleArray(other.buffer.size) { i ->
other.buffer.array[i] + this
other.buffer.toDoubleArray()[i] + this
}
return RealTensor(other.shape, resBuffer)
}
@ -50,34 +50,34 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra<Double, RealT
val newThis = broadcast[0]
val newOther = broadcast[1]
val resBuffer = DoubleArray(newThis.buffer.size) { i ->
newThis.buffer.array[i] + newOther.buffer.array[i]
newThis.buffer.toDoubleArray()[i] + newOther.buffer.toDoubleArray()[i]
}
return RealTensor(newThis.shape, resBuffer)
}
override fun RealTensor.plusAssign(value: Double) {
for (i in this.buffer.array.indices) {
this.buffer.array[i] += value
for (i in this.buffer.toDoubleArray().indices) {
this.buffer.toDoubleArray()[i] += value
}
}
override fun RealTensor.plusAssign(other: RealTensor) {
//todo should be change with broadcasting
for (i in this.buffer.array.indices) {
this.buffer.array[i] += other.buffer.array[i]
for (i in this.buffer.toDoubleArray().indices) {
this.buffer.toDoubleArray()[i] += other.buffer.toDoubleArray()[i]
}
}
override fun Double.minus(other: RealTensor): RealTensor {
val resBuffer = DoubleArray(other.buffer.size) { i ->
this - other.buffer.array[i]
this - other.buffer.toDoubleArray()[i]
}
return RealTensor(other.shape, resBuffer)
}
override fun RealTensor.minus(value: Double): RealTensor {
val resBuffer = DoubleArray(this.buffer.size) { i ->
this.buffer.array[i] - value
this.buffer.toDoubleArray()[i] - value
}
return RealTensor(this.shape, resBuffer)
}
@ -87,14 +87,14 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra<Double, RealT
val newThis = broadcast[0]
val newOther = broadcast[1]
val resBuffer = DoubleArray(newThis.buffer.size) { i ->
newThis.buffer.array[i] - newOther.buffer.array[i]
newThis.buffer.toDoubleArray()[i] - newOther.buffer.toDoubleArray()[i]
}
return RealTensor(newThis.shape, resBuffer)
}
override fun RealTensor.minusAssign(value: Double) {
for (i in this.buffer.array.indices) {
this.buffer.array[i] -= value
for (i in this.buffer.toDoubleArray().indices) {
this.buffer.toDoubleArray()[i] -= value
}
}
@ -105,7 +105,7 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra<Double, RealT
override fun Double.times(other: RealTensor): RealTensor {
//todo should be change with broadcasting
val resBuffer = DoubleArray(other.buffer.size) { i ->
other.buffer.array[i] * this
other.buffer.toDoubleArray()[i] * this
}
return RealTensor(other.shape, resBuffer)
}
@ -116,28 +116,28 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra<Double, RealT
override fun RealTensor.times(other: RealTensor): RealTensor {
//todo should be change with broadcasting
val resBuffer = DoubleArray(this.buffer.size) { i ->
this.buffer.array[i] * other.buffer.array[i]
this.buffer.toDoubleArray()[i] * other.buffer.toDoubleArray()[i]
}
return RealTensor(this.shape, resBuffer)
}
override fun RealTensor.timesAssign(value: Double) {
//todo should be change with broadcasting
for (i in this.buffer.array.indices) {
this.buffer.array[i] *= value
for (i in this.buffer.toDoubleArray().indices) {
this.buffer.toDoubleArray()[i] *= value
}
}
override fun RealTensor.timesAssign(other: RealTensor) {
//todo should be change with broadcasting
for (i in this.buffer.array.indices) {
this.buffer.array[i] *= other.buffer.array[i]
for (i in this.buffer.toDoubleArray().indices) {
this.buffer.toDoubleArray()[i] *= other.buffer.toDoubleArray()[i]
}
}
override fun RealTensor.unaryMinus(): RealTensor {
val resBuffer = DoubleArray(this.buffer.size) { i ->
this.buffer.array[i].unaryMinus()
this.buffer.toDoubleArray()[i].unaryMinus()
}
return RealTensor(this.shape, resBuffer)
}
@ -158,14 +158,14 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra<Double, RealT
newMultiIndex[i] = newMultiIndex[j].also { newMultiIndex[j] = newMultiIndex[i] }
val linearIndex = resTensor.strides.offset(newMultiIndex)
resTensor.buffer.array[linearIndex] = this.buffer.array[offset]
resTensor.buffer.toDoubleArray()[linearIndex] = this.buffer.toDoubleArray()[offset]
}
return resTensor
}
override fun RealTensor.view(shape: IntArray): RealTensor {
return RealTensor(shape, this.buffer.array)
return RealTensor(shape, this.buffer.toDoubleArray())
}
override fun RealTensor.viewAs(other: RealTensor): RealTensor {

View File

@ -1,6 +1,6 @@
package space.kscience.kmath.tensors
import space.kscience.kmath.structures.array
import space.kscience.kmath.structures.toDoubleArray
import kotlin.math.max
@ -55,7 +55,7 @@ internal inline fun broadcastTensors(vararg tensors: RealTensor): List<RealTenso
}
val curLinearIndex = tensor.strides.offset(curMultiIndex)
resTensor.buffer.array[linearIndex] = tensor.buffer.array[curLinearIndex]
resTensor.buffer.toDoubleArray()[linearIndex] = tensor.buffer.toDoubleArray()[curLinearIndex]
}
res.add(resTensor)
}

View File

@ -1,7 +1,7 @@
package space.kscience.kmath.tensors
import space.kscience.kmath.structures.array
import space.kscience.kmath.structures.toDoubleArray
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
@ -19,6 +19,6 @@ class TestRealTensor {
fun stridesTest(){
val tensor = RealTensor(intArrayOf(2,2), doubleArrayOf(3.5,5.8,58.4,2.4))
assertEquals(tensor[intArrayOf(0,1)], 5.8)
assertTrue(tensor.elements().map{ it.second }.toList().toDoubleArray() contentEquals tensor.buffer.array)
assertTrue(tensor.elements().map{ it.second }.toList().toDoubleArray() contentEquals tensor.buffer.toDoubleArray())
}
}

View File

@ -1,6 +1,6 @@
package space.kscience.kmath.tensors
import space.kscience.kmath.structures.array
import space.kscience.kmath.structures.toDoubleArray
import kotlin.test.Test
import kotlin.test.assertTrue
@ -10,7 +10,7 @@ class TestRealTensorAlgebra {
fun doublePlus() = RealTensorAlgebra {
val tensor = RealTensor(intArrayOf(2), doubleArrayOf(1.0, 2.0))
val res = 10.0 + tensor
assertTrue(res.buffer.array contentEquals doubleArrayOf(11.0,12.0))
assertTrue(res.buffer.toDoubleArray() contentEquals doubleArrayOf(11.0,12.0))
}
@Test
@ -18,7 +18,7 @@ class TestRealTensorAlgebra {
val tensor = RealTensor(intArrayOf(1), doubleArrayOf(0.0))
val res = tensor.transpose(0, 0)
assertTrue(res.buffer.array contentEquals doubleArrayOf(0.0))
assertTrue(res.buffer.toDoubleArray() contentEquals doubleArrayOf(0.0))
assertTrue(res.shape contentEquals intArrayOf(1))
}
@ -27,7 +27,7 @@ class TestRealTensorAlgebra {
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.buffer.toDoubleArray() contentEquals doubleArrayOf(1.0, 3.0, 5.0, 2.0, 4.0, 6.0))
assertTrue(res.shape contentEquals intArrayOf(2, 3))
}
@ -42,9 +42,9 @@ class TestRealTensorAlgebra {
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))
assertTrue(res01.buffer.toDoubleArray() contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
assertTrue(res02.buffer.toDoubleArray() contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0))
assertTrue(res12.buffer.toDoubleArray() contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0))
}
@Test
@ -70,9 +70,9 @@ class TestRealTensorAlgebra {
assertTrue(res[1].shape contentEquals intArrayOf(1, 2, 3))
assertTrue(res[2].shape contentEquals intArrayOf(1, 2, 3))
assertTrue(res[0].buffer.array contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
assertTrue(res[1].buffer.array contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0))
assertTrue(res[2].buffer.array contentEquals doubleArrayOf(500.0, 500.0, 500.0, 500.0, 500.0, 500.0))
assertTrue(res[0].buffer.toDoubleArray() contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
assertTrue(res[1].buffer.toDoubleArray() contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0))
assertTrue(res[2].buffer.toDoubleArray() contentEquals doubleArrayOf(500.0, 500.0, 500.0, 500.0, 500.0, 500.0))
}
@Test
@ -82,14 +82,14 @@ class TestRealTensorAlgebra {
val tensor3 = RealTensor(intArrayOf(1, 1, 1), doubleArrayOf(500.0))
assertTrue((tensor2 - tensor1).shape contentEquals intArrayOf(2, 3))
assertTrue((tensor2 - tensor1).buffer.array contentEquals doubleArrayOf(9.0, 18.0, 27.0, 6.0, 15.0, 24.0))
assertTrue((tensor2 - tensor1).buffer.toDoubleArray() contentEquals doubleArrayOf(9.0, 18.0, 27.0, 6.0, 15.0, 24.0))
assertTrue((tensor3 - tensor1).shape contentEquals intArrayOf(1, 2, 3))
assertTrue((tensor3 - tensor1).buffer.array
assertTrue((tensor3 - tensor1).buffer.toDoubleArray()
contentEquals doubleArrayOf(499.0, 498.0, 497.0, 496.0, 495.0, 494.0))
assertTrue((tensor3 - tensor2).shape contentEquals intArrayOf(1, 1, 3))
assertTrue((tensor3 - tensor2).buffer.array contentEquals doubleArrayOf(490.0, 480.0, 470.0))
assertTrue((tensor3 - tensor2).buffer.toDoubleArray() contentEquals doubleArrayOf(490.0, 480.0, 470.0))
}
}