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 31 additions and 37 deletions
Showing only changes of commit 48d86fac56 - Show all commits

View File

@ -9,12 +9,6 @@ import space.kscience.kmath.nd.Strides
import kotlin.math.max import kotlin.math.max
internal fun offsetFromIndex(index: IntArray, shape: IntArray, strides: IntArray): Int =
index.mapIndexed { i, value ->
if (value < 0 || value >= shape[i]) throw IndexOutOfBoundsException("Index $value out of shape bounds: (0,${shape[i]})")
value * strides[i]
}.sum()
internal fun stridesFromShape(shape: IntArray): IntArray { internal fun stridesFromShape(shape: IntArray): IntArray {
val nDim = shape.size val nDim = shape.size
val res = IntArray(nDim) val res = IntArray(nDim)

View File

@ -241,7 +241,7 @@ internal fun DoubleLinearOpsTensorAlgebra.qrHelper(
} }
} }
} }
r[j, j] = DoubleAnalyticTensorAlgebra.invoke { (v dot v).sqrt().value() } r[j, j] = DoubleAnalyticTensorAlgebra { (v dot v).sqrt().value() }
for (i in 0 until n) { for (i in 0 until n) {
qM[i, j] = vv[i] / r[j, j] qM[i, j] = vv[i] / r[j, j]
} }

View File

@ -9,7 +9,7 @@ import kotlin.test.assertTrue
internal class TestBroadcasting { internal class TestBroadcasting {
@Test @Test
fun broadcastShapes() = DoubleTensorAlgebra.invoke { fun broadcastShapes() = DoubleTensorAlgebra {
assertTrue( assertTrue(
broadcastShapes( broadcastShapes(
intArrayOf(2, 3), intArrayOf(1, 3), intArrayOf(1, 1, 1) intArrayOf(2, 3), intArrayOf(1, 3), intArrayOf(1, 1, 1)
@ -24,7 +24,7 @@ internal class TestBroadcasting {
} }
@Test @Test
fun broadcastTo() = DoubleTensorAlgebra.invoke { fun broadcastTo() = DoubleTensorAlgebra {
val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) val tensor2 = fromArray(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0))
@ -34,7 +34,7 @@ internal class TestBroadcasting {
} }
@Test @Test
fun broadcastTensors() = DoubleTensorAlgebra.invoke { fun broadcastTensors() = DoubleTensorAlgebra {
val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) val tensor2 = fromArray(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0))
val tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) val tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0))
@ -51,7 +51,7 @@ internal class TestBroadcasting {
} }
@Test @Test
fun broadcastOuterTensors() = DoubleTensorAlgebra.invoke { fun broadcastOuterTensors() = DoubleTensorAlgebra {
val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) val tensor2 = fromArray(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0))
val tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) val tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0))
@ -68,7 +68,7 @@ internal class TestBroadcasting {
} }
@Test @Test
fun broadcastOuterTensorsShapes() = DoubleTensorAlgebra.invoke { fun broadcastOuterTensorsShapes() = DoubleTensorAlgebra {
val tensor1 = fromArray(intArrayOf(2, 1, 3, 2, 3), DoubleArray(2 * 1 * 3 * 2 * 3) {0.0}) val tensor1 = fromArray(intArrayOf(2, 1, 3, 2, 3), DoubleArray(2 * 1 * 3 * 2 * 3) {0.0})
val tensor2 = fromArray(intArrayOf(4, 2, 5, 1, 3, 3), DoubleArray(4 * 2 * 5 * 1 * 3 * 3) {0.0}) val tensor2 = fromArray(intArrayOf(4, 2, 5, 1, 3, 3), DoubleArray(4 * 2 * 5 * 1 * 3 * 3) {0.0})
val tensor3 = fromArray(intArrayOf(1, 1), doubleArrayOf(500.0)) val tensor3 = fromArray(intArrayOf(1, 1), doubleArrayOf(500.0))

View File

@ -27,7 +27,7 @@ internal class TestDoubleAnalyticTensorAlgebra {
} }
@Test @Test
fun testExp() = DoubleAnalyticTensorAlgebra.invoke { fun testExp() = DoubleAnalyticTensorAlgebra {
tensor.exp().let { tensor.exp().let {
assertTrue { shape contentEquals it.shape } assertTrue { shape contentEquals it.shape }
assertTrue { buffer.fmap(::exp).epsEqual(it.mutableBuffer.array())} assertTrue { buffer.fmap(::exp).epsEqual(it.mutableBuffer.array())}

View File

@ -10,7 +10,7 @@ import kotlin.test.assertTrue
internal class TestDoubleLinearOpsTensorAlgebra { internal class TestDoubleLinearOpsTensorAlgebra {
@Test @Test
fun testDetLU() = DoubleLinearOpsTensorAlgebra.invoke { fun testDetLU() = DoubleLinearOpsTensorAlgebra {
val tensor = fromArray( val tensor = fromArray(
intArrayOf(2, 2, 2), intArrayOf(2, 2, 2),
doubleArrayOf( doubleArrayOf(
@ -35,7 +35,7 @@ internal class TestDoubleLinearOpsTensorAlgebra {
} }
@Test @Test
fun testDet() = DoubleLinearOpsTensorAlgebra.invoke { fun testDet() = DoubleLinearOpsTensorAlgebra {
val expectedValue = 0.019827417 val expectedValue = 0.019827417
val m = fromArray( val m = fromArray(
intArrayOf(3, 3), doubleArrayOf( intArrayOf(3, 3), doubleArrayOf(
@ -49,7 +49,7 @@ internal class TestDoubleLinearOpsTensorAlgebra {
} }
@Test @Test
fun testDetSingle() = DoubleLinearOpsTensorAlgebra.invoke { fun testDetSingle() = DoubleLinearOpsTensorAlgebra {
val expectedValue = 48.151623 val expectedValue = 48.151623
val m = fromArray( val m = fromArray(
intArrayOf(1, 1), doubleArrayOf( intArrayOf(1, 1), doubleArrayOf(
@ -61,7 +61,7 @@ internal class TestDoubleLinearOpsTensorAlgebra {
} }
@Test @Test
fun testInvLU() = DoubleLinearOpsTensorAlgebra.invoke { fun testInvLU() = DoubleLinearOpsTensorAlgebra {
val tensor = fromArray( val tensor = fromArray(
intArrayOf(2, 2, 2), intArrayOf(2, 2, 2),
doubleArrayOf( doubleArrayOf(
@ -86,14 +86,14 @@ internal class TestDoubleLinearOpsTensorAlgebra {
} }
@Test @Test
fun testScalarProduct() = DoubleLinearOpsTensorAlgebra.invoke { fun testScalarProduct() = DoubleLinearOpsTensorAlgebra {
val a = fromArray(intArrayOf(3), doubleArrayOf(1.8, 2.5, 6.8)) val a = fromArray(intArrayOf(3), doubleArrayOf(1.8, 2.5, 6.8))
val b = fromArray(intArrayOf(3), doubleArrayOf(5.5, 2.6, 6.4)) val b = fromArray(intArrayOf(3), doubleArrayOf(5.5, 2.6, 6.4))
assertEquals(a.dot(b).value(), 59.92) assertEquals(a.dot(b).value(), 59.92)
} }
@Test @Test
fun testQR() = DoubleLinearOpsTensorAlgebra.invoke { fun testQR() = DoubleLinearOpsTensorAlgebra {
val shape = intArrayOf(2, 2, 2) val shape = intArrayOf(2, 2, 2)
val buffer = doubleArrayOf( val buffer = doubleArrayOf(
1.0, 3.0, 1.0, 3.0,
@ -114,7 +114,7 @@ internal class TestDoubleLinearOpsTensorAlgebra {
} }
@Test @Test
fun testLU() = DoubleLinearOpsTensorAlgebra.invoke { fun testLU() = DoubleLinearOpsTensorAlgebra {
val shape = intArrayOf(2, 2, 2) val shape = intArrayOf(2, 2, 2)
val buffer = doubleArrayOf( val buffer = doubleArrayOf(
1.0, 3.0, 1.0, 3.0,
@ -134,7 +134,7 @@ internal class TestDoubleLinearOpsTensorAlgebra {
} }
@Test @Test
fun testCholesky() = DoubleLinearOpsTensorAlgebra.invoke { fun testCholesky() = DoubleLinearOpsTensorAlgebra {
val tensor = randomNormal(intArrayOf(2, 5, 5), 0) val tensor = randomNormal(intArrayOf(2, 5, 5), 0)
val sigma = (tensor dot tensor.transpose()) + diagonalEmbedding( val sigma = (tensor dot tensor.transpose()) + diagonalEmbedding(
fromArray(intArrayOf(2, 5), DoubleArray(10) { 0.1 }) fromArray(intArrayOf(2, 5), DoubleArray(10) { 0.1 })
@ -145,7 +145,7 @@ internal class TestDoubleLinearOpsTensorAlgebra {
} }
@Test @Test
fun testSVD1D() = DoubleLinearOpsTensorAlgebra.invoke { fun testSVD1D() = DoubleLinearOpsTensorAlgebra {
val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val res = svd1d(tensor2) val res = svd1d(tensor2)
@ -156,13 +156,13 @@ internal class TestDoubleLinearOpsTensorAlgebra {
} }
@Test @Test
fun testSVD() = DoubleLinearOpsTensorAlgebra.invoke{ fun testSVD() = DoubleLinearOpsTensorAlgebra{
testSVDFor(fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))) testSVDFor(fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)))
testSVDFor(fromArray(intArrayOf(2, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0))) testSVDFor(fromArray(intArrayOf(2, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0)))
} }
@Test @Test
fun testBatchedSVD() = DoubleLinearOpsTensorAlgebra.invoke { fun testBatchedSVD() = DoubleLinearOpsTensorAlgebra {
val tensor = randomNormal(intArrayOf(2, 5, 3), 0) val tensor = randomNormal(intArrayOf(2, 5, 3), 0)
val (tensorU, tensorS, tensorV) = tensor.svd() val (tensorU, tensorS, tensorV) = tensor.svd()
val tensorSVD = tensorU dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) val tensorSVD = tensorU dot (diagonalEmbedding(tensorS) dot tensorV.transpose())
@ -170,7 +170,7 @@ internal class TestDoubleLinearOpsTensorAlgebra {
} }
@Test @Test
fun testBatchedSymEig() = DoubleLinearOpsTensorAlgebra.invoke { fun testBatchedSymEig() = DoubleLinearOpsTensorAlgebra {
val tensor = randomNormal(shape = intArrayOf(2, 3, 3), 0) val tensor = randomNormal(shape = intArrayOf(2, 3, 3), 0)
val tensorSigma = tensor + tensor.transpose() val tensorSigma = tensor + tensor.transpose()
val (tensorS, tensorV) = tensorSigma.symEig() val (tensorS, tensorV) = tensorSigma.symEig()

View File

@ -15,14 +15,14 @@ import kotlin.test.assertTrue
internal class TestDoubleTensor { internal class TestDoubleTensor {
@Test @Test
fun valueTest() = DoubleTensorAlgebra.invoke { fun valueTest() = DoubleTensorAlgebra {
val value = 12.5 val value = 12.5
val tensor = fromArray(intArrayOf(1), doubleArrayOf(value)) val tensor = fromArray(intArrayOf(1), doubleArrayOf(value))
assertEquals(tensor.value(), value) assertEquals(tensor.value(), value)
} }
@Test @Test
fun stridesTest() = DoubleTensorAlgebra.invoke { fun stridesTest() = DoubleTensorAlgebra {
val tensor = fromArray(intArrayOf(2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4)) val tensor = fromArray(intArrayOf(2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4))
assertEquals(tensor[intArrayOf(0, 1)], 5.8) assertEquals(tensor[intArrayOf(0, 1)], 5.8)
assertTrue( assertTrue(
@ -31,7 +31,7 @@ internal class TestDoubleTensor {
} }
@Test @Test
fun getTest() = DoubleTensorAlgebra.invoke { fun getTest() = DoubleTensorAlgebra {
val tensor = fromArray(intArrayOf(1, 2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4)) val tensor = fromArray(intArrayOf(1, 2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4))
val matrix = tensor[0].as2D() val matrix = tensor[0].as2D()
assertEquals(matrix[0, 1], 5.8) assertEquals(matrix[0, 1], 5.8)

View File

@ -10,21 +10,21 @@ import kotlin.test.assertTrue
internal class TestDoubleTensorAlgebra { internal class TestDoubleTensorAlgebra {
@Test @Test
fun doublePlus() = DoubleTensorAlgebra.invoke { fun doublePlus() = DoubleTensorAlgebra {
val tensor = fromArray(intArrayOf(2), doubleArrayOf(1.0, 2.0)) val tensor = fromArray(intArrayOf(2), doubleArrayOf(1.0, 2.0))
val res = 10.0 + tensor val res = 10.0 + tensor
assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(11.0, 12.0)) assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(11.0, 12.0))
} }
@Test @Test
fun doubleDiv() = DoubleTensorAlgebra.invoke { fun doubleDiv() = DoubleTensorAlgebra {
val tensor = fromArray(intArrayOf(2), doubleArrayOf(2.0, 4.0)) val tensor = fromArray(intArrayOf(2), doubleArrayOf(2.0, 4.0))
val res = 2.0/tensor val res = 2.0/tensor
assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 0.5)) assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 0.5))
} }
@Test @Test
fun divDouble() = DoubleTensorAlgebra.invoke { fun divDouble() = DoubleTensorAlgebra {
val tensor = fromArray(intArrayOf(2), doubleArrayOf(10.0, 5.0)) val tensor = fromArray(intArrayOf(2), doubleArrayOf(10.0, 5.0))
val res = tensor / 2.5 val res = tensor / 2.5
assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(4.0, 2.0)) assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(4.0, 2.0))
@ -40,7 +40,7 @@ internal class TestDoubleTensorAlgebra {
} }
@Test @Test
fun transpose3x2() = DoubleTensorAlgebra.invoke { fun transpose3x2() = DoubleTensorAlgebra {
val tensor = fromArray(intArrayOf(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor = fromArray(intArrayOf(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val res = tensor.transpose(1, 0) val res = tensor.transpose(1, 0)
@ -49,7 +49,7 @@ internal class TestDoubleTensorAlgebra {
} }
@Test @Test
fun transpose1x2x3() = DoubleTensorAlgebra.invoke { fun transpose1x2x3() = DoubleTensorAlgebra {
val tensor = fromArray(intArrayOf(1, 2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor = fromArray(intArrayOf(1, 2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val res01 = tensor.transpose(0, 1) val res01 = tensor.transpose(0, 1)
val res02 = tensor.transpose(-3, 2) val res02 = tensor.transpose(-3, 2)
@ -65,7 +65,7 @@ internal class TestDoubleTensorAlgebra {
} }
@Test @Test
fun linearStructure() = DoubleTensorAlgebra.invoke { fun linearStructure() = DoubleTensorAlgebra {
val shape = intArrayOf(3) val shape = intArrayOf(3)
val tensorA = full(value = -4.5, shape = shape) val tensorA = full(value = -4.5, shape = shape)
val tensorB = full(value = 10.9, shape = shape) val tensorB = full(value = 10.9, shape = shape)
@ -97,7 +97,7 @@ internal class TestDoubleTensorAlgebra {
} }
@Test @Test
fun dot() = DoubleTensorAlgebra.invoke { fun dot() = DoubleTensorAlgebra {
val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor11 = fromArray(intArrayOf(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor11 = fromArray(intArrayOf(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(intArrayOf(3), doubleArrayOf(10.0, 20.0, 30.0)) val tensor2 = fromArray(intArrayOf(3), doubleArrayOf(10.0, 20.0, 30.0))
@ -133,7 +133,7 @@ internal class TestDoubleTensorAlgebra {
} }
@Test @Test
fun diagonalEmbedding() = DoubleTensorAlgebra.invoke { fun diagonalEmbedding() = DoubleTensorAlgebra {
val tensor1 = fromArray(intArrayOf(3), doubleArrayOf(10.0, 20.0, 30.0)) val tensor1 = fromArray(intArrayOf(3), doubleArrayOf(10.0, 20.0, 30.0))
val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor3 = zeros(intArrayOf(2, 3, 4, 5)) val tensor3 = zeros(intArrayOf(2, 3, 4, 5))
@ -166,7 +166,7 @@ internal class TestDoubleTensorAlgebra {
} }
@Test @Test
fun testEq() = DoubleTensorAlgebra.invoke { fun testEq() = DoubleTensorAlgebra {
val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))
val tensor3 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 5.0)) val tensor3 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 5.0))