From 835d64d797411141a1b21948566651d6dace882e Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Sat, 16 Jan 2021 19:29:47 +0000 Subject: [PATCH 001/178] Initial draft for TensorAlgebra --- .gitignore | 1 + .../kmath/structures/TensorAlgebra.kt | 49 +++++++++++++++++++ .../kmath/structures/TensorStructure.kt | 11 +++++ 3 files changed, 61 insertions(+) create mode 100644 kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorAlgebra.kt create mode 100644 kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorStructure.kt diff --git a/.gitignore b/.gitignore index bade7f08c..ea8e65fb4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ build/ out/ .idea/ +.vscode/ # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) !gradle-wrapper.jar diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorAlgebra.kt new file mode 100644 index 000000000..f960742ee --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorAlgebra.kt @@ -0,0 +1,49 @@ +package kscience.kmath.structures + + +import kscience.kmath.operations.* + +public interface TensorAlgebra> : Ring { + + public operator fun T.plus(other: TorchTensorType): TorchTensorType + public operator fun TorchTensorType.plus(value: T): TorchTensorType + public operator fun TorchTensorType.plusAssign(value: T): Unit + public operator fun TorchTensorType.plusAssign(b: TorchTensorType): Unit + + public operator fun T.minus(other: TorchTensorType): TorchTensorType + public operator fun TorchTensorType.minus(value: T): TorchTensorType + public operator fun TorchTensorType.minusAssign(value: T): Unit + public operator fun TorchTensorType.minusAssign(b: TorchTensorType): Unit + + public operator fun T.times(other: TorchTensorType): TorchTensorType + public operator fun TorchTensorType.times(value: T): TorchTensorType + public operator fun TorchTensorType.timesAssign(value: T): Unit + public operator fun TorchTensorType.timesAssign(b: TorchTensorType): Unit + + public infix fun TorchTensorType.dot(b: TorchTensorType): TorchTensorType + + public fun diagonalEmbedding( + diagonalEntries: TorchTensorType, + offset: Int = 0, dim1: Int = -2, dim2: Int = -1 + ): TorchTensorType + + public fun TorchTensorType.transpose(i: Int, j: Int): TorchTensorType + public fun TorchTensorType.view(shape: IntArray): TorchTensorType + + public fun TorchTensorType.abs(): TorchTensorType + public fun TorchTensorType.sum(): TorchTensorType + +} + +public interface TensorFieldAlgebra> : + TensorAlgebra, Field { + + public operator fun TorchTensorType.divAssign(b: TorchTensorType) + + public fun TorchTensorType.exp(): TorchTensorType + public fun TorchTensorType.log(): TorchTensorType + + public fun TorchTensorType.svd(): Triple + public fun TorchTensorType.symEig(eigenvectors: Boolean = true): Pair + +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorStructure.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorStructure.kt new file mode 100644 index 000000000..6e3ac0b7b --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorStructure.kt @@ -0,0 +1,11 @@ +package kscience.kmath.structures + +public abstract class TensorStructure: MutableNDStructure { + + // A tensor can have empty shape, in which case it represents just a value + public abstract fun value(): T + + // Tensors are mutable and might hold shared resources + override fun equals(other: Any?): Boolean = false + override fun hashCode(): Int = 0 +} \ No newline at end of file From ecf813803b04f55b602ad50d23d53d13e0b300cb Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Mon, 18 Jan 2021 07:57:13 +0000 Subject: [PATCH 002/178] Correcting terminology and failed connection to Algebra --- .gitignore | 3 + .../kmath/structures/TensorAlgebra.kt | 99 +++++++++++-------- .../kmath/structures/TensorStructure.kt | 11 --- 3 files changed, 62 insertions(+), 51 deletions(-) delete mode 100644 kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorStructure.kt diff --git a/.gitignore b/.gitignore index ea8e65fb4..f32005cd2 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ out/ # Cache of project .gradletasknamecache + +# Generated by javac -h +*.class \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorAlgebra.kt index f960742ee..ca7619429 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorAlgebra.kt @@ -1,49 +1,68 @@ package kscience.kmath.structures - -import kscience.kmath.operations.* - -public interface TensorAlgebra> : Ring { - - public operator fun T.plus(other: TorchTensorType): TorchTensorType - public operator fun TorchTensorType.plus(value: T): TorchTensorType - public operator fun TorchTensorType.plusAssign(value: T): Unit - public operator fun TorchTensorType.plusAssign(b: TorchTensorType): Unit - - public operator fun T.minus(other: TorchTensorType): TorchTensorType - public operator fun TorchTensorType.minus(value: T): TorchTensorType - public operator fun TorchTensorType.minusAssign(value: T): Unit - public operator fun TorchTensorType.minusAssign(b: TorchTensorType): Unit - - public operator fun T.times(other: TorchTensorType): TorchTensorType - public operator fun TorchTensorType.times(value: T): TorchTensorType - public operator fun TorchTensorType.timesAssign(value: T): Unit - public operator fun TorchTensorType.timesAssign(b: TorchTensorType): Unit - - public infix fun TorchTensorType.dot(b: TorchTensorType): TorchTensorType - - public fun diagonalEmbedding( - diagonalEntries: TorchTensorType, - offset: Int = 0, dim1: Int = -2, dim2: Int = -1 - ): TorchTensorType - - public fun TorchTensorType.transpose(i: Int, j: Int): TorchTensorType - public fun TorchTensorType.view(shape: IntArray): TorchTensorType - - public fun TorchTensorType.abs(): TorchTensorType - public fun TorchTensorType.sum(): TorchTensorType - +public interface TensorStructure : MutableNDStructure { + // A tensor can have empty shape, in which case it represents just a value + public abstract fun value(): T } -public interface TensorFieldAlgebra> : - TensorAlgebra, Field { +// https://proofwiki.org/wiki/Definition:Algebra_over_Ring - public operator fun TorchTensorType.divAssign(b: TorchTensorType) +public interface TensorAlgebra> { - public fun TorchTensorType.exp(): TorchTensorType - public fun TorchTensorType.log(): TorchTensorType + public operator fun T.plus(other: TensorType): TensorType + public operator fun TensorType.plus(value: T): TensorType + public operator fun TensorType.plus(other: TensorType): TensorType + public operator fun TensorType.plusAssign(value: T): Unit + public operator fun TensorType.plusAssign(other: TensorType): Unit - public fun TorchTensorType.svd(): Triple - public fun TorchTensorType.symEig(eigenvectors: Boolean = true): Pair + public operator fun T.minus(other: TensorType): TensorType + public operator fun TensorType.minus(value: T): TensorType + public operator fun TensorType.minus(other: TensorType): TensorType + public operator fun TensorType.minusAssign(value: T): Unit + public operator fun TensorType.minusAssign(other: TensorType): Unit + + public operator fun T.times(other: TensorType): TensorType + public operator fun TensorType.times(value: T): TensorType + public operator fun TensorType.times(other: TensorType): TensorType + public operator fun TensorType.timesAssign(value: T): Unit + public operator fun TensorType.timesAssign(other: TensorType): Unit + public operator fun TensorType.unaryMinus(): TensorType + + + public infix fun TensorType.dot(other: TensorType): TensorType + public infix fun TensorType.dotAssign(other: TensorType): Unit + public infix fun TensorType.dotRightAssign(other: TensorType): Unit + + public fun diagonalEmbedding( + diagonalEntries: TensorType, + offset: Int = 0, dim1: Int = -2, dim2: Int = -1 + ): TensorType + + public fun TensorType.transpose(i: Int, j: Int): TensorType + public fun TensorType.transposeAssign(i: Int, j: Int): Unit + + public fun TensorType.view(shape: IntArray): TensorType + + public fun TensorType.abs(): TensorType + public fun TensorType.absAssign(): Unit + public fun TensorType.sum(): TensorType + public fun TensorType.sumAssign(): Unit +} + +// https://proofwiki.org/wiki/Definition:Division_Algebra + +public interface TensorPartialDivisionAlgebra> : + TensorAlgebra { + + public operator fun TensorType.div(other: TensorType): TensorType + public operator fun TensorType.divAssign(other: TensorType) + + public fun TensorType.exp(): TensorType + public fun TensorType.expAssign(): Unit + public fun TensorType.log(): TensorType + public fun TensorType.logAssign(): Unit + + public fun TensorType.svd(): Triple + public fun TensorType.symEig(eigenvectors: Boolean = true): Pair } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorStructure.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorStructure.kt deleted file mode 100644 index 6e3ac0b7b..000000000 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorStructure.kt +++ /dev/null @@ -1,11 +0,0 @@ -package kscience.kmath.structures - -public abstract class TensorStructure: MutableNDStructure { - - // A tensor can have empty shape, in which case it represents just a value - public abstract fun value(): T - - // Tensors are mutable and might hold shared resources - override fun equals(other: Any?): Boolean = false - override fun hashCode(): Int = 0 -} \ No newline at end of file From 360e0e17e94d997088915fda214a663a0928bfb9 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 19 Jan 2021 22:24:42 +0300 Subject: [PATCH 003/178] Minor optimization for RealNDAlgebra --- .../ast/ExpressionsInterpretersBenchmark.kt | 4 +- .../kscience/kmath/benchmarks/DotBenchmark.kt | 20 ++++----- .../kmath/benchmarks/LargeNDBenchmark.kt | 25 ----------- .../benchmarks/LinearAlgebraBenchmark.kt | 8 +--- .../FunctionalExpressionAlgebra.kt | 5 ++- .../kscience/kmath/linear/LupDecomposition.kt | 1 + .../kscience/kmath/operations/Complex.kt | 2 + .../kscience/kmath/structures/RealNDField.kt | 41 +++++++++---------- .../kscience/kmath/linear/MatrixTest.kt | 1 + .../kmath/structures/NumberNDFieldTest.kt | 1 + .../kscience/dimensions/DMatrixContextTest.kt | 1 + 11 files changed, 42 insertions(+), 67 deletions(-) delete mode 100644 examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LargeNDBenchmark.kt diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt index 6acaca84d..c5edcdedf 100644 --- a/examples/src/benchmarks/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt +++ b/examples/src/benchmarks/kotlin/kscience/kmath/ast/ExpressionsInterpretersBenchmark.kt @@ -28,7 +28,7 @@ internal class ExpressionsInterpretersBenchmark { @Benchmark fun mstExpression() { val expr = algebra.mstInField { - symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0) + symbol("x") * 2.0 + 2.0 / symbol("x") - 16.0 } invokeAndSum(expr) @@ -37,7 +37,7 @@ internal class ExpressionsInterpretersBenchmark { @Benchmark fun asmExpression() { val expr = algebra.mstInField { - symbol("x") * number(2.0) + number(2.0) / symbol("x") - number(16.0) + symbol("x") * 2.0 + 2.0 / symbol("x") - 16.0 }.compile() invokeAndSum(expr) diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/DotBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/DotBenchmark.kt index 8823e86db..5c59afaee 100644 --- a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/DotBenchmark.kt @@ -2,9 +2,8 @@ package kscience.kmath.benchmarks import kotlinx.benchmark.Benchmark import kscience.kmath.commons.linear.CMMatrixContext -import kscience.kmath.commons.linear.toCM import kscience.kmath.ejml.EjmlMatrixContext -import kscience.kmath.ejml.toEjml + import kscience.kmath.linear.BufferMatrixContext import kscience.kmath.linear.RealMatrixContext import kscience.kmath.linear.real @@ -26,11 +25,11 @@ class DotBenchmark { val matrix1 = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } val matrix2 = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } - val cmMatrix1 = matrix1.toCM() - val cmMatrix2 = matrix2.toCM() + val cmMatrix1 = CMMatrixContext { matrix1.toCM() } + val cmMatrix2 = CMMatrixContext { matrix2.toCM() } - val ejmlMatrix1 = matrix1.toEjml() - val ejmlMatrix2 = matrix2.toEjml() + val ejmlMatrix1 = EjmlMatrixContext { matrix1.toEjml() } + val ejmlMatrix2 = EjmlMatrixContext { matrix2.toEjml() } } @Benchmark @@ -49,22 +48,23 @@ class DotBenchmark { @Benchmark fun ejmlMultiplicationwithConversion() { - val ejmlMatrix1 = matrix1.toEjml() - val ejmlMatrix2 = matrix2.toEjml() EjmlMatrixContext { + val ejmlMatrix1 = matrix1.toEjml() + val ejmlMatrix2 = matrix2.toEjml() + ejmlMatrix1 dot ejmlMatrix2 } } @Benchmark fun bufferedMultiplication() { - BufferMatrixContext(RealField, Buffer.Companion::real).invoke{ + BufferMatrixContext(RealField, Buffer.Companion::real).invoke { matrix1 dot matrix2 } } @Benchmark - fun realMultiplication(){ + fun realMultiplication() { RealMatrixContext { matrix1 dot matrix2 } diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LargeNDBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LargeNDBenchmark.kt deleted file mode 100644 index 395fde619..000000000 --- a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LargeNDBenchmark.kt +++ /dev/null @@ -1,25 +0,0 @@ -package kscience.kmath.benchmarks - -import kscience.kmath.structures.NDField -import org.openjdk.jmh.annotations.Benchmark -import org.openjdk.jmh.annotations.Scope -import org.openjdk.jmh.annotations.State -import org.openjdk.jmh.infra.Blackhole -import kotlin.random.Random - -@State(Scope.Benchmark) -class LargeNDBenchmark { - val arraySize = 10000 - val RANDOM = Random(222) - val src1 = DoubleArray(arraySize) { RANDOM.nextDouble() } - val src2 = DoubleArray(arraySize) { RANDOM.nextDouble() } - val field = NDField.real(arraySize) - val kmathArray1 = field.produce { (a) -> src1[a] } - val kmathArray2 = field.produce { (a) -> src2[a] } - - @Benchmark - fun test10000(bh: Blackhole) { - bh.consume(field.add(kmathArray1, kmathArray2)) - } - -} \ No newline at end of file diff --git a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LinearAlgebraBenchmark.kt b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LinearAlgebraBenchmark.kt index ec8714617..5ff43ef80 100644 --- a/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LinearAlgebraBenchmark.kt +++ b/examples/src/benchmarks/kotlin/kscience/kmath/benchmarks/LinearAlgebraBenchmark.kt @@ -5,10 +5,8 @@ import kotlinx.benchmark.Benchmark import kscience.kmath.commons.linear.CMMatrixContext import kscience.kmath.commons.linear.CMMatrixContext.dot import kscience.kmath.commons.linear.inverse -import kscience.kmath.commons.linear.toCM import kscience.kmath.ejml.EjmlMatrixContext import kscience.kmath.ejml.inverse -import kscience.kmath.ejml.toEjml import kscience.kmath.operations.invoke import kscience.kmath.structures.Matrix import org.openjdk.jmh.annotations.Scope @@ -35,16 +33,14 @@ class LinearAlgebraBenchmark { @Benchmark fun cmLUPInversion() { CMMatrixContext { - val cm = matrix.toCM() //avoid overhead on conversion - inverse(cm) + inverse(matrix) } } @Benchmark fun ejmlInverse() { EjmlMatrixContext { - val km = matrix.toEjml() //avoid overhead on conversion - inverse(km) + inverse(matrix) } } } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt index 880a4e34c..1a3668855 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -95,8 +95,9 @@ public open class FunctionalExpressionRing>( super.binaryOperationFunction(operation) } -public open class FunctionalExpressionField>(algebra: A) : - FunctionalExpressionRing(algebra), Field> { +public open class FunctionalExpressionField>( + algebra: A, +) : FunctionalExpressionRing(algebra), Field> { /** * Builds an Expression of division an expression by another one. */ diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LupDecomposition.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LupDecomposition.kt index f4f998da2..5cf7c8f70 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LupDecomposition.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/linear/LupDecomposition.kt @@ -224,6 +224,7 @@ public inline fun , F : Field> GenericMatrixContext ): Matrix = solveWithLUP(matrix, one(matrix.rowNum, matrix.colNum), bufferFactory, checkSingular) +@OptIn(UnstableKMathAPI::class) public fun RealMatrixContext.solveWithLUP(a: Matrix, b: Matrix): Matrix { // Use existing decomposition if it is provided by matrix val bufferFactory: MutableBufferFactory = MutableBuffer.Companion::real diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Complex.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Complex.kt index 5695e6696..c6409c015 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Complex.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Complex.kt @@ -3,6 +3,7 @@ package kscience.kmath.operations import kscience.kmath.memory.MemoryReader import kscience.kmath.memory.MemorySpec import kscience.kmath.memory.MemoryWriter +import kscience.kmath.misc.UnstableKMathAPI import kscience.kmath.structures.Buffer import kscience.kmath.structures.MemoryBuffer import kscience.kmath.structures.MutableBuffer @@ -41,6 +42,7 @@ private val PI_DIV_2 = Complex(PI / 2, 0) /** * A field of [Complex]. */ +@OptIn(UnstableKMathAPI::class) public object ComplexField : ExtendedField, Norm, RingWithNumbers { override val zero: Complex = 0.0.toComplex() override val one: Complex = 1.0.toComplex() diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealNDField.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealNDField.kt index 3eb1dc4ca..60e6de440 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealNDField.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/RealNDField.kt @@ -11,7 +11,7 @@ public typealias RealNDElement = BufferedNDFieldElement public class RealNDField(override val shape: IntArray) : BufferedNDField, ExtendedNDField>, - RingWithNumbers>{ + RingWithNumbers> { override val strides: Strides = DefaultStrides(shape) @@ -24,35 +24,31 @@ public class RealNDField(override val shape: IntArray) : return produce { d } } - private inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Double): Buffer = - RealBuffer(DoubleArray(size) { initializer(it) }) - - /** - * Inline transform an NDStructure to - */ - override fun map( + @Suppress("OVERRIDE_BY_INLINE") + override inline fun map( arg: NDBuffer, - transform: RealField.(Double) -> Double + transform: RealField.(Double) -> Double, ): RealNDElement { check(arg) - val array = buildBuffer(arg.strides.linearSize) { offset -> RealField.transform(arg.buffer[offset]) } + val array = RealBuffer(arg.strides.linearSize) { offset -> RealField.transform(arg.buffer[offset]) } return BufferedNDFieldElement(this, array) } - override fun produce(initializer: RealField.(IntArray) -> Double): RealNDElement { - val array = buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) } + @Suppress("OVERRIDE_BY_INLINE") + override inline fun produce(initializer: RealField.(IntArray) -> Double): RealNDElement { + val array = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) } return BufferedNDFieldElement(this, array) } - override fun mapIndexed( + @Suppress("OVERRIDE_BY_INLINE") + override inline fun mapIndexed( arg: NDBuffer, - transform: RealField.(index: IntArray, Double) -> Double + transform: RealField.(index: IntArray, Double) -> Double, ): RealNDElement { check(arg) - return BufferedNDFieldElement( this, - buildBuffer(arg.strides.linearSize) { offset -> + RealBuffer(arg.strides.linearSize) { offset -> elementContext.transform( arg.strides.index(offset), arg.buffer[offset] @@ -60,16 +56,17 @@ public class RealNDField(override val shape: IntArray) : }) } - override fun combine( + @Suppress("OVERRIDE_BY_INLINE") + override inline fun combine( a: NDBuffer, b: NDBuffer, - transform: RealField.(Double, Double) -> Double + transform: RealField.(Double, Double) -> Double, ): RealNDElement { check(a, b) - return BufferedNDFieldElement( - this, - buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) } - ) + val buffer = RealBuffer(strides.linearSize) { offset -> + elementContext.transform(a.buffer[offset], b.buffer[offset]) + } + return BufferedNDFieldElement(this, buffer) } override fun NDBuffer.toElement(): FieldElement, *, out BufferedNDField> = diff --git a/kmath-core/src/commonTest/kotlin/kscience/kmath/linear/MatrixTest.kt b/kmath-core/src/commonTest/kotlin/kscience/kmath/linear/MatrixTest.kt index 0a582e339..d7755dcb5 100644 --- a/kmath-core/src/commonTest/kotlin/kscience/kmath/linear/MatrixTest.kt +++ b/kmath-core/src/commonTest/kotlin/kscience/kmath/linear/MatrixTest.kt @@ -7,6 +7,7 @@ import kscience.kmath.structures.as2D import kotlin.test.Test import kotlin.test.assertEquals +@Suppress("UNUSED_VARIABLE") class MatrixTest { @Test fun testTranspose() { diff --git a/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NumberNDFieldTest.kt b/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NumberNDFieldTest.kt index f5e008ef3..22a0d3629 100644 --- a/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NumberNDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/kscience/kmath/structures/NumberNDFieldTest.kt @@ -8,6 +8,7 @@ import kotlin.math.pow import kotlin.test.Test import kotlin.test.assertEquals +@Suppress("UNUSED_VARIABLE") class NumberNDFieldTest { val array1: RealNDElement = real2D(3, 3) { i, j -> (i + j).toDouble() } val array2: RealNDElement = real2D(3, 3) { i, j -> (i - j).toDouble() } diff --git a/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt b/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt index 5b330fcce..b9193d4dd 100644 --- a/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt +++ b/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt @@ -6,6 +6,7 @@ import kscience.kmath.dimensions.DMatrixContext import kscience.kmath.dimensions.one import kotlin.test.Test +@Suppress("UNUSED_VARIABLE") internal class DMatrixContextTest { @Test fun testDimensionSafeMatrix() { From a11711c336e7698a7cf418e5e727d3ed338cb45c Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 19 Jan 2021 22:25:04 +0300 Subject: [PATCH 004/178] Tensor algebra refactoring --- .../{structures => tensors}/TensorAlgebra.kt | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) rename kmath-core/src/commonMain/kotlin/kscience/kmath/{structures => tensors}/TensorAlgebra.kt (76%) diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/tensors/TensorAlgebra.kt similarity index 76% rename from kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorAlgebra.kt rename to kmath-core/src/commonMain/kotlin/kscience/kmath/tensors/TensorAlgebra.kt index ca7619429..c40544579 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/structures/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/tensors/TensorAlgebra.kt @@ -1,32 +1,36 @@ -package kscience.kmath.structures +package kscience.kmath.tensors -public interface TensorStructure : MutableNDStructure { - // A tensor can have empty shape, in which case it represents just a value - public abstract fun value(): T -} +import kscience.kmath.operations.Ring +import kscience.kmath.structures.MutableNDStructure + +public typealias Tensor = MutableNDStructure + +public val Tensor.value: T + get() { + require(shape.contentEquals(intArrayOf(1))) { "Value available only for a tensor with no dimensions" } + return get(intArrayOf(0)) + } // https://proofwiki.org/wiki/Definition:Algebra_over_Ring - -public interface TensorAlgebra> { +/** + * To be moved to a separate project + */ +public interface TensorAlgebra> : Ring { public operator fun T.plus(other: TensorType): TensorType public operator fun TensorType.plus(value: T): TensorType - public operator fun TensorType.plus(other: TensorType): TensorType public operator fun TensorType.plusAssign(value: T): Unit public operator fun TensorType.plusAssign(other: TensorType): Unit public operator fun T.minus(other: TensorType): TensorType public operator fun TensorType.minus(value: T): TensorType - public operator fun TensorType.minus(other: TensorType): TensorType public operator fun TensorType.minusAssign(value: T): Unit public operator fun TensorType.minusAssign(other: TensorType): Unit public operator fun T.times(other: TensorType): TensorType public operator fun TensorType.times(value: T): TensorType - public operator fun TensorType.times(other: TensorType): TensorType public operator fun TensorType.timesAssign(value: T): Unit public operator fun TensorType.timesAssign(other: TensorType): Unit - public operator fun TensorType.unaryMinus(): TensorType public infix fun TensorType.dot(other: TensorType): TensorType @@ -35,7 +39,7 @@ public interface TensorAlgebra> { public fun diagonalEmbedding( diagonalEntries: TensorType, - offset: Int = 0, dim1: Int = -2, dim2: Int = -1 + offset: Int = 0, dim1: Int = -2, dim2: Int = -1, ): TensorType public fun TensorType.transpose(i: Int, j: Int): TensorType @@ -51,8 +55,7 @@ public interface TensorAlgebra> { // https://proofwiki.org/wiki/Definition:Division_Algebra -public interface TensorPartialDivisionAlgebra> : - TensorAlgebra { +public interface TensorPartialDivisionAlgebra> : TensorAlgebra { public operator fun TensorType.div(other: TensorType): TensorType public operator fun TensorType.divAssign(other: TensorType) From 9011579d2c777b4844e4fbb10da9c077ce027c24 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 20 Jan 2021 11:43:01 +0300 Subject: [PATCH 005/178] [WIP] Tensor algebra design --- build.gradle.kts | 2 +- .../kscience/kmath/tensors/TensorAlgebra.kt | 74 ++++++++++--------- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index d171bd608..0572217af 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { id("ru.mipt.npm.project") } -internal val kmathVersion: String by extra("0.2.0-dev-5") +internal val kmathVersion: String by extra("0.2.0-dev-6") internal val bintrayRepo: String by extra("kscience") internal val githubProject: String by extra("kmath") diff --git a/kmath-core/src/commonMain/kotlin/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/kscience/kmath/tensors/TensorAlgebra.kt index c40544579..c14f0ee0d 100644 --- a/kmath-core/src/commonMain/kotlin/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/kscience/kmath/tensors/TensorAlgebra.kt @@ -1,10 +1,13 @@ package kscience.kmath.tensors +import kscience.kmath.misc.UnstableKMathAPI +import kscience.kmath.operations.Field import kscience.kmath.operations.Ring import kscience.kmath.structures.MutableNDStructure public typealias Tensor = MutableNDStructure +@UnstableKMathAPI public val Tensor.value: T get() { require(shape.contentEquals(intArrayOf(1))) { "Value available only for a tensor with no dimensions" } @@ -13,59 +16,60 @@ public val Tensor.value: T // https://proofwiki.org/wiki/Definition:Algebra_over_Ring /** - * To be moved to a separate project + * TODO To be moved to a separate project */ -public interface TensorAlgebra> : Ring { +@UnstableKMathAPI +public interface TensorAlgebra> : Ring { - public operator fun T.plus(other: TensorType): TensorType - public operator fun TensorType.plus(value: T): TensorType - public operator fun TensorType.plusAssign(value: T): Unit - public operator fun TensorType.plusAssign(other: TensorType): Unit + public operator fun T.plus(other: TT): TT + public operator fun TT.plus(value: T): TT + public operator fun TT.plusAssign(value: T): Unit + public operator fun TT.plusAssign(other: TT): Unit - public operator fun T.minus(other: TensorType): TensorType - public operator fun TensorType.minus(value: T): TensorType - public operator fun TensorType.minusAssign(value: T): Unit - public operator fun TensorType.minusAssign(other: TensorType): Unit + public operator fun T.minus(other: TT): TT + public operator fun TT.minus(value: T): TT + public operator fun TT.minusAssign(value: T): Unit + public operator fun TT.minusAssign(other: TT): Unit - public operator fun T.times(other: TensorType): TensorType - public operator fun TensorType.times(value: T): TensorType - public operator fun TensorType.timesAssign(value: T): Unit - public operator fun TensorType.timesAssign(other: TensorType): Unit + public operator fun T.times(other: TT): TT + public operator fun TT.times(value: T): TT + public operator fun TT.timesAssign(value: T): Unit + public operator fun TT.timesAssign(other: TT): Unit - public infix fun TensorType.dot(other: TensorType): TensorType - public infix fun TensorType.dotAssign(other: TensorType): Unit - public infix fun TensorType.dotRightAssign(other: TensorType): Unit + public infix fun TT.dot(other: TT): TT + public infix fun TT.dotAssign(other: TT): Unit + public infix fun TT.dotRightAssign(other: TT): Unit public fun diagonalEmbedding( - diagonalEntries: TensorType, + diagonalEntries: TT, offset: Int = 0, dim1: Int = -2, dim2: Int = -1, - ): TensorType + ): TT - public fun TensorType.transpose(i: Int, j: Int): TensorType - public fun TensorType.transposeAssign(i: Int, j: Int): Unit + public fun TT.transpose(i: Int, j: Int): TT + public fun TT.transposeAssign(i: Int, j: Int): Unit - public fun TensorType.view(shape: IntArray): TensorType + public fun TT.view(shape: IntArray): TT - public fun TensorType.abs(): TensorType - public fun TensorType.absAssign(): Unit - public fun TensorType.sum(): TensorType - public fun TensorType.sumAssign(): Unit + public fun abs(tensor: TT): TT + public fun TT.absAssign(): Unit + public fun TT.sum(): TT + public fun TT.sumAssign(): Unit } // https://proofwiki.org/wiki/Definition:Division_Algebra -public interface TensorPartialDivisionAlgebra> : TensorAlgebra { +public interface TensorPartialDivisionAlgebra> : + TensorAlgebra, Field { - public operator fun TensorType.div(other: TensorType): TensorType - public operator fun TensorType.divAssign(other: TensorType) + public operator fun TT.divAssign(other: TT) - public fun TensorType.exp(): TensorType - public fun TensorType.expAssign(): Unit - public fun TensorType.log(): TensorType - public fun TensorType.logAssign(): Unit + public fun exp(tensor: TT): TT + public fun TT.expAssign(): Unit + public fun log(tensor: TT): TT + public fun TT.logAssign(): Unit - public fun TensorType.svd(): Triple - public fun TensorType.symEig(eigenvectors: Boolean = true): Pair + public fun svd(tensor: TT): Triple + public fun symEig(tensor: TT, eigenvectors: Boolean = true): Pair } \ No newline at end of file From f15ac203236355117e72f81159af7a496f5c6706 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Mon, 1 Mar 2021 22:52:58 +0000 Subject: [PATCH 006/178] Cannot afford to inherit from RingWithNumbers --- .../kmath/tensors/RealTensorAlgebra.kt | 35 +++++++++---------- .../kscience/kmath/tensors/TensorAlgebra.kt | 9 ++--- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index 0a28ace4f..6023d2b72 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -19,25 +19,6 @@ public class RealTensor( public class RealTensorAlgebra : TensorPartialDivisionAlgebra { - override fun add(a: RealTensor, b: RealTensor): RealTensor { - TODO("Not yet implemented") - } - - override fun multiply(a: RealTensor, k: Number): RealTensor { - TODO("Not yet implemented") - } - - override val zero: RealTensor - get() = TODO("Not yet implemented") - - override fun multiply(a: RealTensor, b: RealTensor): RealTensor { - TODO("Not yet implemented") - } - - override val one: RealTensor - get() = TODO("Not yet implemented") - - override fun Double.plus(other: RealTensor): RealTensor { val n = other.buffer.size val arr = other.buffer.array @@ -51,6 +32,10 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra>: RingWithNumbers { +public interface TensorAlgebra>{ public operator fun T.plus(other: TensorType): TensorType public operator fun TensorType.plus(value: T): TensorType + public operator fun TensorType.plus(other: TensorType): TensorType public operator fun TensorType.plusAssign(value: T): Unit public operator fun TensorType.plusAssign(other: TensorType): Unit public operator fun T.minus(other: TensorType): TensorType public operator fun TensorType.minus(value: T): TensorType + public operator fun TensorType.minus(other: TensorType): TensorType public operator fun TensorType.minusAssign(value: T): Unit public operator fun TensorType.minusAssign(other: TensorType): Unit public operator fun T.times(other: TensorType): TensorType public operator fun TensorType.times(value: T): TensorType + public operator fun TensorType.times(other: TensorType): TensorType public operator fun TensorType.timesAssign(value: T): Unit public operator fun TensorType.timesAssign(other: TensorType): Unit + public operator fun TensorType.unaryMinus(): TensorType //https://pytorch.org/docs/stable/generated/torch.matmul.html From 4aa1df0628c5d531b518691eb8ab22b907946eb0 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 2 Mar 2021 09:32:36 +0000 Subject: [PATCH 007/178] Safe item method and view_as added --- .../space/kscience/kmath/tensors/RealTensorAlgebra.kt | 10 +++++++++- .../space/kscience/kmath/tensors/TensorAlgebra.kt | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index 6023d2b72..24612a6aa 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -14,9 +14,13 @@ public class RealTensor( TensorStrides(shape), RealBuffer(buffer) ) { - override fun item(): Double = buffer[0] + override fun item(): Double { + check(buffer.size > 0) { "The tensor is empty" } + return buffer[0] + } } + public class RealTensorAlgebra : TensorPartialDivisionAlgebra { override fun Double.plus(other: RealTensor): RealTensor { @@ -116,6 +120,10 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra>{ //https://pytorch.org/docs/stable/tensor_view.html public fun TensorType.view(shape: IntArray): TensorType + public fun TensorType.view_as(other: TensorType): TensorType //https://pytorch.org/docs/stable/generated/torch.abs.html public fun TensorType.abs(): TensorType From ed007589cfc97d4b6c8d01a51719f2511d0ee3b3 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 2 Mar 2021 14:54:07 +0000 Subject: [PATCH 008/178] LU decomposition set up --- .../kscience/kmath/tensors/RealTensorAlgebra.kt | 13 +++++++++++++ .../space/kscience/kmath/tensors/TensorAlgebra.kt | 3 +++ 2 files changed, 16 insertions(+) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index 24612a6aa..f234d7d6a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -1,5 +1,6 @@ package space.kscience.kmath.tensors +import space.kscience.kmath.linear.LupDecompositionFeature import space.kscience.kmath.nd.MutableNDBuffer import space.kscience.kmath.structures.RealBuffer import space.kscience.kmath.structures.array @@ -164,7 +165,19 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra { + /** + * Main first task for @AndreiKingsley + * Compare with the implementation of [LupDecomposition] + * and provide a common API + */ + TODO("Not yet implemented") + } + override fun RealTensor.svd(): Triple { + /** + * Main first task for @AlyaNovikova + */ TODO("Not yet implemented") } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index cddda7670..03f6f05c2 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -66,6 +66,9 @@ public interface TensorPartialDivisionAlgebra public fun TensorType.log(): TensorType public fun TensorType.logAssign(): Unit + //https://pytorch.org/docs/stable/generated/torch.lu.html + public fun TensorType.lu(): Pair + //https://pytorch.org/docs/stable/generated/torch.svd.html public fun TensorType.svd(): Triple From 90f4ff06fd76fb60f4966d8d60fa31c6b4ebf96f Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Thu, 4 Mar 2021 13:22:28 +0000 Subject: [PATCH 009/178] Basic tasks for Alya and Andrei --- .../kmath/tensors/RealTensorAlgebra.kt | 58 +++++++++++-------- .../kscience/kmath/tensors/TensorAlgebra.kt | 7 ++- .../kscience/kmath/tensors/TensorStructure.kt | 4 ++ 3 files changed, 44 insertions(+), 25 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index f234d7d6a..cad01c4d0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -1,6 +1,5 @@ package space.kscience.kmath.tensors -import space.kscience.kmath.linear.LupDecompositionFeature import space.kscience.kmath.nd.MutableNDBuffer import space.kscience.kmath.structures.RealBuffer import space.kscience.kmath.structures.array @@ -15,6 +14,9 @@ public class RealTensor( TensorStrides(shape), RealBuffer(buffer) ) { + /* + * TODO: Andrei remove item() + */ override fun item(): Double { check(buffer.size > 0) { "The tensor is empty" } return buffer[0] @@ -24,6 +26,10 @@ public class RealTensor( public class RealTensorAlgebra : TensorPartialDivisionAlgebra { + override fun RealTensor.value(): Double { + TODO("Andrei") + } + override fun Double.plus(other: RealTensor): RealTensor { val n = other.buffer.size val arr = other.buffer.array @@ -34,95 +40,95 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra { + TODO("Not yet implemented") + } + override fun RealTensor.svd(): Triple { /** * Main first task for @AlyaNovikova diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index 03f6f05c2..b2586e1e9 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -1,7 +1,9 @@ package space.kscience.kmath.tensors // https://proofwiki.org/wiki/Definition:Algebra_over_Ring -public interface TensorAlgebra>{ +public interface TensorAlgebra> { + + public fun TensorType.value(): T public operator fun T.plus(other: TensorType): TensorType public operator fun TensorType.plus(value: T): TensorType @@ -69,6 +71,9 @@ public interface TensorPartialDivisionAlgebra //https://pytorch.org/docs/stable/generated/torch.lu.html public fun TensorType.lu(): Pair + //https://pytorch.org/docs/stable/generated/torch.lu_unpack.html + public fun lu_unpack(A_LU: TensorType, pivots: TensorType): Triple + //https://pytorch.org/docs/stable/generated/torch.svd.html public fun TensorType.svd(): Triple diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt index 6d2d855b6..3775ea2e5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt @@ -3,6 +3,10 @@ package space.kscience.kmath.tensors import space.kscience.kmath.nd.MutableNDStructure public interface TensorStructure : MutableNDStructure { + + /* + * TODO: Andrei remove item() and value() + */ public fun item(): T // A tensor can have empty shape, in which case it represents just a value From fe55856a26bd92c7389c57a17df9f908ea2cc343 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 9 Mar 2021 22:18:46 +0300 Subject: [PATCH 010/178] basic implements & refactor tensor structure & and new tensor algebra methods --- .../kmath/tensors/RealTensorAlgebra.kt | 137 ++++++++++++------ .../kscience/kmath/tensors/TensorAlgebra.kt | 14 +- .../kscience/kmath/tensors/TensorStrides.kt | 4 +- .../kscience/kmath/tensors/TensorStructure.kt | 23 +-- 4 files changed, 111 insertions(+), 67 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index cad01c4d0..13c57fc18 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -3,6 +3,8 @@ package space.kscience.kmath.tensors import space.kscience.kmath.nd.MutableNDBuffer import space.kscience.kmath.structures.RealBuffer import space.kscience.kmath.structures.array +import kotlin.js.JsName +import kotlin.math.abs public class RealTensor( @@ -13,46 +15,80 @@ public class RealTensor( MutableNDBuffer( TensorStrides(shape), RealBuffer(buffer) - ) { - /* - * TODO: Andrei remove item() - */ - override fun item(): Double { - check(buffer.size > 0) { "The tensor is empty" } - return buffer[0] - } -} - + ) public class RealTensorAlgebra : TensorPartialDivisionAlgebra { + //rename to item? override fun RealTensor.value(): Double { - TODO("Andrei") + check(this.dimension == 0) { + // todo change message + "This tensor has shape ${shape.toList()}" + } + return this.buffer.array[0] + } + + override fun eye(n: Int): RealTensor { + val shape = intArrayOf(n, n) + val buffer = DoubleArray(n * n) { 0.0 } + val res = RealTensor(shape, buffer) + for (i in 0 until n) { + res[intArrayOf(i, i)] = 1.0 + } + return res + } + + override fun zeros(shape: IntArray): RealTensor { + TODO("Not yet implemented") + } + + override fun zeroesLike(other: RealTensor): RealTensor { + TODO("Not yet implemented") + } + + override fun ones(shape: IntArray): RealTensor { + TODO("Not yet implemented") + } + + override fun onesLike(shape: IntArray): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.copy(): RealTensor { + TODO("Not yet implemented") } override fun Double.plus(other: RealTensor): RealTensor { - val n = other.buffer.size - val arr = other.buffer.array - val res = DoubleArray(n) - for (i in 1..n) - res[i - 1] = arr[i - 1] + this - return RealTensor(other.shape, res) + //todo should be change with broadcasting + val resBuffer = DoubleArray(other.buffer.size) { i -> + other.buffer.array[i] + this + } + return RealTensor(other.shape, resBuffer) } - override fun RealTensor.plus(value: Double): RealTensor { - TODO("Andrei") - } + //todo should be change with broadcasting + override fun RealTensor.plus(value: Double): RealTensor = value + this override fun RealTensor.plus(other: RealTensor): RealTensor { - TODO("Andrei") + //todo should be change with broadcasting + val resBuffer = DoubleArray(this.buffer.size) { i -> + this.buffer.array[i] + other.buffer.array[i] + } + return RealTensor(this.shape, resBuffer) } override fun RealTensor.plusAssign(value: Double) { - TODO("Andrei") + //todo should be change with broadcasting + for (i in this.buffer.array.indices) { + this.buffer.array[i] += value + } } override fun RealTensor.plusAssign(other: RealTensor) { - TODO("Andrei") + //todo should be change with broadcasting + for (i in this.buffer.array.indices) { + this.buffer.array[i] += other.buffer.array[i] + } } override fun Double.minus(other: RealTensor): RealTensor { @@ -76,27 +112,43 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra + other.buffer.array[i] * this + } + return RealTensor(other.shape, resBuffer) } - override fun RealTensor.times(value: Double): RealTensor { - TODO("Andrei") - } + //todo should be change with broadcasting + override fun RealTensor.times(value: Double): RealTensor = value * this override fun RealTensor.times(other: RealTensor): RealTensor { - TODO("Andrei") + //todo should be change with broadcasting + val resBuffer = DoubleArray(this.buffer.size) { i -> + this.buffer.array[i] * other.buffer.array[i] + } + return RealTensor(this.shape, resBuffer) } override fun RealTensor.timesAssign(value: Double) { - TODO("Andrei") + //todo should be change with broadcasting + for (i in this.buffer.array.indices) { + this.buffer.array[i] *= value + } } override fun RealTensor.timesAssign(other: RealTensor) { - TODO("Andrei") + //todo should be change with broadcasting + for (i in this.buffer.array.indices) { + this.buffer.array[i] *= other.buffer.array[i] + } } override fun RealTensor.unaryMinus(): RealTensor { - TODO("Andrei") + val resBuffer = DoubleArray(this.buffer.size) { i -> + this.buffer.array[i].unaryMinus() + } + return RealTensor(this.shape, resBuffer) } override fun RealTensor.dot(other: RealTensor): RealTensor { @@ -124,11 +176,11 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra { - /** - * Main first task for @AndreiKingsley - * Compare with the implementation of [LupDecomposition] - * and provide a common API - */ - TODO("Not yet implemented") + TODO() } - override fun lu_unpack(A_LU: RealTensor, pivots: RealTensor): Triple { + override fun luUnpack(A_LU: RealTensor, pivots: RealTensor): Triple { TODO("Not yet implemented") } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index b2586e1e9..6f42623e0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -5,6 +5,14 @@ public interface TensorAlgebra> { public fun TensorType.value(): T + public fun eye(n: Int): TensorType + public fun zeros(shape: IntArray): TensorType + public fun zeroesLike(other: TensorType): TensorType + public fun ones(shape: IntArray): TensorType + public fun onesLike(shape: IntArray): TensorType + + public fun TensorType.copy(): TensorType + public operator fun T.plus(other: TensorType): TensorType public operator fun TensorType.plus(value: T): TensorType public operator fun TensorType.plus(other: TensorType): TensorType @@ -42,7 +50,7 @@ public interface TensorAlgebra> { //https://pytorch.org/docs/stable/tensor_view.html public fun TensorType.view(shape: IntArray): TensorType - public fun TensorType.view_as(other: TensorType): TensorType + public fun TensorType.viewAs(other: TensorType): TensorType //https://pytorch.org/docs/stable/generated/torch.abs.html public fun TensorType.abs(): TensorType @@ -57,7 +65,9 @@ public interface TensorAlgebra> { public interface TensorPartialDivisionAlgebra> : TensorAlgebra { + public operator fun TensorType.div(value: T): TensorType public operator fun TensorType.div(other: TensorType): TensorType + public operator fun TensorType.divAssign(value: T) public operator fun TensorType.divAssign(other: TensorType) //https://pytorch.org/docs/stable/generated/torch.exp.html @@ -72,7 +82,7 @@ public interface TensorPartialDivisionAlgebra public fun TensorType.lu(): Pair //https://pytorch.org/docs/stable/generated/torch.lu_unpack.html - public fun lu_unpack(A_LU: TensorType, pivots: TensorType): Triple + public fun luUnpack(A_LU: TensorType, pivots: TensorType): Triple //https://pytorch.org/docs/stable/generated/torch.svd.html public fun TensorType.svd(): Triple diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStrides.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStrides.kt index 3ea8f4bf0..dbaefe907 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStrides.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStrides.kt @@ -5,7 +5,7 @@ import space.kscience.kmath.nd.offsetFromIndex import kotlin.math.max -inline public fun stridesFromShape(shape: IntArray): IntArray { +public inline fun stridesFromShape(shape: IntArray): IntArray { val nDim = shape.size val res = IntArray(nDim) if (nDim == 0) @@ -22,7 +22,7 @@ inline public fun stridesFromShape(shape: IntArray): IntArray { } -inline public fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): IntArray { +public inline fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): IntArray { val res = IntArray(nDim) var current = offset var strideIndex = 0 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt index 3775ea2e5..5463877ce 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt @@ -2,26 +2,5 @@ package space.kscience.kmath.tensors import space.kscience.kmath.nd.MutableNDStructure -public interface TensorStructure : MutableNDStructure { +public typealias TensorStructure = MutableNDStructure - /* - * TODO: Andrei remove item() and value() - */ - public fun item(): T - - // A tensor can have empty shape, in which case it represents just a value - public fun value(): T { - checkIsValue() - return item() - } -} - -public inline fun TensorStructure.isValue(): Boolean { - return (dimension == 0) -} - -public inline fun TensorStructure.isNotValue(): Boolean = !this.isValue() - -public inline fun TensorStructure.checkIsValue(): Unit = check(this.isValue()) { - "This tensor has shape ${shape.toList()}" -} \ No newline at end of file From 3a37b88b5c4808107e2522d5f33eb07440169fb9 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 9 Mar 2021 21:13:48 +0000 Subject: [PATCH 011/178] Fixed getting value test for tensors --- .../space/kscience/kmath/tensors/RealTensorAlgebra.kt | 8 ++------ .../kotlin/space/kscience/kmath/tensors/TensorStrides.kt | 2 +- .../kotlin/space/kscience/kmath/tensors/TestRealTensor.kt | 4 ++-- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index 13c57fc18..366acfb62 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -3,8 +3,6 @@ package space.kscience.kmath.tensors import space.kscience.kmath.nd.MutableNDBuffer import space.kscience.kmath.structures.RealBuffer import space.kscience.kmath.structures.array -import kotlin.js.JsName -import kotlin.math.abs public class RealTensor( @@ -19,11 +17,9 @@ public class RealTensor( public class RealTensorAlgebra : TensorPartialDivisionAlgebra { - //rename to item? override fun RealTensor.value(): Double { - check(this.dimension == 0) { - // todo change message - "This tensor has shape ${shape.toList()}" + check(this.shape contentEquals intArrayOf(1)) { + "Inconsistent value for tensor of shape ${shape.toList()}" } return this.buffer.array[0] } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStrides.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStrides.kt index dbaefe907..0c10203f0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStrides.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStrides.kt @@ -48,5 +48,5 @@ public class TensorStrides(override val shape: IntArray): Strides indexFromOffset(offset, strides, shape.size) override val linearSize: Int - get() = shape.fold(1) { acc, i -> acc * i } + get() = shape.reduce(Int::times) } \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensor.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensor.kt index 7938eb864..d96b00baf 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensor.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensor.kt @@ -9,9 +9,9 @@ import kotlin.test.assertTrue class TestRealTensor { @Test - fun valueTest(){ + fun valueTest() = RealTensorAlgebra { val value = 12.5 - val tensor = RealTensor(IntArray(0), doubleArrayOf(value)) + val tensor = RealTensor(intArrayOf(1), doubleArrayOf(value)) assertEquals(tensor.value(), value) } From 723e0e458e7be15e3388e4bef6654db487d2cf03 Mon Sep 17 00:00:00 2001 From: AlyaNovikova Date: Thu, 11 Mar 2021 23:04:42 +0300 Subject: [PATCH 012/178] add functions transpose and transposeAssign --- .../space/kscience/kmath/nd/NDStructure.kt | 9 ++++ .../kmath/tensors/RealTensorAlgebra.kt | 26 +++++++++- .../kscience/kmath/tensors/TensorStrides.kt | 20 ++++++++ .../kmath/tensors/TestRealTensorAlgebra.kt | 51 +++++++++++++++++++ 4 files changed, 104 insertions(+), 2 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/NDStructure.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/NDStructure.kt index 54e410ade..e458d0606 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/NDStructure.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/NDStructure.kt @@ -174,6 +174,11 @@ public interface Strides { */ 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 */ @@ -232,6 +237,10 @@ public class DefaultStrides private constructor(override val shape: IntArray) : return res } + override fun nextIndex(index: IntArray): IntArray { + TODO("Not yet implemented") + } + override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is DefaultStrides) return false diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index 366acfb62..a5c00e8ec 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -164,11 +164,33 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra= shape[current]) { + carry = 1 + res[current] = 0 + } + current-- + } while(carry != 0 && current >= 0) + + return res +} + 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 = indexFromOffset(offset, strides, shape.size) + override fun nextIndex(index: IntArray): IntArray = + nextIndex(index, shape, shape.size) + override val linearSize: Int get() = shape.reduce(Int::times) } \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt index 86caa0338..8e95922b8 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt @@ -13,4 +13,55 @@ class TestRealTensorAlgebra { 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)) + } } \ No newline at end of file From bb4894b87ea5d4ed64b290ae0ddcd35c9ebe6d1a Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Thu, 11 Mar 2021 21:46:35 +0000 Subject: [PATCH 013/178] removing assignement for non operator members --- .../kmath/tensors/RealTensorAlgebra.kt | 31 +------------------ .../kscience/kmath/tensors/TensorAlgebra.kt | 7 ----- .../kmath/tensors/TestRealTensorAlgebra.kt | 18 ----------- 3 files changed, 1 insertion(+), 55 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index a5c00e8ec..16f90341b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -151,14 +151,6 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra { TODO() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index 6f42623e0..f1d401f6e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -35,8 +35,6 @@ public interface TensorAlgebra> { //https://pytorch.org/docs/stable/generated/torch.matmul.html public infix fun TensorType.dot(other: TensorType): TensorType - public infix fun TensorType.dotAssign(other: TensorType): Unit - public infix fun TensorType.dotRightAssign(other: TensorType): Unit //https://pytorch.org/docs/stable/generated/torch.diag_embed.html public fun diagonalEmbedding( @@ -46,7 +44,6 @@ public interface TensorAlgebra> { //https://pytorch.org/docs/stable/generated/torch.transpose.html public fun TensorType.transpose(i: Int, j: Int): TensorType - public fun TensorType.transposeAssign(i: Int, j: Int): Unit //https://pytorch.org/docs/stable/tensor_view.html public fun TensorType.view(shape: IntArray): TensorType @@ -54,11 +51,9 @@ public interface TensorAlgebra> { //https://pytorch.org/docs/stable/generated/torch.abs.html public fun TensorType.abs(): TensorType - public fun TensorType.absAssign(): Unit //https://pytorch.org/docs/stable/generated/torch.sum.html public fun TensorType.sum(): TensorType - public fun TensorType.sumAssign(): Unit } // https://proofwiki.org/wiki/Definition:Division_Algebra @@ -72,11 +67,9 @@ public interface TensorPartialDivisionAlgebra //https://pytorch.org/docs/stable/generated/torch.exp.html public fun TensorType.exp(): TensorType - public fun TensorType.expAssign(): Unit //https://pytorch.org/docs/stable/generated/torch.log.html public fun TensorType.log(): TensorType - public fun TensorType.logAssign(): Unit //https://pytorch.org/docs/stable/generated/torch.lu.html public fun TensorType.lu(): Pair diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt index 8e95922b8..19f0c0ef0 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt @@ -46,22 +46,4 @@ class TestRealTensorAlgebra { 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)) - } } \ No newline at end of file From f9500f44ec6fc811a17e76104a9bea7ed6f790cc Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Fri, 12 Mar 2021 13:50:06 +0300 Subject: [PATCH 014/178] new tensor def --- .../kscience/kmath/tensors/BufferTensor.kt | 28 +++++++++++++++++++ .../kmath/tensors/RealTensorAlgebra.kt | 14 +++++----- 2 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferTensor.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferTensor.kt new file mode 100644 index 000000000..4d8aea32c --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferTensor.kt @@ -0,0 +1,28 @@ +package space.kscience.kmath.tensors + +import space.kscience.kmath.linear.BufferMatrix +import space.kscience.kmath.linear.RealMatrixContext.toBufferMatrix +import space.kscience.kmath.nd.MutableNDBuffer +import space.kscience.kmath.nd.as2D +import space.kscience.kmath.structures.MutableBuffer +import space.kscience.kmath.structures.toList + +public open class BufferTensor( + override val shape: IntArray, + buffer: MutableBuffer +) : + TensorStructure, + MutableNDBuffer( + TensorStrides(shape), + buffer + ) + + +public fun BufferTensor.toBufferMatrix(): BufferMatrix { + return BufferMatrix(shape[0], shape[1], this.buffer) +} + +public fun BufferMatrix.BufferTensor(): BufferTensor { + return BufferTensor(intArrayOf(rowNum, colNum), buffer) +} + diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index a5c00e8ec..e38056097 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -1,19 +1,19 @@ package space.kscience.kmath.tensors +import space.kscience.kmath.linear.BufferMatrix +import space.kscience.kmath.linear.RealMatrixContext.toBufferMatrix import space.kscience.kmath.nd.MutableNDBuffer +import space.kscience.kmath.nd.as2D +import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.RealBuffer import space.kscience.kmath.structures.array +import space.kscience.kmath.structures.toList public class RealTensor( - override val shape: IntArray, + shape: IntArray, buffer: DoubleArray -) : - TensorStructure, - MutableNDBuffer( - TensorStrides(shape), - RealBuffer(buffer) - ) +) : BufferTensor(shape, RealBuffer(buffer)) public class RealTensorAlgebra : TensorPartialDivisionAlgebra { From 95b814e1637c281b6cc771b0c89e3475a27323c9 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Fri, 12 Mar 2021 14:29:51 +0300 Subject: [PATCH 015/178] add fromMatrix --- .../kotlin/space/kscience/kmath/tensors/BufferTensor.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferTensor.kt index 4d8aea32c..817c51f11 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferTensor.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferTensor.kt @@ -2,8 +2,12 @@ package space.kscience.kmath.tensors import space.kscience.kmath.linear.BufferMatrix import space.kscience.kmath.linear.RealMatrixContext.toBufferMatrix +import space.kscience.kmath.nd.Matrix import space.kscience.kmath.nd.MutableNDBuffer +import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.nd.as2D +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.BufferAccessor2D import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.toList @@ -22,7 +26,8 @@ public fun BufferTensor.toBufferMatrix(): BufferMatrix { return BufferMatrix(shape[0], shape[1], this.buffer) } -public fun BufferMatrix.BufferTensor(): BufferTensor { - return BufferTensor(intArrayOf(rowNum, colNum), buffer) +// T??? +public fun BufferMatrix.BufferTensor(): BufferTensor { + return BufferTensor(intArrayOf(rowNum, colNum), BufferAccessor2D(rowNum, colNum, Buffer.Companion::real).create(this)) } From 454d574ccd8876982753e8e09782ff1f4fb0c564 Mon Sep 17 00:00:00 2001 From: AlyaNovikova Date: Fri, 12 Mar 2021 15:20:46 +0300 Subject: [PATCH 016/178] add broadcast and functions plus and minus --- .../kmath/tensors/RealTensorAlgebra.kt | 96 ++++++++++++++++--- .../kscience/kmath/tensors/TensorAlgebra.kt | 3 + .../kmath/tensors/TestRealTensorAlgebra.kt | 47 +++++++++ 3 files changed, 135 insertions(+), 11 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index a5c00e8ec..a4ad54bfc 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -2,7 +2,9 @@ package space.kscience.kmath.tensors import space.kscience.kmath.nd.MutableNDBuffer import space.kscience.kmath.structures.RealBuffer +import space.kscience.kmath.structures.ValueFlag import space.kscience.kmath.structures.array +import kotlin.math.max public class RealTensor( @@ -54,27 +56,85 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra { + val totalShape = broadcastShapes(*(tensors.map { it.shape }).toTypedArray()) + val n = totalShape.reduce{ acc, i -> acc * i } + + val res = ArrayList(0) + for (tensor in tensors) { + val resTensor = RealTensor(totalShape, DoubleArray(n)) + + for (linearIndex in 0 until n) { + val totalMultiIndex = resTensor.strides.index(linearIndex) + val curMultiIndex = tensor.shape.copyOf() + + val offset = totalMultiIndex.size - curMultiIndex.size + + for (i in curMultiIndex.indices) { + if (curMultiIndex[i] != 1) { + curMultiIndex[i] = totalMultiIndex[i + offset] + } else { + curMultiIndex[i] = 0 + } + } + + val curLinearIndex = tensor.strides.offset(curMultiIndex) + resTensor.buffer.array[linearIndex] = tensor.buffer.array[curLinearIndex] + } + res.add(resTensor) + } + + return res + } + override fun Double.plus(other: RealTensor): RealTensor { - //todo should be change with broadcasting val resBuffer = DoubleArray(other.buffer.size) { i -> other.buffer.array[i] + this } return RealTensor(other.shape, resBuffer) } - //todo should be change with broadcasting override fun RealTensor.plus(value: Double): RealTensor = value + this override fun RealTensor.plus(other: RealTensor): RealTensor { - //todo should be change with broadcasting - val resBuffer = DoubleArray(this.buffer.size) { i -> - this.buffer.array[i] + other.buffer.array[i] + val broadcast = broadcastTensors(this, other) + val newThis = broadcast[0] + val newOther = broadcast[1] + val resBuffer = DoubleArray(newThis.buffer.size) { i -> + newThis.buffer.array[i] + newOther.buffer.array[i] } - return RealTensor(this.shape, resBuffer) + return RealTensor(newThis.shape, resBuffer) } override fun RealTensor.plusAssign(value: Double) { - //todo should be change with broadcasting for (i in this.buffer.array.indices) { this.buffer.array[i] += value } @@ -88,19 +148,33 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra + this - other.buffer.array[i] + } + return RealTensor(other.shape, resBuffer) } override fun RealTensor.minus(value: Double): RealTensor { - TODO("Alya") + val resBuffer = DoubleArray(this.buffer.size) { i -> + this.buffer.array[i] - value + } + return RealTensor(this.shape, resBuffer) } override fun RealTensor.minus(other: RealTensor): RealTensor { - TODO("Alya") + val broadcast = broadcastTensors(this, other) + val newThis = broadcast[0] + val newOther = broadcast[1] + val resBuffer = DoubleArray(newThis.buffer.size) { i -> + newThis.buffer.array[i] - newOther.buffer.array[i] + } + return RealTensor(newThis.shape, resBuffer) } override fun RealTensor.minusAssign(value: Double) { - TODO("Alya") + for (i in this.buffer.array.indices) { + this.buffer.array[i] -= value + } } override fun RealTensor.minusAssign(other: RealTensor) { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index 6f42623e0..bd47a1b76 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -13,6 +13,9 @@ public interface TensorAlgebra> { public fun TensorType.copy(): TensorType + public fun broadcastShapes(vararg shapes: IntArray): IntArray + public fun broadcastTensors(vararg tensors: RealTensor): List + public operator fun T.plus(other: TensorType): TensorType public operator fun TensorType.plus(value: T): TensorType public operator fun TensorType.plus(other: TensorType): TensorType diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt index 8e95922b8..18639bf3c 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt @@ -2,6 +2,8 @@ package space.kscience.kmath.tensors import space.kscience.kmath.structures.array import kotlin.test.Test +import kotlin.test.assertFails +import kotlin.test.assertFailsWith import kotlin.test.assertTrue class TestRealTensorAlgebra { @@ -64,4 +66,49 @@ class TestRealTensorAlgebra { 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)) } + + @Test + fun broadcastShapes() = RealTensorAlgebra { + assertTrue(this.broadcastShapes( + intArrayOf(2, 3), intArrayOf(1, 3), intArrayOf(1, 1, 1) + ) contentEquals intArrayOf(1, 2, 3)) + + assertTrue(this.broadcastShapes( + intArrayOf(6, 7), intArrayOf(5, 6, 1), intArrayOf(7,), intArrayOf(5, 1, 7) + ) contentEquals intArrayOf(5, 6, 7)) + } + + @Test + fun broadcastTensors() = RealTensorAlgebra { + val tensor1 = RealTensor(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + val tensor2 = RealTensor(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) + val tensor3 = RealTensor(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) + + val res = this.broadcastTensors(tensor1, tensor2, tensor3) + + assertTrue(res[0].shape contentEquals intArrayOf(1, 2, 3)) + 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)) + } + + @Test + fun minusTensor() = RealTensorAlgebra { + val tensor1 = RealTensor(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + val tensor2 = RealTensor(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) + 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((tensor3 - tensor1).shape contentEquals intArrayOf(1, 2, 3)) + assertTrue((tensor3 - tensor1).buffer.array + 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)) + } } \ No newline at end of file From 70e1861e536febfe9792fcbd3dde3dbd66cb4682 Mon Sep 17 00:00:00 2001 From: AlyaNovikova Date: Fri, 12 Mar 2021 15:25:47 +0300 Subject: [PATCH 017/178] remove extra import --- .../kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index a4ad54bfc..afe78ae08 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -2,7 +2,6 @@ package space.kscience.kmath.tensors import space.kscience.kmath.nd.MutableNDBuffer import space.kscience.kmath.structures.RealBuffer -import space.kscience.kmath.structures.ValueFlag import space.kscience.kmath.structures.array import kotlin.math.max From 626d5c98fa843fe6833cf300f8b71871d54474b1 Mon Sep 17 00:00:00 2001 From: AlyaNovikova Date: Fri, 12 Mar 2021 15:43:44 +0300 Subject: [PATCH 018/178] change IllegalArgumentException to RuntimeException --- .../kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index afe78ae08..9e090e376 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -75,7 +75,7 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra Date: Sat, 13 Mar 2021 19:30:58 +0300 Subject: [PATCH 019/178] add buffered tensor + lu --- .../kscience/kmath/tensors/BufferTensor.kt | 33 --------- .../kscience/kmath/tensors/BufferedTensor.kt | 33 +++++++++ .../kmath/tensors/RealTensorAlgebra.kt | 69 +++++++++++++++---- .../kscience/kmath/tensors/TensorAlgebra.kt | 5 +- 4 files changed, 92 insertions(+), 48 deletions(-) delete mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferTensor.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferTensor.kt deleted file mode 100644 index 817c51f11..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferTensor.kt +++ /dev/null @@ -1,33 +0,0 @@ -package space.kscience.kmath.tensors - -import space.kscience.kmath.linear.BufferMatrix -import space.kscience.kmath.linear.RealMatrixContext.toBufferMatrix -import space.kscience.kmath.nd.Matrix -import space.kscience.kmath.nd.MutableNDBuffer -import space.kscience.kmath.nd.Structure2D -import space.kscience.kmath.nd.as2D -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferAccessor2D -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.toList - -public open class BufferTensor( - override val shape: IntArray, - buffer: MutableBuffer -) : - TensorStructure, - MutableNDBuffer( - TensorStrides(shape), - buffer - ) - - -public fun BufferTensor.toBufferMatrix(): BufferMatrix { - return BufferMatrix(shape[0], shape[1], this.buffer) -} - -// T??? -public fun BufferMatrix.BufferTensor(): BufferTensor { - return BufferTensor(intArrayOf(rowNum, colNum), BufferAccessor2D(rowNum, colNum, Buffer.Companion::real).create(this)) -} - diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt new file mode 100644 index 000000000..9ffe2db61 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt @@ -0,0 +1,33 @@ +package space.kscience.kmath.tensors + +import space.kscience.kmath.linear.BufferMatrix +import space.kscience.kmath.nd.MutableNDBuffer +import space.kscience.kmath.structures.* +import space.kscience.kmath.structures.BufferAccessor2D + +public open class BufferedTensor( + override val shape: IntArray, + buffer: MutableBuffer +) : + TensorStructure, + MutableNDBuffer( + TensorStrides(shape), + buffer + ) { + + public operator fun get(i: Int, j: Int): T{ + check(this.dimension == 2) {"Not matrix"} + return this[intArrayOf(i, j)] + } + + public operator fun set(i: Int, j: Int, value: T): Unit{ + check(this.dimension == 2) {"Not matrix"} + this[intArrayOf(i, j)] = value + } + +} + +public class IntTensor( + shape: IntArray, + buffer: IntArray +) : BufferedTensor(shape, IntBuffer(buffer)) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index e38056097..3e21a3a98 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -1,24 +1,19 @@ package space.kscience.kmath.tensors -import space.kscience.kmath.linear.BufferMatrix -import space.kscience.kmath.linear.RealMatrixContext.toBufferMatrix -import space.kscience.kmath.nd.MutableNDBuffer -import space.kscience.kmath.nd.as2D -import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.RealBuffer import space.kscience.kmath.structures.array -import space.kscience.kmath.structures.toList +import kotlin.math.abs public class RealTensor( shape: IntArray, buffer: DoubleArray -) : BufferTensor(shape, RealBuffer(buffer)) +) : BufferedTensor(shape, RealBuffer(buffer)) public class RealTensorAlgebra : TensorPartialDivisionAlgebra { override fun RealTensor.value(): Double { - check(this.shape contentEquals intArrayOf(1)) { + check(this.shape contentEquals intArrayOf(1)) { "Inconsistent value for tensor of shape ${shape.toList()}" } return this.buffer.array[0] @@ -51,7 +46,8 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra { - TODO() + override fun RealTensor.lu(): Pair { + // todo checks + val lu = this.copy() + val m = this.shape[0] + val pivot = IntArray(m) + + + // Initialize permutation array and parity + for (row in 0 until m) pivot[row] = row + var even = true + + for (i in 0 until m) { + var maxA = -1.0 + var iMax = i + + for (k in i until m) { + val absA = abs(lu[k, i]) + if (absA > maxA) { + maxA = absA + iMax = k + } + } + + //todo check singularity + + if (iMax != i) { + + val j = pivot[i] + pivot[i] = pivot[iMax] + pivot[iMax] = j + even != even + + for (k in 0 until m) { + val tmp = lu[i, k] + lu[i, k] = lu[iMax, k] + lu[iMax, k] = tmp + } + + } + + for (j in i + 1 until m) { + lu[j, i] /= lu[i, i] + for (k in i + 1 until m) { + lu[j, k] -= lu[j, i] * lu[i, k] + } + } + } + return Pair(lu, IntTensor(intArrayOf(m), pivot)) } - override fun luUnpack(A_LU: RealTensor, pivots: RealTensor): Triple { - TODO("Not yet implemented") + override fun luUnpack(A_LU: RealTensor, pivots: IntTensor): Triple { + // todo checks + } override fun RealTensor.svd(): Triple { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index 6f42623e0..0dbcae044 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -78,11 +78,12 @@ public interface TensorPartialDivisionAlgebra public fun TensorType.log(): TensorType public fun TensorType.logAssign(): Unit + // todo change type of pivots //https://pytorch.org/docs/stable/generated/torch.lu.html - public fun TensorType.lu(): Pair + public fun TensorType.lu(): Pair //https://pytorch.org/docs/stable/generated/torch.lu_unpack.html - public fun luUnpack(A_LU: TensorType, pivots: TensorType): Triple + public fun luUnpack(A_LU: TensorType, pivots: IntTensor): Triple //https://pytorch.org/docs/stable/generated/torch.svd.html public fun TensorType.svd(): Triple From 8f88a101d24faee0504228c57642bb980a7d48e4 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Sat, 13 Mar 2021 20:51:15 +0300 Subject: [PATCH 020/178] complete lu for matrix --- .../kmath/tensors/RealTensorAlgebra.kt | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index 9e040fcd8..f91f44519 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -35,7 +35,10 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra { + override fun luUnpack(lu: RealTensor, pivots: IntTensor): Triple { // todo checks + val n = lu.shape[0] + val p = zeroesLike(lu) + pivots.buffer.array.forEachIndexed { i, pivot -> + p[i, pivot] = 1.0 + } + val l = zeroesLike(lu) + val u = zeroesLike(lu) + for (i in 0 until n){ + for (j in 0 until n){ + if (i == j) { + l[i, j] = 1.0 + } + if (j < i) { + l[i, j] = lu[i, j] + } + if (j >= i) { + u[i, j] = lu[i, j] + } + } + } + return Triple(p, l, u) } override fun RealTensor.svd(): Triple { From 384415dc98ae27125f894798057f6052103e2594 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Sat, 13 Mar 2021 19:16:13 +0000 Subject: [PATCH 021/178] utils module for tensors --- .../kscience/kmath/tensors/BufferedTensor.kt | 28 ++++-- .../kmath/tensors/RealTensorAlgebra.kt | 63 ------------ .../kscience/kmath/tensors/TensorAlgebra.kt | 46 +-------- .../kscience/kmath/tensors/TensorStrides.kt | 6 +- .../space/kscience/kmath/tensors/utils.kt | 96 +++++++++++++++++++ .../kmath/tensors/TestRealTensorAlgebra.kt | 8 +- 6 files changed, 124 insertions(+), 123 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt index 9ffe2db61..29605024d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt @@ -1,9 +1,8 @@ package space.kscience.kmath.tensors -import space.kscience.kmath.linear.BufferMatrix import space.kscience.kmath.nd.MutableNDBuffer import space.kscience.kmath.structures.* -import space.kscience.kmath.structures.BufferAccessor2D + public open class BufferedTensor( override val shape: IntArray, @@ -15,13 +14,13 @@ public open class BufferedTensor( buffer ) { - public operator fun get(i: Int, j: Int): T{ - check(this.dimension == 2) {"Not matrix"} - return this[intArrayOf(i, j)] + public operator fun get(i: Int, j: Int): T { + check(this.dimension == 2) { "Not matrix" } + return this[intArrayOf(i, j)] } - public operator fun set(i: Int, j: Int, value: T): Unit{ - check(this.dimension == 2) {"Not matrix"} + public operator fun set(i: Int, j: Int, value: T): Unit { + check(this.dimension == 2) { "Not matrix" } this[intArrayOf(i, j)] = value } @@ -31,3 +30,18 @@ public class IntTensor( shape: IntArray, buffer: IntArray ) : BufferedTensor(shape, IntBuffer(buffer)) + +public class LongTensor( + shape: IntArray, + buffer: LongArray +) : BufferedTensor(shape, LongBuffer(buffer)) + +public class FloatTensor( + shape: IntArray, + buffer: FloatArray +) : BufferedTensor(shape, FloatBuffer(buffer)) + +public class RealTensor( + shape: IntArray, + buffer: DoubleArray +) : BufferedTensor(shape, RealBuffer(buffer)) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index f91f44519..b3e54f077 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -6,11 +6,6 @@ import kotlin.math.abs import kotlin.math.max -public class RealTensor( - shape: IntArray, - buffer: DoubleArray -) : BufferedTensor(shape, RealBuffer(buffer)) - public class RealTensorAlgebra : TensorPartialDivisionAlgebra { override fun RealTensor.value(): Double { @@ -54,64 +49,6 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra { - val totalShape = broadcastShapes(*(tensors.map { it.shape }).toTypedArray()) - val n = totalShape.reduce{ acc, i -> acc * i } - - val res = ArrayList(0) - for (tensor in tensors) { - val resTensor = RealTensor(totalShape, DoubleArray(n)) - - for (linearIndex in 0 until n) { - val totalMultiIndex = resTensor.strides.index(linearIndex) - val curMultiIndex = tensor.shape.copyOf() - - val offset = totalMultiIndex.size - curMultiIndex.size - - for (i in curMultiIndex.indices) { - if (curMultiIndex[i] != 1) { - curMultiIndex[i] = totalMultiIndex[i + offset] - } else { - curMultiIndex[i] = 0 - } - } - - val curLinearIndex = tensor.strides.offset(curMultiIndex) - resTensor.buffer.array[linearIndex] = tensor.buffer.array[curLinearIndex] - } - res.add(resTensor) - } - - return res - } override fun Double.plus(other: RealTensor): RealTensor { val resBuffer = DoubleArray(other.buffer.size) { i -> diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index ec257e45c..280acf8ea 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -13,9 +13,6 @@ public interface TensorAlgebra> { public fun TensorType.copy(): TensorType - public fun broadcastShapes(vararg shapes: IntArray): IntArray - public fun broadcastTensors(vararg tensors: RealTensor): List - public operator fun T.plus(other: TensorType): TensorType public operator fun TensorType.plus(value: T): TensorType public operator fun TensorType.plus(other: TensorType): TensorType @@ -87,45 +84,4 @@ public interface TensorPartialDivisionAlgebra //https://pytorch.org/docs/stable/generated/torch.symeig.html public fun TensorType.symEig(eigenvectors: Boolean = true): Pair -} - -public inline fun , - TorchTensorAlgebraType : TensorAlgebra> - TorchTensorAlgebraType.checkShapeCompatible( - a: TensorType, b: TensorType -): Unit = - check(a.shape contentEquals b.shape) { - "Tensors must be of identical shape" - } - -public inline fun , - TorchTensorAlgebraType : TensorAlgebra> - TorchTensorAlgebraType.checkDot(a: TensorType, b: TensorType): Unit { - val sa = a.shape - val sb = b.shape - val na = sa.size - val nb = sb.size - var status: Boolean - if (nb == 1) { - status = sa.last() == sb[0] - } else { - status = sa.last() == sb[nb - 2] - if ((na > 2) and (nb > 2)) { - status = status and - (sa.take(nb - 2).toIntArray() contentEquals sb.take(nb - 2).toIntArray()) - } - } - check(status) { "Incompatible shapes $sa and $sb for dot product" } -} - -public inline fun , - TorchTensorAlgebraType : TensorAlgebra> - TorchTensorAlgebraType.checkTranspose(dim: Int, i: Int, j: Int): Unit = - check((i < dim) and (j < dim)) { - "Cannot transpose $i to $j for a tensor of dim $dim" - } - -public inline fun , - TorchTensorAlgebraType : TensorAlgebra> - TorchTensorAlgebraType.checkView(a: TensorType, shape: IntArray): Unit = - check(a.shape.reduce(Int::times) == shape.reduce(Int::times)) \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStrides.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStrides.kt index d6a6f5f16..d1d1204b4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStrides.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStrides.kt @@ -5,7 +5,7 @@ import space.kscience.kmath.nd.offsetFromIndex import kotlin.math.max -public inline fun stridesFromShape(shape: IntArray): IntArray { +internal inline fun stridesFromShape(shape: IntArray): IntArray { val nDim = shape.size val res = IntArray(nDim) if (nDim == 0) @@ -22,7 +22,7 @@ public inline fun stridesFromShape(shape: IntArray): IntArray { } -public inline fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): IntArray { +internal inline fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): IntArray { val res = IntArray(nDim) var current = offset var strideIndex = 0 @@ -35,7 +35,7 @@ public inline fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): In return res } -public inline fun nextIndex(index: IntArray, shape: IntArray, nDim: Int): IntArray { +internal inline fun nextIndex(index: IntArray, shape: IntArray, nDim: Int): IntArray { val res = index.copyOf() var current = nDim - 1 var carry = 0 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt new file mode 100644 index 000000000..65409bb15 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt @@ -0,0 +1,96 @@ +package space.kscience.kmath.tensors + +import space.kscience.kmath.structures.array +import kotlin.math.max + + +internal inline fun broadcastShapes(vararg shapes: IntArray): IntArray { + var totalDim = 0 + for (shape in shapes) { + totalDim = max(totalDim, shape.size) + } + + val totalShape = IntArray(totalDim) { 0 } + for (shape in shapes) { + for (i in shape.indices) { + val curDim = shape[i] + val offset = totalDim - shape.size + totalShape[i + offset] = max(totalShape[i + offset], curDim) + } + } + + for (shape in shapes) { + for (i in shape.indices) { + val curDim = shape[i] + val offset = totalDim - shape.size + if (curDim != 1 && totalShape[i + offset] != curDim) { + throw RuntimeException("Shapes are not compatible and cannot be broadcast") + } + } + } + + return totalShape +} + +internal inline fun broadcastTensors(vararg tensors: RealTensor): List { + val totalShape = broadcastShapes(*(tensors.map { it.shape }).toTypedArray()) + val n = totalShape.reduce { acc, i -> acc * i } + + val res = ArrayList(0) + for (tensor in tensors) { + val resTensor = RealTensor(totalShape, DoubleArray(n)) + + for (linearIndex in 0 until n) { + val totalMultiIndex = resTensor.strides.index(linearIndex) + val curMultiIndex = tensor.shape.copyOf() + + val offset = totalMultiIndex.size - curMultiIndex.size + + for (i in curMultiIndex.indices) { + if (curMultiIndex[i] != 1) { + curMultiIndex[i] = totalMultiIndex[i + offset] + } else { + curMultiIndex[i] = 0 + } + } + + val curLinearIndex = tensor.strides.offset(curMultiIndex) + resTensor.buffer.array[linearIndex] = tensor.buffer.array[curLinearIndex] + } + res.add(resTensor) + } + + return res +} + +internal inline fun , + TorchTensorAlgebraType : TensorAlgebra> + TorchTensorAlgebraType.checkDot(a: TensorType, b: TensorType): Unit { + val sa = a.shape + val sb = b.shape + val na = sa.size + val nb = sb.size + var status: Boolean + if (nb == 1) { + status = sa.last() == sb[0] + } else { + status = sa.last() == sb[nb - 2] + if ((na > 2) and (nb > 2)) { + status = status and + (sa.take(nb - 2).toIntArray() contentEquals sb.take(nb - 2).toIntArray()) + } + } + check(status) { "Incompatible shapes $sa and $sb for dot product" } +} + +internal inline fun , + TorchTensorAlgebraType : TensorAlgebra> + TorchTensorAlgebraType.checkTranspose(dim: Int, i: Int, j: Int): Unit = + check((i < dim) and (j < dim)) { + "Cannot transpose $i to $j for a tensor of dim $dim" + } + +internal inline fun , + TorchTensorAlgebraType : TensorAlgebra> + TorchTensorAlgebraType.checkView(a: TensorType, shape: IntArray): Unit = + check(a.shape.reduce(Int::times) == shape.reduce(Int::times)) \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt index c9fd6bb3a..7c27f5fa9 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt @@ -2,8 +2,6 @@ package space.kscience.kmath.tensors import space.kscience.kmath.structures.array import kotlin.test.Test -import kotlin.test.assertFails -import kotlin.test.assertFailsWith import kotlin.test.assertTrue class TestRealTensorAlgebra { @@ -51,11 +49,11 @@ class TestRealTensorAlgebra { @Test fun broadcastShapes() = RealTensorAlgebra { - assertTrue(this.broadcastShapes( + assertTrue(broadcastShapes( intArrayOf(2, 3), intArrayOf(1, 3), intArrayOf(1, 1, 1) ) contentEquals intArrayOf(1, 2, 3)) - assertTrue(this.broadcastShapes( + assertTrue(broadcastShapes( intArrayOf(6, 7), intArrayOf(5, 6, 1), intArrayOf(7,), intArrayOf(5, 1, 7) ) contentEquals intArrayOf(5, 6, 7)) } @@ -66,7 +64,7 @@ class TestRealTensorAlgebra { val tensor2 = RealTensor(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) val tensor3 = RealTensor(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) - val res = this.broadcastTensors(tensor1, tensor2, tensor3) + val res = broadcastTensors(tensor1, tensor2, tensor3) assertTrue(res[0].shape contentEquals intArrayOf(1, 2, 3)) assertTrue(res[1].shape contentEquals intArrayOf(1, 2, 3)) From c02f71263ded2c41806c821c351c58fd40d868ec Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Sun, 14 Mar 2021 21:18:20 +0000 Subject: [PATCH 022/178] Adding the interfaces for AnalyticTensorAlgebra and LinearOpsTensorAlgebra --- .../kmath/tensors/AnalyticTensorAlgebra.kt | 112 +++++++++++ .../kmath/tensors/LinearOpsTensorAlgebra.kt | 43 ++++ .../tensors/RealAnalyticTensorAlgebra.kt | 148 ++++++++++++++ .../tensors/RealLinearOpsTensorAlgebra.kt | 133 +++++++++++++ .../kmath/tensors/RealTensorAlgebra.kt | 185 +++++++----------- .../kscience/kmath/tensors/TensorAlgebra.kt | 93 +++++---- .../tensors/TensorPartialDivisionAlgebra.kt | 27 +++ 7 files changed, 586 insertions(+), 155 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt new file mode 100644 index 000000000..17a25b6b3 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt @@ -0,0 +1,112 @@ +package space.kscience.kmath.tensors + + +public interface AnalyticTensorAlgebra> : + TensorPartialDivisionAlgebra { + + //https://pytorch.org/docs/stable/generated/torch.exp.html + public fun TensorType.exp(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.log.html + public fun TensorType.log(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.sqrt.html + public fun TensorType.sqrt(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.square.html + public fun TensorType.square(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.acos.html#torch.cos + public fun TensorType.cos(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.acos.html#torch.acos + public fun TensorType.acos(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.cosh + public fun TensorType.cosh(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.acosh + public fun TensorType.acosh(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sin + public fun TensorType.sin(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asin + public fun TensorType.asin(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sinh + public fun TensorType.sinh(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asinh + public fun TensorType.asinh(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.atan.html#torch.tan + public fun TensorType.tan(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.atan.html#torch.atan + public fun TensorType.atan(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.tanh + public fun TensorType.tanh(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.atanh + public fun TensorType.atanh(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.ceil.html#torch.ceil + public fun TensorType.ceil(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.floor.html#torch.floor + public fun TensorType.floor(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.clamp.html#torch.clamp + public fun TensorType.clamp(min: T, max: T): TensorType + + //https://pytorch.org/docs/stable/generated/torch.erf.html#torch.erf + public fun TensorType.erf(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.erfinv.html#torch.erfinv + public fun TensorType.erfinv(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.erfc.html#torch.erfc + public fun TensorType.erfc(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.lerp.html#torch.lerp + public fun TensorType.lerp(end: TensorType, weight: TensorType): TensorType + + //https://pytorch.org/docs/stable/generated/torch.lgamma.html#torch.lgamma + public fun TensorType.lgamma(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.logit.html#torch.logit + public fun TensorType.logit(eps: T): TensorType + + //https://pytorch.org/docs/stable/generated/torch.igamma.html#torch.igamma + public fun TensorType.igamma(other: TensorType): TensorType + + //https://pytorch.org/docs/stable/generated/torch.igammac.html#torch.igammac + public fun TensorType.igammac(other: TensorType): TensorType + + //https://pytorch.org/docs/stable/generated/torch.mvlgamma.html#torch.mvlgamma + public fun TensorType.mvlgamma(dimensions: Int): TensorType + + //https://pytorch.org/docs/stable/generated/torch.polygamma.html#torch.polygamma + public fun TensorType.polygamma(order: Int): TensorType + + //https://pytorch.org/docs/stable/generated/torch.pow.html#torch.pow + public fun TensorType.pow(exponent: T): TensorType + + //https://pytorch.org/docs/stable/generated/torch.round.html#torch.round + public fun TensorType.round(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.sigmoid.html#torch.sigmoid + public fun TensorType.sigmoid(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.sinc.html#torch.sinc + public fun TensorType.sinc(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.heaviside.html#torch.heaviside + public fun TensorType.heaviside(values: TensorType): TensorType + + //https://pytorch.org/docs/stable/generated/torch.trapz.html#torch.trapz + public fun TensorType.trapz(xValues: TensorType, dim: Int): TensorType + +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt new file mode 100644 index 000000000..bd9cbfd45 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt @@ -0,0 +1,43 @@ +package space.kscience.kmath.tensors + + +public interface LinearOpsTensorAlgebra> : + TensorPartialDivisionAlgebra { + + //https://pytorch.org/docs/stable/generated/torch.eye.html + public fun eye(n: Int): TensorType + + //https://pytorch.org/docs/stable/generated/torch.matmul.html + public infix fun TensorType.dot(other: TensorType): TensorType + + //https://pytorch.org/docs/stable/generated/torch.diag_embed.html + public fun diagonalEmbedding( + diagonalEntries: TensorType, + offset: Int = 0, dim1: Int = -2, dim2: Int = -1 + ): TensorType + + //https://pytorch.org/docs/stable/linalg.html#torch.linalg.det + public fun TensorType.det(): TensorType + + //https://pytorch.org/docs/stable/linalg.html#torch.linalg.inv + public fun TensorType.inv(): TensorType + + //https://pytorch.org/docs/stable/linalg.html#torch.linalg.cholesky + public fun TensorType.cholesky(): TensorType + + //https://pytorch.org/docs/stable/linalg.html#torch.linalg.qr + public fun TensorType.qr(): TensorType + + //https://pytorch.org/docs/stable/generated/torch.lu.html + public fun TensorType.lu(): Pair + + //https://pytorch.org/docs/stable/generated/torch.lu_unpack.html + public fun luPivot(aLU: TensorType, pivots: IntTensor): Triple + + //https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd + public fun TensorType.svd(): Triple + + //https://pytorch.org/docs/stable/generated/torch.symeig.html + public fun TensorType.symEig(eigenvectors: Boolean = true): Pair + +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt new file mode 100644 index 000000000..cfecac0f4 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt @@ -0,0 +1,148 @@ +package space.kscience.kmath.tensors + +public class RealAnalyticTensorAlgebra: + AnalyticTensorAlgebra, + RealTensorAlgebra() +{ + override fun RealTensor.exp(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.log(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.sqrt(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.square(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.cos(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.acos(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.cosh(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.acosh(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.sin(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.asin(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.sinh(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.asinh(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.tan(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.atan(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.tanh(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.atanh(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.ceil(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.floor(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.clamp(min: Double, max: Double): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.erf(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.erfinv(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.erfc(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.lerp(end: RealTensor, weight: RealTensor): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.lgamma(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.logit(eps: Double): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.igamma(other: RealTensor): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.igammac(other: RealTensor): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.mvlgamma(dimensions: Int): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.polygamma(order: Int): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.pow(exponent: Double): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.round(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.sigmoid(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.sinc(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.heaviside(values: RealTensor): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.trapz(xValues: RealTensor, dim: Int): RealTensor { + TODO("Not yet implemented") + } + + +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt new file mode 100644 index 000000000..18c2050c0 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt @@ -0,0 +1,133 @@ +package space.kscience.kmath.tensors + +import space.kscience.kmath.structures.array + +public class RealLinearOpsTensorAlgebra : + LinearOpsTensorAlgebra, + RealTensorAlgebra() +{ + override fun eye(n: Int): RealTensor { + val shape = intArrayOf(n, n) + val buffer = DoubleArray(n * n) { 0.0 } + val res = RealTensor(shape, buffer) + for (i in 0 until n) { + res[intArrayOf(i, i)] = 1.0 + } + return res + } + + + override fun RealTensor.dot(other: RealTensor): RealTensor { + TODO("Alya") + } + + override fun diagonalEmbedding(diagonalEntries: RealTensor, offset: Int, dim1: Int, dim2: Int): RealTensor { + TODO("Alya") + } + + + override fun RealTensor.lu(): Pair { + // todo checks + val lu = this.copy() + val m = this.shape[0] + val pivot = IntArray(m) + + + // Initialize permutation array and parity + for (row in 0 until m) pivot[row] = row + var even = true + + for (i in 0 until m) { + var maxA = -1.0 + var iMax = i + + for (k in i until m) { + val absA = kotlin.math.abs(lu[k, i]) + if (absA > maxA) { + maxA = absA + iMax = k + } + } + + //todo check singularity + + if (iMax != i) { + + val j = pivot[i] + pivot[i] = pivot[iMax] + pivot[iMax] = j + even != even + + for (k in 0 until m) { + val tmp = lu[i, k] + lu[i, k] = lu[iMax, k] + lu[iMax, k] = tmp + } + + } + + for (j in i + 1 until m) { + lu[j, i] /= lu[i, i] + for (k in i + 1 until m) { + lu[j, k] -= lu[j, i] * lu[i, k] + } + } + } + return Pair(lu, IntTensor(intArrayOf(m), pivot)) + } + + override fun luPivot(lu: RealTensor, pivots: IntTensor): Triple { + // todo checks + val n = lu.shape[0] + val p = lu.zeroesLike() + pivots.buffer.array.forEachIndexed { i, pivot -> + p[i, pivot] = 1.0 + } + val l = lu.zeroesLike() + val u = lu.zeroesLike() + + for (i in 0 until n) { + for (j in 0 until n) { + if (i == j) { + l[i, j] = 1.0 + } + if (j < i) { + l[i, j] = lu[i, j] + } + if (j >= i) { + u[i, j] = lu[i, j] + } + } + } + return Triple(p, l, u) + } + + override fun RealTensor.det(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.inv(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.cholesky(): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.qr(): RealTensor { + TODO("Not yet implemented") + } + + + override fun RealTensor.svd(): Triple { + TODO("Not yet implemented") + } + + override fun RealTensor.symEig(eigenvectors: Boolean): Pair { + TODO("Not yet implemented") + } + +} + +public inline fun RealLinearOpsTensorAlgebra(block: RealTensorAlgebra.() -> R): R = + RealTensorAlgebra().block() \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index b3e54f077..05e2b57d2 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -1,12 +1,9 @@ package space.kscience.kmath.tensors -import space.kscience.kmath.structures.RealBuffer import space.kscience.kmath.structures.array -import kotlin.math.abs -import kotlin.math.max -public class RealTensorAlgebra : TensorPartialDivisionAlgebra { +public open class RealTensorAlgebra : TensorPartialDivisionAlgebra { override fun RealTensor.value(): Double { check(this.shape contentEquals intArrayOf(1)) { @@ -15,24 +12,13 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra, dim: Int): RealTensor { TODO("Not yet implemented") } @@ -213,6 +246,10 @@ public class RealTensorAlgebra : TensorPartialDivisionAlgebra { - // todo checks - val lu = this.copy() - val m = this.shape[0] - val pivot = IntArray(m) - - - // Initialize permutation array and parity - for (row in 0 until m) pivot[row] = row - var even = true - - for (i in 0 until m) { - var maxA = -1.0 - var iMax = i - - for (k in i until m) { - val absA = abs(lu[k, i]) - if (absA > maxA) { - maxA = absA - iMax = k - } - } - - //todo check singularity - - if (iMax != i) { - - val j = pivot[i] - pivot[i] = pivot[iMax] - pivot[iMax] = j - even != even - - for (k in 0 until m) { - val tmp = lu[i, k] - lu[i, k] = lu[iMax, k] - lu[iMax, k] = tmp - } - - } - - for (j in i + 1 until m) { - lu[j, i] /= lu[i, i] - for (k in i + 1 until m) { - lu[j, k] -= lu[j, i] * lu[i, k] - } - } - } - return Pair(lu, IntTensor(intArrayOf(m), pivot)) - } - - override fun luUnpack(lu: RealTensor, pivots: IntTensor): Triple { - // todo checks - val n = lu.shape[0] - val p = zeroesLike(lu) - pivots.buffer.array.forEachIndexed { i, pivot -> - p[i, pivot] = 1.0 - } - val l = zeroesLike(lu) - val u = zeroesLike(lu) - - for (i in 0 until n){ - for (j in 0 until n){ - if (i == j) { - l[i, j] = 1.0 - } - if (j < i) { - l[i, j] = lu[i, j] - } - if (j >= i) { - u[i, j] = lu[i, j] - } - } - } - return Triple(p, l, u) - } - - override fun RealTensor.svd(): Triple { - /** - * Main first task for @AlyaNovikova - */ + override fun RealTensor.std(dim: Int, unbiased: Boolean, keepDim: Boolean): RealTensor { TODO("Not yet implemented") } - override fun RealTensor.symEig(eigenvectors: Boolean): Pair { + override fun RealTensor.variance(dim: Int, unbiased: Boolean, keepDim: Boolean): RealTensor { + TODO("Not yet implemented") + } + + override fun RealTensor.histc(bins: Int, min: Double, max: Double): RealTensor { TODO("Not yet implemented") } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index 280acf8ea..a53054e21 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -5,11 +5,17 @@ public interface TensorAlgebra> { public fun TensorType.value(): T - public fun eye(n: Int): TensorType public fun zeros(shape: IntArray): TensorType - public fun zeroesLike(other: TensorType): TensorType + public fun TensorType.zeroesLike(): TensorType public fun ones(shape: IntArray): TensorType - public fun onesLike(shape: IntArray): TensorType + public fun TensorType.onesLike(): TensorType + + + //https://pytorch.org/docs/stable/generated/torch.full.html + public fun full(shape: IntArray, value: T): TensorType + + //https://pytorch.org/docs/stable/generated/torch.full_like.html#torch.full_like + public fun TensorType.fullLike(value: T): TensorType public fun TensorType.copy(): TensorType @@ -33,15 +39,6 @@ public interface TensorAlgebra> { public operator fun TensorType.unaryMinus(): TensorType - //https://pytorch.org/docs/stable/generated/torch.matmul.html - public infix fun TensorType.dot(other: TensorType): TensorType - - //https://pytorch.org/docs/stable/generated/torch.diag_embed.html - public fun diagonalEmbedding( - diagonalEntries: TensorType, - offset: Int = 0, dim1: Int = -2, dim2: Int = -1 - ): TensorType - //https://pytorch.org/docs/stable/generated/torch.transpose.html public fun TensorType.transpose(i: Int, j: Int): TensorType @@ -53,35 +50,45 @@ public interface TensorAlgebra> { public fun TensorType.abs(): TensorType //https://pytorch.org/docs/stable/generated/torch.sum.html - public fun TensorType.sum(): TensorType + public fun TensorType.sum(dim: Int, keepDim: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.cumsum.html#torch.cumsum + public fun TensorType.cumsum(dim: Int): TensorType + + //https://pytorch.org/docs/stable/generated/torch.prod.html#torch.prod + public fun TensorType.prod(dim: Int, keepDim: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.cumprod.html#torch.cumprod + public fun TensorType.cumprod(dim: Int): TensorType + + //https://pytorch.org/docs/stable/generated/torch.max.html#torch.max + public fun TensorType.max(dim: Int, keepDim: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.cummax.html#torch.cummax + public fun TensorType.cummax(dim: Int): TensorType + + //https://pytorch.org/docs/stable/generated/torch.min.html#torch.min + public fun TensorType.min(dim: Int, keepDim: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.cummin.html#torch.cummin + public fun TensorType.cummin(dim: Int): TensorType + + //https://pytorch.org/docs/stable/generated/torch.median.html#torch.median + public fun TensorType.median(dim: Int, keepDim: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.maximum.html#torch.maximum + public fun maximum(lhs: TensorType, rhs: TensorType) + + //https://pytorch.org/docs/stable/generated/torch.minimum.html#torch.minimum + public fun minimum(lhs: TensorType, rhs: TensorType) + + //https://pytorch.org/docs/stable/generated/torch.sort.html#torch.sort + public fun TensorType.sort(dim: Int, keepDim: Boolean, descending: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.cat.html#torch.cat + public fun cat(tensors: List, dim: Int): TensorType + + //https://pytorch.org/docs/stable/generated/torch.flatten.html#torch.flatten + public fun TensorType.flatten(startDim: Int, endDim: Int): TensorType + } - -// https://proofwiki.org/wiki/Definition:Division_Algebra -public interface TensorPartialDivisionAlgebra> : - TensorAlgebra { - - public operator fun TensorType.div(value: T): TensorType - public operator fun TensorType.div(other: TensorType): TensorType - public operator fun TensorType.divAssign(value: T) - public operator fun TensorType.divAssign(other: TensorType) - - //https://pytorch.org/docs/stable/generated/torch.exp.html - public fun TensorType.exp(): TensorType - - //https://pytorch.org/docs/stable/generated/torch.log.html - public fun TensorType.log(): TensorType - - // todo change type of pivots - //https://pytorch.org/docs/stable/generated/torch.lu.html - public fun TensorType.lu(): Pair - - //https://pytorch.org/docs/stable/generated/torch.lu_unpack.html - public fun luUnpack(A_LU: TensorType, pivots: IntTensor): Triple - - //https://pytorch.org/docs/stable/generated/torch.svd.html - public fun TensorType.svd(): Triple - - //https://pytorch.org/docs/stable/generated/torch.symeig.html - public fun TensorType.symEig(eigenvectors: Boolean = true): Pair - -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt new file mode 100644 index 000000000..2d448fa8c --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt @@ -0,0 +1,27 @@ +package space.kscience.kmath.tensors + +// https://proofwiki.org/wiki/Definition:Division_Algebra +public interface TensorPartialDivisionAlgebra> : + TensorAlgebra { + + public operator fun TensorType.div(value: T): TensorType + public operator fun TensorType.div(other: TensorType): TensorType + public operator fun TensorType.divAssign(value: T) + public operator fun TensorType.divAssign(other: TensorType) + + //https://pytorch.org/docs/stable/generated/torch.mean.html#torch.mean + public fun TensorType.mean(dim: Int, keepDim: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.quantile.html#torch.quantile + public fun TensorType.quantile(q: T, dim: Int, keepDim: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.std.html#torch.std + public fun TensorType.std(dim: Int, unbiased: Boolean, keepDim: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.var.html#torch.var + public fun TensorType.variance(dim: Int, unbiased: Boolean, keepDim: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.histc.html#torch.histc + public fun TensorType.histc(bins: Int, min: T, max: T): TensorType + +} From 39a088912346078f3c3647ac262b2cf8c490aa4a Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Mon, 15 Mar 2021 07:50:20 +0000 Subject: [PATCH 023/178] Dev merge assemble fixed, tests still broken --- .../kmath/tensors/LinearOpsTensorAlgebra.kt | 2 +- .../tensors/RealAnalyticTensorAlgebra.kt | 4 +- .../tensors/RealLinearOpsTensorAlgebra.kt | 7 +-- .../kmath/tensors/RealTensorAlgebra.kt | 46 +++++++++---------- .../space/kscience/kmath/tensors/utils.kt | 4 +- .../kscience/kmath/tensors/TestRealTensor.kt | 4 +- .../kmath/tensors/TestRealTensorAlgebra.kt | 26 +++++------ 7 files changed, 48 insertions(+), 45 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt index bd9cbfd45..db1135a33 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt @@ -32,7 +32,7 @@ public interface LinearOpsTensorAlgebra> : public fun TensorType.lu(): Pair //https://pytorch.org/docs/stable/generated/torch.lu_unpack.html - public fun luPivot(aLU: TensorType, pivots: IntTensor): Triple + public fun luPivot(lu: TensorType, pivots: IntTensor): Triple //https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd public fun TensorType.svd(): Triple diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt index cfecac0f4..a93ebcb89 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt @@ -144,5 +144,7 @@ public class RealAnalyticTensorAlgebra: TODO("Not yet implemented") } +} -} \ No newline at end of file +public inline fun RealAnalyticTensorAlgebra(block: RealTensorAlgebra.() -> R): R = + RealAnalyticTensorAlgebra().block() \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt index 18c2050c0..98a5e581f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt @@ -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, @@ -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 RealLinearOpsTensorAlgebra(block: RealTensorAlgebra.() -> R): R = - RealTensorAlgebra().block() \ No newline at end of file + RealLinearOpsTensorAlgebra().block() \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index 05e2b57d2..10cc0edad 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -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 { @@ -9,7 +9,7 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra - other.buffer.array[i] + this + other.buffer.toDoubleArray()[i] + this } return RealTensor(other.shape, resBuffer) } @@ -50,34 +50,34 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra - 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 - 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 - other.buffer.array[i] * this + other.buffer.toDoubleArray()[i] * this } return RealTensor(other.shape, resBuffer) } @@ -116,28 +116,28 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra - 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 Date: Mon, 15 Mar 2021 08:31:19 +0000 Subject: [PATCH 024/178] Fixed tests with unsafe accessors --- .../kscience/kmath/structures/FloatBuffer.kt | 8 ++++ .../kscience/kmath/structures/IntBuffer.kt | 8 ++++ .../kscience/kmath/structures/LongBuffer.kt | 8 ++++ .../kscience/kmath/structures/RealBuffer.kt | 8 ++++ .../tensors/RealLinearOpsTensorAlgebra.kt | 5 +- .../kmath/tensors/RealTensorAlgebra.kt | 46 +++++++++---------- .../space/kscience/kmath/tensors/utils.kt | 4 +- 7 files changed, 59 insertions(+), 28 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt index 9fc7d55f3..dbcf35504 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt @@ -43,6 +43,14 @@ public fun Buffer.toFloatArray(): FloatArray = when(this) { else -> FloatArray(size, ::get) } +/** + * Returns a reference to [FloatArray] containing all of the elements of this [Buffer]. + */ +public fun Buffer.unsafeToFloatArray(): FloatArray = when(this) { + is FloatBuffer -> array + else -> throw RuntimeException("Failed to cast Buffer to FloatArray") +} + /** * Returns [FloatBuffer] over this array. * diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt index d3d0f79a5..d58451bc4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt @@ -42,6 +42,14 @@ public fun Buffer.toIntArray(): IntArray = when(this) { else -> IntArray(size, ::get) } +/** + * Returns a reference to [IntArray] containing all of the elements of this [Buffer]. + */ +public fun Buffer.unsafeToIntArray(): IntArray = when(this) { + is IntBuffer -> array + else -> throw RuntimeException("Failed to cast Buffer to IntArray") +} + /** * Returns [IntBuffer] over this array. * diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt index fec358421..3fa9bf861 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt @@ -42,6 +42,14 @@ public fun Buffer.toLongArray(): LongArray = when(this) { else -> LongArray(size, ::get) } +/** + * Returns a reference to [LongArray] containing all of the elements of this [Buffer]. + */ +public fun Buffer.unsafeToLongArray(): LongArray = when(this) { + is LongBuffer -> array + else -> throw RuntimeException("Failed to cast Buffer to LongArray") +} + /** * Returns [LongBuffer] over this array. * diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/RealBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/RealBuffer.kt index 01b533138..69e1ae9cd 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/RealBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/RealBuffer.kt @@ -47,6 +47,14 @@ public fun Buffer.toDoubleArray(): DoubleArray = when(this) { else -> DoubleArray(size, ::get) } +/** + * Returns a reference to [DoubleArray] containing all of the elements of this [Buffer]. + */ +public fun Buffer.unsafeToDoubleArray(): DoubleArray = when(this) { + is RealBuffer -> array + else -> throw RuntimeException("Failed to cast Buffer to DoubleArray") +} + /** * Returns [RealBuffer] over this array. * diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt index 98a5e581f..f73e4c4cd 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt @@ -1,7 +1,6 @@ package space.kscience.kmath.tensors -import space.kscience.kmath.structures.toDoubleArray -import space.kscience.kmath.structures.toIntArray +import space.kscience.kmath.structures.unsafeToIntArray public class RealLinearOpsTensorAlgebra : LinearOpsTensorAlgebra, @@ -81,7 +80,7 @@ public class RealLinearOpsTensorAlgebra : // todo checks val n = lu.shape[0] val p = lu.zeroesLike() - pivots.buffer.toIntArray().forEachIndexed { i, pivot -> + pivots.buffer.unsafeToIntArray().forEachIndexed { i, pivot -> p[i, pivot] = 1.0 } val l = lu.zeroesLike() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index 10cc0edad..ee0733577 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -1,6 +1,6 @@ package space.kscience.kmath.tensors -import space.kscience.kmath.structures.toDoubleArray +import space.kscience.kmath.structures.unsafeToDoubleArray public open class RealTensorAlgebra : TensorPartialDivisionAlgebra { @@ -9,7 +9,7 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra - other.buffer.toDoubleArray()[i] + this + other.buffer.unsafeToDoubleArray()[i] + this } return RealTensor(other.shape, resBuffer) } @@ -50,34 +50,34 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra - newThis.buffer.toDoubleArray()[i] + newOther.buffer.toDoubleArray()[i] + newThis.buffer.unsafeToDoubleArray()[i] + newOther.buffer.unsafeToDoubleArray()[i] } return RealTensor(newThis.shape, resBuffer) } override fun RealTensor.plusAssign(value: Double) { - for (i in this.buffer.toDoubleArray().indices) { - this.buffer.toDoubleArray()[i] += value + for (i in this.buffer.unsafeToDoubleArray().indices) { + this.buffer.unsafeToDoubleArray()[i] += value } } override fun RealTensor.plusAssign(other: RealTensor) { //todo should be change with broadcasting - for (i in this.buffer.toDoubleArray().indices) { - this.buffer.toDoubleArray()[i] += other.buffer.toDoubleArray()[i] + for (i in this.buffer.unsafeToDoubleArray().indices) { + this.buffer.unsafeToDoubleArray()[i] += other.buffer.unsafeToDoubleArray()[i] } } override fun Double.minus(other: RealTensor): RealTensor { val resBuffer = DoubleArray(other.buffer.size) { i -> - this - other.buffer.toDoubleArray()[i] + this - other.buffer.unsafeToDoubleArray()[i] } return RealTensor(other.shape, resBuffer) } override fun RealTensor.minus(value: Double): RealTensor { val resBuffer = DoubleArray(this.buffer.size) { i -> - this.buffer.toDoubleArray()[i] - value + this.buffer.unsafeToDoubleArray()[i] - value } return RealTensor(this.shape, resBuffer) } @@ -87,14 +87,14 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra - newThis.buffer.toDoubleArray()[i] - newOther.buffer.toDoubleArray()[i] + newThis.buffer.unsafeToDoubleArray()[i] - newOther.buffer.unsafeToDoubleArray()[i] } return RealTensor(newThis.shape, resBuffer) } override fun RealTensor.minusAssign(value: Double) { - for (i in this.buffer.toDoubleArray().indices) { - this.buffer.toDoubleArray()[i] -= value + for (i in this.buffer.unsafeToDoubleArray().indices) { + this.buffer.unsafeToDoubleArray()[i] -= value } } @@ -105,7 +105,7 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra - other.buffer.toDoubleArray()[i] * this + other.buffer.unsafeToDoubleArray()[i] * this } return RealTensor(other.shape, resBuffer) } @@ -116,28 +116,28 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra - this.buffer.toDoubleArray()[i] * other.buffer.toDoubleArray()[i] + this.buffer.unsafeToDoubleArray()[i] * other.buffer.unsafeToDoubleArray()[i] } return RealTensor(this.shape, resBuffer) } override fun RealTensor.timesAssign(value: Double) { //todo should be change with broadcasting - for (i in this.buffer.toDoubleArray().indices) { - this.buffer.toDoubleArray()[i] *= value + for (i in this.buffer.unsafeToDoubleArray().indices) { + this.buffer.unsafeToDoubleArray()[i] *= value } } override fun RealTensor.timesAssign(other: RealTensor) { //todo should be change with broadcasting - for (i in this.buffer.toDoubleArray().indices) { - this.buffer.toDoubleArray()[i] *= other.buffer.toDoubleArray()[i] + for (i in this.buffer.unsafeToDoubleArray().indices) { + this.buffer.unsafeToDoubleArray()[i] *= other.buffer.unsafeToDoubleArray()[i] } } override fun RealTensor.unaryMinus(): RealTensor { val resBuffer = DoubleArray(this.buffer.size) { i -> - this.buffer.toDoubleArray()[i].unaryMinus() + this.buffer.unsafeToDoubleArray()[i].unaryMinus() } return RealTensor(this.shape, resBuffer) } @@ -158,14 +158,14 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra Date: Mon, 15 Mar 2021 08:48:31 +0000 Subject: [PATCH 025/178] unsafe buffer casts moved to internal utils --- .../kscience/kmath/structures/FloatBuffer.kt | 8 ----- .../kscience/kmath/structures/IntBuffer.kt | 8 ----- .../kscience/kmath/structures/LongBuffer.kt | 8 ----- .../kscience/kmath/structures/RealBuffer.kt | 8 ----- .../tensors/RealLinearOpsTensorAlgebra.kt | 2 -- .../kmath/tensors/RealTensorAlgebra.kt | 2 -- .../space/kscience/kmath/tensors/utils.kt | 36 +++++++++++++++++-- .../kmath/tensors/TestRealTensorAlgebra.kt | 26 +++++++------- 8 files changed, 47 insertions(+), 51 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt index dbcf35504..9fc7d55f3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt @@ -43,14 +43,6 @@ public fun Buffer.toFloatArray(): FloatArray = when(this) { else -> FloatArray(size, ::get) } -/** - * Returns a reference to [FloatArray] containing all of the elements of this [Buffer]. - */ -public fun Buffer.unsafeToFloatArray(): FloatArray = when(this) { - is FloatBuffer -> array - else -> throw RuntimeException("Failed to cast Buffer to FloatArray") -} - /** * Returns [FloatBuffer] over this array. * diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt index d58451bc4..d3d0f79a5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt @@ -42,14 +42,6 @@ public fun Buffer.toIntArray(): IntArray = when(this) { else -> IntArray(size, ::get) } -/** - * Returns a reference to [IntArray] containing all of the elements of this [Buffer]. - */ -public fun Buffer.unsafeToIntArray(): IntArray = when(this) { - is IntBuffer -> array - else -> throw RuntimeException("Failed to cast Buffer to IntArray") -} - /** * Returns [IntBuffer] over this array. * diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt index 3fa9bf861..fec358421 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt @@ -42,14 +42,6 @@ public fun Buffer.toLongArray(): LongArray = when(this) { else -> LongArray(size, ::get) } -/** - * Returns a reference to [LongArray] containing all of the elements of this [Buffer]. - */ -public fun Buffer.unsafeToLongArray(): LongArray = when(this) { - is LongBuffer -> array - else -> throw RuntimeException("Failed to cast Buffer to LongArray") -} - /** * Returns [LongBuffer] over this array. * diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/RealBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/RealBuffer.kt index 69e1ae9cd..01b533138 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/RealBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/RealBuffer.kt @@ -47,14 +47,6 @@ public fun Buffer.toDoubleArray(): DoubleArray = when(this) { else -> DoubleArray(size, ::get) } -/** - * Returns a reference to [DoubleArray] containing all of the elements of this [Buffer]. - */ -public fun Buffer.unsafeToDoubleArray(): DoubleArray = when(this) { - is RealBuffer -> array - else -> throw RuntimeException("Failed to cast Buffer to DoubleArray") -} - /** * Returns [RealBuffer] over this array. * diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt index f73e4c4cd..dcd740356 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt @@ -1,7 +1,5 @@ package space.kscience.kmath.tensors -import space.kscience.kmath.structures.unsafeToIntArray - public class RealLinearOpsTensorAlgebra : LinearOpsTensorAlgebra, RealTensorAlgebra() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt index ee0733577..83a513a7a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt @@ -1,7 +1,5 @@ package space.kscience.kmath.tensors -import space.kscience.kmath.structures.unsafeToDoubleArray - public open class RealTensorAlgebra : TensorPartialDivisionAlgebra { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt index 04b4ddcbf..b03fb7dd7 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt @@ -1,6 +1,6 @@ package space.kscience.kmath.tensors -import space.kscience.kmath.structures.unsafeToDoubleArray +import space.kscience.kmath.structures.* import kotlin.math.max @@ -93,4 +93,36 @@ internal inline fun , internal inline fun , TorchTensorAlgebraType : TensorAlgebra> TorchTensorAlgebraType.checkView(a: TensorType, shape: IntArray): Unit = - check(a.shape.reduce(Int::times) == shape.reduce(Int::times)) \ No newline at end of file + check(a.shape.reduce(Int::times) == shape.reduce(Int::times)) + +/** + * Returns a reference to [IntArray] containing all of the elements of this [Buffer]. + */ +internal fun Buffer.unsafeToIntArray(): IntArray = when(this) { + is IntBuffer -> array + else -> throw RuntimeException("Failed to cast Buffer to IntArray") +} + +/** + * Returns a reference to [LongArray] containing all of the elements of this [Buffer]. + */ +internal fun Buffer.unsafeToLongArray(): LongArray = when(this) { + is LongBuffer -> array + else -> throw RuntimeException("Failed to cast Buffer to LongArray") +} + +/** + * Returns a reference to [FloatArray] containing all of the elements of this [Buffer]. + */ +internal fun Buffer.unsafeToFloatArray(): FloatArray = when(this) { + is FloatBuffer -> array + else -> throw RuntimeException("Failed to cast Buffer to FloatArray") +} + +/** + * Returns a reference to [DoubleArray] containing all of the elements of this [Buffer]. + */ +internal fun Buffer.unsafeToDoubleArray(): DoubleArray = when(this) { + is RealBuffer -> array + else -> throw RuntimeException("Failed to cast Buffer to DoubleArray") +} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt index 80e3c3eab..72bbf1787 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt @@ -1,6 +1,6 @@ package space.kscience.kmath.tensors -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.toDoubleArray() contentEquals doubleArrayOf(11.0,12.0)) + assertTrue(res.buffer.unsafeToDoubleArray() 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.toDoubleArray() contentEquals doubleArrayOf(0.0)) + assertTrue(res.buffer.unsafeToDoubleArray() 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.toDoubleArray() contentEquals doubleArrayOf(1.0, 3.0, 5.0, 2.0, 4.0, 6.0)) + assertTrue(res.buffer.unsafeToDoubleArray() 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.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)) + assertTrue(res01.buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + assertTrue(res02.buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0)) + assertTrue(res12.buffer.unsafeToDoubleArray() 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.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)) + assertTrue(res[0].buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + assertTrue(res[1].buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0)) + assertTrue(res[2].buffer.unsafeToDoubleArray() 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.toDoubleArray() contentEquals doubleArrayOf(9.0, 18.0, 27.0, 6.0, 15.0, 24.0)) + assertTrue((tensor2 - tensor1).buffer.unsafeToDoubleArray() 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.toDoubleArray() + assertTrue((tensor3 - tensor1).buffer.unsafeToDoubleArray() 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.toDoubleArray() contentEquals doubleArrayOf(490.0, 480.0, 470.0)) + assertTrue((tensor3 - tensor2).buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(490.0, 480.0, 470.0)) } } \ No newline at end of file From 2d2c5aa6840902db6c5688d19e2960b124b5e0d3 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Mon, 15 Mar 2021 15:18:21 +0300 Subject: [PATCH 026/178] matrixhelper --- .../kscience/kmath/tensors/BufferedTensor.kt | 53 ++++++++ .../tensors/RealLinearOpsTensorAlgebra.kt | 116 ++++++++++-------- 2 files changed, 120 insertions(+), 49 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt index 29605024d..4d89996a0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt @@ -13,6 +13,7 @@ public open class BufferedTensor( TensorStrides(shape), buffer ) { + /* public operator fun get(i: Int, j: Int): T { check(this.dimension == 2) { "Not matrix" } @@ -24,8 +25,60 @@ public open class BufferedTensor( this[intArrayOf(i, j)] = value } + */ } +//todo make generator mb nextMatrixIndex? +public class InnerMatrix(private val tensor: BufferedTensor){ + private var offset: Int = 0 + private val n : Int = tensor.shape.size + //stride? + private val step = tensor.shape[n - 1] * tensor.shape[n - 2] + + public operator fun get(i: Int, j: Int): T { + val index = tensor.strides.index(offset) + index[n - 2] = i + index[n - 1] = j + return tensor[index] + } + + public operator fun set(i: Int, j: Int, value: T): Unit { + val index = tensor.strides.index(offset) + index[n - 2] = i + index[n - 1] = j + tensor[index] = value + } + + public fun makeStep(){ + offset += step + } +} + +public class InnerVector(private val tensor: BufferedTensor){ + private var offset: Int = 0 + private val n : Int = tensor.shape.size + //stride? + private val step = tensor.shape[n - 1] + + public operator fun get(i: Int): T { + val index = tensor.strides.index(offset) + index[n - 1] = i + return tensor[index] + } + + public operator fun set(i: Int, value: T): Unit { + val index = tensor.strides.index(offset) + index[n - 1] = i + tensor[index] = value + } + + public fun makeStep(){ + offset += step + } +} + + +//todo default buffer = arrayOf(0)??? public class IntTensor( shape: IntArray, buffer: IntArray diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt index dcd740356..ab39fc6ac 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt @@ -2,8 +2,7 @@ package space.kscience.kmath.tensors public class RealLinearOpsTensorAlgebra : LinearOpsTensorAlgebra, - RealTensorAlgebra() -{ + RealTensorAlgebra() { override fun eye(n: Int): RealTensor { val shape = intArrayOf(n, n) val buffer = DoubleArray(n * n) { 0.0 } @@ -26,55 +25,71 @@ public class RealLinearOpsTensorAlgebra : override fun RealTensor.lu(): Pair { // todo checks - val lu = this.copy() - val m = this.shape[0] - val pivot = IntArray(m) - - - // Initialize permutation array and parity - for (row in 0 until m) pivot[row] = row - var even = true - - for (i in 0 until m) { - var maxA = -1.0 - var iMax = i - - for (k in i until m) { - val absA = kotlin.math.abs(lu[k, i]) - if (absA > maxA) { - maxA = absA - iMax = k - } - } - - //todo check singularity - - if (iMax != i) { - - val j = pivot[i] - pivot[i] = pivot[iMax] - pivot[iMax] = j - even != even - - for (k in 0 until m) { - val tmp = lu[i, k] - lu[i, k] = lu[iMax, k] - lu[iMax, k] = tmp - } - - } - - for (j in i + 1 until m) { - lu[j, i] /= lu[i, i] - for (k in i + 1 until m) { - lu[j, k] -= lu[j, i] * lu[i, k] - } - } + val luTensor = this.copy() + val lu = InnerMatrix(luTensor) + //stride TODO!!! move to generator? + var matCnt = 1 + for (i in 0 until this.shape.size - 2) { + matCnt *= this.shape[i] } - return Pair(lu, IntTensor(intArrayOf(m), pivot)) + val n = this.shape.size + val m = this.shape[n - 1] + val pivotsShape = IntArray(n - 1) { i -> + this.shape[i] + } + val pivotsTensor = IntTensor( + pivotsShape, + IntArray(matCnt * m) { 0 } + ) + val pivot = InnerVector(pivotsTensor) + for (i in 0 until matCnt) { + for (row in 0 until m) pivot[row] = row + + for (i in 0 until m) { + var maxA = -1.0 + var iMax = i + + for (k in i until m) { + val absA = kotlin.math.abs(lu[k, i]) + if (absA > maxA) { + maxA = absA + iMax = k + } + } + + //todo check singularity + + if (iMax != i) { + + val j = pivot[i] + pivot[i] = pivot[iMax] + pivot[iMax] = j + + for (k in 0 until m) { + val tmp = lu[i, k] + lu[i, k] = lu[iMax, k] + lu[iMax, k] = tmp + } + + } + + for (j in i + 1 until m) { + lu[j, i] /= lu[i, i] + for (k in i + 1 until m) { + lu[j, k] -= lu[j, i] * lu[i, k] + } + } + } + lu.makeStep() + pivot.makeStep() + } + + return Pair(luTensor, pivotsTensor) } override fun luPivot(lu: RealTensor, pivots: IntTensor): Triple { + TODO() + /* // todo checks val n = lu.shape[0] val p = lu.zeroesLike() @@ -97,9 +112,12 @@ public class RealLinearOpsTensorAlgebra : } } } - return Triple(p, l, u) + + return Triple(p, l, u)*/ } + + override fun RealTensor.det(): RealTensor { TODO("Not yet implemented") } @@ -127,5 +145,5 @@ public class RealLinearOpsTensorAlgebra : } -public inline fun RealLinearOpsTensorAlgebra(block: RealTensorAlgebra.() -> R): R = +public inline fun RealLinearOpsTensorAlgebra(block: RealLinearOpsTensorAlgebra.() -> R): R = RealLinearOpsTensorAlgebra().block() \ No newline at end of file From 50ed7ce28bb072f33a3527879fe8d9453cba6ac4 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Mon, 15 Mar 2021 12:54:46 +0000 Subject: [PATCH 027/178] ComplexTensorAlgebra interface --- .../kmath/tensors/ComplexTensorAlgebra.kt | 47 +++++++++++++++++++ .../kmath/tensors/ComplexTensorStructure.kt | 14 ++++++ .../tensors/RealAnalyticTensorAlgebra.kt | 2 +- .../tensors/RealLinearOpsTensorAlgebra.kt | 2 +- 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorStructure.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt new file mode 100644 index 000000000..3f5b7d667 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt @@ -0,0 +1,47 @@ +package space.kscience.kmath.tensors + +public interface ComplexTensorAlgebra, + ComplexTensorType : ComplexTensorStructure> + : TensorPartialDivisionAlgebra{ + + //https://pytorch.org/docs/stable/generated/torch.view_as_complex.html + public fun RealTensorType.viewAsComplex(): ComplexTensorType + + //https://pytorch.org/docs/stable/generated/torch.angle.html + public fun ComplexTensorType.angle(): RealTensorType + + //https://pytorch.org/docs/stable/generated/torch.stft.html#torch.stft + public fun ComplexTensorType.stft( + nFFT: Int, + hopLength: Int, + winLength: Int, + window: RealTensorType, + normalised: Boolean, + oneSided: Boolean + ) + + //https://pytorch.org/docs/stable/generated/torch.istft.html#torch.istft + public fun ComplexTensorType.istft( + nFFT: Int, + hopLength: Int, + winLength: Int, + window: RealTensorType, + center: Boolean, + normalised: Boolean, + oneSided: Boolean, + length: Int + ) + + //https://pytorch.org/docs/stable/generated/torch.bartlett_window.html#torch.bartlett_window + public fun bartlettWindow(windowLength: Int, periodic: Boolean): RealTensorType + + //https://pytorch.org/docs/stable/generated/torch.blackman_window.html#torch.blackman_window + public fun blackmanWindow(windowLength: Int, periodic: Boolean): RealTensorType + + //https://pytorch.org/docs/stable/generated/torch.hamming_window.html#torch.hamming_window + public fun hammingWindow(windowLength: Int, periodic: Boolean, alpha: T, beta: T): RealTensorType + + //https://pytorch.org/docs/stable/generated/torch.kaiser_window.html#torch.kaiser_window + public fun kaiserWindow(windowLength: Int, periodic: Boolean, beta: T): RealTensorType +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorStructure.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorStructure.kt new file mode 100644 index 000000000..0e0975830 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorStructure.kt @@ -0,0 +1,14 @@ +package space.kscience.kmath.tensors + +public interface ComplexTensorStructure> : TensorStructure { + + //https://pytorch.org/docs/master/generated/torch.view_as_real.html + public fun viewAsReal(): RealTensorType + + //https://pytorch.org/docs/stable/generated/torch.real.html + public fun realPart(): RealTensorType + + //https://pytorch.org/docs/stable/generated/torch.imag.html + public fun imaginaryPart(): RealTensorType + +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt index a93ebcb89..f610361fc 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt @@ -146,5 +146,5 @@ public class RealAnalyticTensorAlgebra: } -public inline fun RealAnalyticTensorAlgebra(block: RealTensorAlgebra.() -> R): R = +public inline fun RealAnalyticTensorAlgebra(block: RealAnalyticTensorAlgebra.() -> R): R = RealAnalyticTensorAlgebra().block() \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt index dcd740356..6b1957b8c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt @@ -127,5 +127,5 @@ public class RealLinearOpsTensorAlgebra : } -public inline fun RealLinearOpsTensorAlgebra(block: RealTensorAlgebra.() -> R): R = +public inline fun RealLinearOpsTensorAlgebra(block: RealLinearOpsTensorAlgebra.() -> R): R = RealLinearOpsTensorAlgebra().block() \ No newline at end of file From a3ca861ebe034fc1a8b08f18c2613df3ef81c785 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Mon, 15 Mar 2021 13:05:45 +0000 Subject: [PATCH 028/178] Rename FFTs --- .../space/kscience/kmath/tensors/ComplexTensorAlgebra.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt index 3f5b7d667..8399511a5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt @@ -12,7 +12,7 @@ public interface ComplexTensorAlgebra Date: Mon, 15 Mar 2021 16:59:50 +0000 Subject: [PATCH 029/178] RealTensor to DoubleTensor rename --- .../kscience/kmath/tensors/BufferedTensor.kt | 2 +- .../tensors/DoubleAnalyticTensorAlgebra.kt | 150 ++++++++++++++++++ ...bra.kt => DoubleLinearOpsTensorAlgebra.kt} | 26 +-- ...ensorAlgebra.kt => DoubleTensorAlgebra.kt} | 128 +++++++-------- .../tensors/RealAnalyticTensorAlgebra.kt | 150 ------------------ .../space/kscience/kmath/tensors/utils.kt | 6 +- .../kscience/kmath/tensors/TestRealTensor.kt | 4 +- .../kmath/tensors/TestRealTensorAlgebra.kt | 20 +-- 8 files changed, 243 insertions(+), 243 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/{RealLinearOpsTensorAlgebra.kt => DoubleLinearOpsTensorAlgebra.kt} (73%) rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/{RealTensorAlgebra.kt => DoubleTensorAlgebra.kt} (54%) delete mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt index 29605024d..066fb8708 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt @@ -41,7 +41,7 @@ public class FloatTensor( buffer: FloatArray ) : BufferedTensor(shape, FloatBuffer(buffer)) -public class RealTensor( +public class DoubleTensor( shape: IntArray, buffer: DoubleArray ) : BufferedTensor(shape, RealBuffer(buffer)) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt new file mode 100644 index 000000000..702049a20 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt @@ -0,0 +1,150 @@ +package space.kscience.kmath.tensors + +public class RealAnalyticTensorAlgebra: + AnalyticTensorAlgebra, + RealTensorAlgebra() +{ + override fun DoubleTensor.exp(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.log(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.sqrt(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.square(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.cos(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.acos(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.cosh(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.acosh(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.sin(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.asin(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.sinh(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.asinh(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.tan(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.atan(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.tanh(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.atanh(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.ceil(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.floor(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.clamp(min: Double, max: Double): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.erf(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.erfinv(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.erfc(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.lerp(end: DoubleTensor, weight: DoubleTensor): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.lgamma(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.logit(eps: Double): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.igamma(other: DoubleTensor): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.igammac(other: DoubleTensor): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.mvlgamma(dimensions: Int): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.polygamma(order: Int): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.pow(exponent: Double): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.round(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.sigmoid(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.sinc(): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.heaviside(values: DoubleTensor): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.trapz(xValues: DoubleTensor, dim: Int): DoubleTensor { + TODO("Not yet implemented") + } + +} + +public inline fun RealAnalyticTensorAlgebra(block: RealAnalyticTensorAlgebra.() -> R): R = + RealAnalyticTensorAlgebra().block() \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt similarity index 73% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt index 6b1957b8c..5fd8c4151 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt @@ -1,13 +1,13 @@ package space.kscience.kmath.tensors public class RealLinearOpsTensorAlgebra : - LinearOpsTensorAlgebra, + LinearOpsTensorAlgebra, RealTensorAlgebra() { - override fun eye(n: Int): RealTensor { + override fun eye(n: Int): DoubleTensor { val shape = intArrayOf(n, n) val buffer = DoubleArray(n * n) { 0.0 } - val res = RealTensor(shape, buffer) + val res = DoubleTensor(shape, buffer) for (i in 0 until n) { res[intArrayOf(i, i)] = 1.0 } @@ -15,16 +15,16 @@ public class RealLinearOpsTensorAlgebra : } - override fun RealTensor.dot(other: RealTensor): RealTensor { + override fun DoubleTensor.dot(other: DoubleTensor): DoubleTensor { TODO("Alya") } - override fun diagonalEmbedding(diagonalEntries: RealTensor, offset: Int, dim1: Int, dim2: Int): RealTensor { + override fun diagonalEmbedding(diagonalEntries: DoubleTensor, offset: Int, dim1: Int, dim2: Int): DoubleTensor { TODO("Alya") } - override fun RealTensor.lu(): Pair { + override fun DoubleTensor.lu(): Pair { // todo checks val lu = this.copy() val m = this.shape[0] @@ -74,7 +74,7 @@ public class RealLinearOpsTensorAlgebra : return Pair(lu, IntTensor(intArrayOf(m), pivot)) } - override fun luPivot(lu: RealTensor, pivots: IntTensor): Triple { + override fun luPivot(lu: DoubleTensor, pivots: IntTensor): Triple { // todo checks val n = lu.shape[0] val p = lu.zeroesLike() @@ -100,28 +100,28 @@ public class RealLinearOpsTensorAlgebra : return Triple(p, l, u) } - override fun RealTensor.det(): RealTensor { + override fun DoubleTensor.det(): DoubleTensor { TODO("Not yet implemented") } - override fun RealTensor.inv(): RealTensor { + override fun DoubleTensor.inv(): DoubleTensor { TODO("Not yet implemented") } - override fun RealTensor.cholesky(): RealTensor { + override fun DoubleTensor.cholesky(): DoubleTensor { TODO("Not yet implemented") } - override fun RealTensor.qr(): RealTensor { + override fun DoubleTensor.qr(): DoubleTensor { TODO("Not yet implemented") } - override fun RealTensor.svd(): Triple { + override fun DoubleTensor.svd(): Triple { TODO("Not yet implemented") } - override fun RealTensor.symEig(eigenvectors: Boolean): Pair { + override fun DoubleTensor.symEig(eigenvectors: Boolean): Pair { TODO("Not yet implemented") } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt similarity index 54% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt index 83a513a7a..dd15a257c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt @@ -1,146 +1,146 @@ package space.kscience.kmath.tensors -public open class RealTensorAlgebra : TensorPartialDivisionAlgebra { +public open class RealTensorAlgebra : TensorPartialDivisionAlgebra { - override fun RealTensor.value(): Double { + override fun DoubleTensor.value(): Double { check(this.shape contentEquals intArrayOf(1)) { "Inconsistent value for tensor of shape ${shape.toList()}" } return this.buffer.unsafeToDoubleArray()[0] } - override fun zeros(shape: IntArray): RealTensor { + override fun zeros(shape: IntArray): DoubleTensor { TODO("Not yet implemented") } - override fun RealTensor.zeroesLike(): RealTensor { + override fun DoubleTensor.zeroesLike(): DoubleTensor { val shape = this.shape val buffer = DoubleArray(this.buffer.size) { 0.0 } - return RealTensor(shape, buffer) + return DoubleTensor(shape, buffer) } - override fun ones(shape: IntArray): RealTensor { + override fun ones(shape: IntArray): DoubleTensor { TODO("Not yet implemented") } - override fun RealTensor.onesLike(): RealTensor { + override fun DoubleTensor.onesLike(): DoubleTensor { TODO("Not yet implemented") } - override fun RealTensor.copy(): RealTensor { + override fun DoubleTensor.copy(): DoubleTensor { // should be rework as soon as copy() method for NDBuffer will be available - return RealTensor(this.shape, this.buffer.unsafeToDoubleArray().copyOf()) + return DoubleTensor(this.shape, this.buffer.unsafeToDoubleArray().copyOf()) } - override fun Double.plus(other: RealTensor): RealTensor { + override fun Double.plus(other: DoubleTensor): DoubleTensor { val resBuffer = DoubleArray(other.buffer.size) { i -> other.buffer.unsafeToDoubleArray()[i] + this } - return RealTensor(other.shape, resBuffer) + return DoubleTensor(other.shape, resBuffer) } - override fun RealTensor.plus(value: Double): RealTensor = value + this + override fun DoubleTensor.plus(value: Double): DoubleTensor = value + this - override fun RealTensor.plus(other: RealTensor): RealTensor { + override fun DoubleTensor.plus(other: DoubleTensor): DoubleTensor { val broadcast = broadcastTensors(this, other) val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.buffer.size) { i -> newThis.buffer.unsafeToDoubleArray()[i] + newOther.buffer.unsafeToDoubleArray()[i] } - return RealTensor(newThis.shape, resBuffer) + return DoubleTensor(newThis.shape, resBuffer) } - override fun RealTensor.plusAssign(value: Double) { + override fun DoubleTensor.plusAssign(value: Double) { for (i in this.buffer.unsafeToDoubleArray().indices) { this.buffer.unsafeToDoubleArray()[i] += value } } - override fun RealTensor.plusAssign(other: RealTensor) { + override fun DoubleTensor.plusAssign(other: DoubleTensor) { //todo should be change with broadcasting for (i in this.buffer.unsafeToDoubleArray().indices) { this.buffer.unsafeToDoubleArray()[i] += other.buffer.unsafeToDoubleArray()[i] } } - override fun Double.minus(other: RealTensor): RealTensor { + override fun Double.minus(other: DoubleTensor): DoubleTensor { val resBuffer = DoubleArray(other.buffer.size) { i -> this - other.buffer.unsafeToDoubleArray()[i] } - return RealTensor(other.shape, resBuffer) + return DoubleTensor(other.shape, resBuffer) } - override fun RealTensor.minus(value: Double): RealTensor { + override fun DoubleTensor.minus(value: Double): DoubleTensor { val resBuffer = DoubleArray(this.buffer.size) { i -> this.buffer.unsafeToDoubleArray()[i] - value } - return RealTensor(this.shape, resBuffer) + return DoubleTensor(this.shape, resBuffer) } - override fun RealTensor.minus(other: RealTensor): RealTensor { + override fun DoubleTensor.minus(other: DoubleTensor): DoubleTensor { val broadcast = broadcastTensors(this, other) val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.buffer.size) { i -> newThis.buffer.unsafeToDoubleArray()[i] - newOther.buffer.unsafeToDoubleArray()[i] } - return RealTensor(newThis.shape, resBuffer) + return DoubleTensor(newThis.shape, resBuffer) } - override fun RealTensor.minusAssign(value: Double) { + override fun DoubleTensor.minusAssign(value: Double) { for (i in this.buffer.unsafeToDoubleArray().indices) { this.buffer.unsafeToDoubleArray()[i] -= value } } - override fun RealTensor.minusAssign(other: RealTensor) { + override fun DoubleTensor.minusAssign(other: DoubleTensor) { TODO("Alya") } - override fun Double.times(other: RealTensor): RealTensor { + override fun Double.times(other: DoubleTensor): DoubleTensor { //todo should be change with broadcasting val resBuffer = DoubleArray(other.buffer.size) { i -> other.buffer.unsafeToDoubleArray()[i] * this } - return RealTensor(other.shape, resBuffer) + return DoubleTensor(other.shape, resBuffer) } //todo should be change with broadcasting - override fun RealTensor.times(value: Double): RealTensor = value * this + override fun DoubleTensor.times(value: Double): DoubleTensor = value * this - override fun RealTensor.times(other: RealTensor): RealTensor { + override fun DoubleTensor.times(other: DoubleTensor): DoubleTensor { //todo should be change with broadcasting val resBuffer = DoubleArray(this.buffer.size) { i -> this.buffer.unsafeToDoubleArray()[i] * other.buffer.unsafeToDoubleArray()[i] } - return RealTensor(this.shape, resBuffer) + return DoubleTensor(this.shape, resBuffer) } - override fun RealTensor.timesAssign(value: Double) { + override fun DoubleTensor.timesAssign(value: Double) { //todo should be change with broadcasting for (i in this.buffer.unsafeToDoubleArray().indices) { this.buffer.unsafeToDoubleArray()[i] *= value } } - override fun RealTensor.timesAssign(other: RealTensor) { + override fun DoubleTensor.timesAssign(other: DoubleTensor) { //todo should be change with broadcasting for (i in this.buffer.unsafeToDoubleArray().indices) { this.buffer.unsafeToDoubleArray()[i] *= other.buffer.unsafeToDoubleArray()[i] } } - override fun RealTensor.unaryMinus(): RealTensor { + override fun DoubleTensor.unaryMinus(): DoubleTensor { val resBuffer = DoubleArray(this.buffer.size) { i -> this.buffer.unsafeToDoubleArray()[i].unaryMinus() } - return RealTensor(this.shape, resBuffer) + return DoubleTensor(this.shape, resBuffer) } - override fun RealTensor.transpose(i: Int, j: Int): RealTensor { + override fun DoubleTensor.transpose(i: Int, j: Int): DoubleTensor { checkTranspose(this.dimension, i, j) val n = this.buffer.size val resBuffer = DoubleArray(n) @@ -148,7 +148,7 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra, dim: Int): RealTensor { + override fun cat(tensors: List, dim: Int): DoubleTensor { TODO("Not yet implemented") } - override fun RealTensor.div(value: Double): RealTensor { + override fun DoubleTensor.div(value: Double): DoubleTensor { TODO("Not yet implemented") } - override fun RealTensor.div(other: RealTensor): RealTensor { + override fun DoubleTensor.div(other: DoubleTensor): DoubleTensor { TODO("Not yet implemented") } - override fun RealTensor.flatten(startDim: Int, endDim: Int): RealTensor { + override fun DoubleTensor.flatten(startDim: Int, endDim: Int): DoubleTensor { TODO("Not yet implemented") } - override fun RealTensor.divAssign(value: Double) { + override fun DoubleTensor.divAssign(value: Double) { TODO("Not yet implemented") } - override fun RealTensor.divAssign(other: RealTensor) { + override fun DoubleTensor.divAssign(other: DoubleTensor) { TODO("Not yet implemented") } - override fun RealTensor.mean(dim: Int, keepDim: Boolean): RealTensor { + override fun DoubleTensor.mean(dim: Int, keepDim: Boolean): DoubleTensor { TODO("Not yet implemented") } - override fun RealTensor.quantile(q: Double, dim: Int, keepDim: Boolean): RealTensor { + override fun DoubleTensor.quantile(q: Double, dim: Int, keepDim: Boolean): DoubleTensor { TODO("Not yet implemented") } - override fun RealTensor.std(dim: Int, unbiased: Boolean, keepDim: Boolean): RealTensor { + override fun DoubleTensor.std(dim: Int, unbiased: Boolean, keepDim: Boolean): DoubleTensor { TODO("Not yet implemented") } - override fun RealTensor.variance(dim: Int, unbiased: Boolean, keepDim: Boolean): RealTensor { + override fun DoubleTensor.variance(dim: Int, unbiased: Boolean, keepDim: Boolean): DoubleTensor { TODO("Not yet implemented") } - override fun RealTensor.histc(bins: Int, min: Double, max: Double): RealTensor { + override fun DoubleTensor.histc(bins: Int, min: Double, max: Double): DoubleTensor { TODO("Not yet implemented") } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt deleted file mode 100644 index f610361fc..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/RealAnalyticTensorAlgebra.kt +++ /dev/null @@ -1,150 +0,0 @@ -package space.kscience.kmath.tensors - -public class RealAnalyticTensorAlgebra: - AnalyticTensorAlgebra, - RealTensorAlgebra() -{ - override fun RealTensor.exp(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.log(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.sqrt(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.square(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.cos(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.acos(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.cosh(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.acosh(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.sin(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.asin(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.sinh(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.asinh(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.tan(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.atan(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.tanh(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.atanh(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.ceil(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.floor(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.clamp(min: Double, max: Double): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.erf(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.erfinv(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.erfc(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.lerp(end: RealTensor, weight: RealTensor): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.lgamma(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.logit(eps: Double): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.igamma(other: RealTensor): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.igammac(other: RealTensor): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.mvlgamma(dimensions: Int): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.polygamma(order: Int): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.pow(exponent: Double): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.round(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.sigmoid(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.sinc(): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.heaviside(values: RealTensor): RealTensor { - TODO("Not yet implemented") - } - - override fun RealTensor.trapz(xValues: RealTensor, dim: Int): RealTensor { - TODO("Not yet implemented") - } - -} - -public inline fun RealAnalyticTensorAlgebra(block: RealAnalyticTensorAlgebra.() -> R): R = - RealAnalyticTensorAlgebra().block() \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt index b03fb7dd7..9f7e811db 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt @@ -32,13 +32,13 @@ internal inline fun broadcastShapes(vararg shapes: IntArray): IntArray { return totalShape } -internal inline fun broadcastTensors(vararg tensors: RealTensor): List { +internal inline fun broadcastTensors(vararg tensors: DoubleTensor): List { val totalShape = broadcastShapes(*(tensors.map { it.shape }).toTypedArray()) val n = totalShape.reduce { acc, i -> acc * i } - val res = ArrayList(0) + val res = ArrayList(0) for (tensor in tensors) { - val resTensor = RealTensor(totalShape, DoubleArray(n)) + val resTensor = DoubleTensor(totalShape, DoubleArray(n)) for (linearIndex in 0 until n) { val totalMultiIndex = resTensor.strides.index(linearIndex) diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensor.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensor.kt index 473a3da8b..5d42e6d0f 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensor.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensor.kt @@ -11,13 +11,13 @@ class TestRealTensor { @Test fun valueTest() = RealTensorAlgebra { val value = 12.5 - val tensor = RealTensor(intArrayOf(1), doubleArrayOf(value)) + val tensor = DoubleTensor(intArrayOf(1), doubleArrayOf(value)) assertEquals(tensor.value(), value) } @Test fun stridesTest(){ - val tensor = RealTensor(intArrayOf(2,2), doubleArrayOf(3.5,5.8,58.4,2.4)) + val tensor = DoubleTensor(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.toDoubleArray()) } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt index 72bbf1787..3e27a1cc2 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt @@ -8,14 +8,14 @@ class TestRealTensorAlgebra { @Test fun doublePlus() = RealTensorAlgebra { - val tensor = RealTensor(intArrayOf(2), doubleArrayOf(1.0, 2.0)) + val tensor = DoubleTensor(intArrayOf(2), doubleArrayOf(1.0, 2.0)) val res = 10.0 + tensor assertTrue(res.buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(11.0,12.0)) } @Test fun transpose1x1() = RealTensorAlgebra { - val tensor = RealTensor(intArrayOf(1), doubleArrayOf(0.0)) + val tensor = DoubleTensor(intArrayOf(1), doubleArrayOf(0.0)) val res = tensor.transpose(0, 0) assertTrue(res.buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(0.0)) @@ -24,7 +24,7 @@ class TestRealTensorAlgebra { @Test fun transpose3x2() = RealTensorAlgebra { - val tensor = RealTensor(intArrayOf(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + val tensor = DoubleTensor(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.unsafeToDoubleArray() contentEquals doubleArrayOf(1.0, 3.0, 5.0, 2.0, 4.0, 6.0)) @@ -33,7 +33,7 @@ class TestRealTensorAlgebra { @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 tensor = DoubleTensor(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) @@ -60,9 +60,9 @@ class TestRealTensorAlgebra { @Test fun broadcastTensors() = RealTensorAlgebra { - val tensor1 = RealTensor(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = RealTensor(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) - val tensor3 = RealTensor(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) + val tensor1 = DoubleTensor(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + val tensor2 = DoubleTensor(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) + val tensor3 = DoubleTensor(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) val res = broadcastTensors(tensor1, tensor2, tensor3) @@ -77,9 +77,9 @@ class TestRealTensorAlgebra { @Test fun minusTensor() = RealTensorAlgebra { - val tensor1 = RealTensor(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = RealTensor(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) - val tensor3 = RealTensor(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) + val tensor1 = DoubleTensor(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + val tensor2 = DoubleTensor(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) + val tensor3 = DoubleTensor(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) assertTrue((tensor2 - tensor1).shape contentEquals intArrayOf(2, 3)) assertTrue((tensor2 - tensor1).buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(9.0, 18.0, 27.0, 6.0, 15.0, 24.0)) From b227a82a80d406fa3c4b4e50373a02363f161954 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Mon, 15 Mar 2021 19:06:33 +0000 Subject: [PATCH 030/178] OrderedTensorAlgebra --- .../kmath/tensors/ComplexTensorAlgebra.kt | 6 +++ .../tensors/DoubleAnalyticTensorAlgebra.kt | 8 +-- .../tensors/DoubleLinearOpsTensorAlgebra.kt | 32 ++---------- .../tensors/DoubleOrderedTensorAlgebra.kt | 41 +++++++++++++++ .../kmath/tensors/DoubleTensorAlgebra.kt | 51 ++++++++----------- .../kmath/tensors/LinearOpsTensorAlgebra.kt | 15 ------ .../kmath/tensors/OrderedTensorAlgebra.kt | 29 +++++++++++ .../kscience/kmath/tensors/TensorAlgebra.kt | 35 +++++-------- .../kscience/kmath/tensors/TestRealTensor.kt | 2 +- .../kmath/tensors/TestRealTensorAlgebra.kt | 14 ++--- 10 files changed, 125 insertions(+), 108 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleOrderedTensorAlgebra.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/OrderedTensorAlgebra.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt index 8399511a5..e56920916 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt @@ -8,6 +8,12 @@ public interface ComplexTensorAlgebra, - RealTensorAlgebra() + DoubleTensorAlgebra() { override fun DoubleTensor.exp(): DoubleTensor { TODO("Not yet implemented") @@ -146,5 +146,5 @@ public class RealAnalyticTensorAlgebra: } -public inline fun RealAnalyticTensorAlgebra(block: RealAnalyticTensorAlgebra.() -> R): R = - RealAnalyticTensorAlgebra().block() \ No newline at end of file +public inline fun DoubleAnalyticTensorAlgebra(block: DoubleAnalyticTensorAlgebra.() -> R): R = + DoubleAnalyticTensorAlgebra().block() \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt index ddb3dfa12..1aaf8df9d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt @@ -2,27 +2,12 @@ package space.kscience.kmath.tensors public class DoubleLinearOpsTensorAlgebra : LinearOpsTensorAlgebra, - RealTensorAlgebra() { - override fun eye(n: Int): DoubleTensor { - val shape = intArrayOf(n, n) - val buffer = DoubleArray(n * n) { 0.0 } - val res = DoubleTensor(shape, buffer) - for (i in 0 until n) { - res[intArrayOf(i, i)] = 1.0 - } - return res + DoubleTensorAlgebra() { + + override fun DoubleTensor.inv(): DoubleTensor { + TODO("Not yet implemented") } - - override fun DoubleTensor.dot(other: DoubleTensor): DoubleTensor { - TODO("Alya") - } - - override fun diagonalEmbedding(diagonalEntries: DoubleTensor, offset: Int, dim1: Int, dim2: Int): DoubleTensor { - TODO("Alya") - } - - override fun DoubleTensor.lu(): Pair { // todo checks val luTensor = this.copy() @@ -115,15 +100,6 @@ public class DoubleLinearOpsTensorAlgebra : return Triple(p, l, u) } - override fun DoubleTensor.det(): DoubleTensor { - - TODO("Not yet implemented") - } - - override fun DoubleTensor.inv(): DoubleTensor { - TODO("Not yet implemented") - } - override fun DoubleTensor.cholesky(): DoubleTensor { TODO("Not yet implemented") } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleOrderedTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleOrderedTensorAlgebra.kt new file mode 100644 index 000000000..e7ebf6c56 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleOrderedTensorAlgebra.kt @@ -0,0 +1,41 @@ +package space.kscience.kmath.tensors + +public class DoubleOrderedTensorAlgebra: + OrderedTensorAlgebra, + DoubleTensorAlgebra() +{ + override fun DoubleTensor.max(dim: Int, keepDim: Boolean): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.cummax(dim: Int): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.min(dim: Int, keepDim: Boolean): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.cummin(dim: Int): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.median(dim: Int, keepDim: Boolean): DoubleTensor { + TODO("Not yet implemented") + } + + override fun maximum(lhs: DoubleTensor, rhs: DoubleTensor) { + TODO("Not yet implemented") + } + + override fun minimum(lhs: DoubleTensor, rhs: DoubleTensor) { + TODO("Not yet implemented") + } + + override fun DoubleTensor.sort(dim: Int, keepDim: Boolean, descending: Boolean): DoubleTensor { + TODO("Not yet implemented") + } +} + +public inline fun DoubleOrderedTensorAlgebra(block: DoubleOrderedTensorAlgebra.() -> R): R = + DoubleOrderedTensorAlgebra().block() \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt index dd15a257c..8b9701127 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt @@ -1,7 +1,7 @@ package space.kscience.kmath.tensors -public open class RealTensorAlgebra : TensorPartialDivisionAlgebra { +public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { override fun DoubleTensor.value(): Double { check(this.shape contentEquals intArrayOf(1)) { @@ -27,6 +27,15 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra, dim: Int): DoubleTensor { @@ -276,7 +261,11 @@ public open class RealTensorAlgebra : TensorPartialDivisionAlgebra RealTensorAlgebra(block: RealTensorAlgebra.() -> R): R = - RealTensorAlgebra().block() \ No newline at end of file +public inline fun DoubleTensorAlgebra(block: DoubleTensorAlgebra.() -> R): R = + DoubleTensorAlgebra().block() \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt index db1135a33..7450c09c1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt @@ -4,21 +4,6 @@ package space.kscience.kmath.tensors public interface LinearOpsTensorAlgebra> : TensorPartialDivisionAlgebra { - //https://pytorch.org/docs/stable/generated/torch.eye.html - public fun eye(n: Int): TensorType - - //https://pytorch.org/docs/stable/generated/torch.matmul.html - public infix fun TensorType.dot(other: TensorType): TensorType - - //https://pytorch.org/docs/stable/generated/torch.diag_embed.html - public fun diagonalEmbedding( - diagonalEntries: TensorType, - offset: Int = 0, dim1: Int = -2, dim2: Int = -1 - ): TensorType - - //https://pytorch.org/docs/stable/linalg.html#torch.linalg.det - public fun TensorType.det(): TensorType - //https://pytorch.org/docs/stable/linalg.html#torch.linalg.inv public fun TensorType.inv(): TensorType diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/OrderedTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/OrderedTensorAlgebra.kt new file mode 100644 index 000000000..3320c3a1e --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/OrderedTensorAlgebra.kt @@ -0,0 +1,29 @@ +package space.kscience.kmath.tensors + +public interface OrderedTensorAlgebra> : + TensorAlgebra { + + //https://pytorch.org/docs/stable/generated/torch.max.html#torch.max + public fun TensorType.max(dim: Int, keepDim: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.cummax.html#torch.cummax + public fun TensorType.cummax(dim: Int): TensorType + + //https://pytorch.org/docs/stable/generated/torch.min.html#torch.min + public fun TensorType.min(dim: Int, keepDim: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.cummin.html#torch.cummin + public fun TensorType.cummin(dim: Int): TensorType + + //https://pytorch.org/docs/stable/generated/torch.median.html#torch.median + public fun TensorType.median(dim: Int, keepDim: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.maximum.html#torch.maximum + public fun maximum(lhs: TensorType, rhs: TensorType) + + //https://pytorch.org/docs/stable/generated/torch.minimum.html#torch.minimum + public fun minimum(lhs: TensorType, rhs: TensorType) + + //https://pytorch.org/docs/stable/generated/torch.sort.html#torch.sort + public fun TensorType.sort(dim: Int, keepDim: Boolean, descending: Boolean): TensorType +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index a53054e21..6f368f332 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -17,6 +17,9 @@ public interface TensorAlgebra> { //https://pytorch.org/docs/stable/generated/torch.full_like.html#torch.full_like public fun TensorType.fullLike(value: T): TensorType + //https://pytorch.org/docs/stable/generated/torch.eye.html + public fun eye(n: Int): TensorType + public fun TensorType.copy(): TensorType public operator fun T.plus(other: TensorType): TensorType @@ -46,6 +49,9 @@ public interface TensorAlgebra> { public fun TensorType.view(shape: IntArray): TensorType public fun TensorType.viewAs(other: TensorType): TensorType + //https://pytorch.org/docs/stable/linalg.html#torch.linalg.det + public fun TensorType.det(): TensorType + //https://pytorch.org/docs/stable/generated/torch.abs.html public fun TensorType.abs(): TensorType @@ -61,29 +67,14 @@ public interface TensorAlgebra> { //https://pytorch.org/docs/stable/generated/torch.cumprod.html#torch.cumprod public fun TensorType.cumprod(dim: Int): TensorType - //https://pytorch.org/docs/stable/generated/torch.max.html#torch.max - public fun TensorType.max(dim: Int, keepDim: Boolean): TensorType + //https://pytorch.org/docs/stable/generated/torch.matmul.html + public infix fun TensorType.dot(other: TensorType): TensorType - //https://pytorch.org/docs/stable/generated/torch.cummax.html#torch.cummax - public fun TensorType.cummax(dim: Int): TensorType - - //https://pytorch.org/docs/stable/generated/torch.min.html#torch.min - public fun TensorType.min(dim: Int, keepDim: Boolean): TensorType - - //https://pytorch.org/docs/stable/generated/torch.cummin.html#torch.cummin - public fun TensorType.cummin(dim: Int): TensorType - - //https://pytorch.org/docs/stable/generated/torch.median.html#torch.median - public fun TensorType.median(dim: Int, keepDim: Boolean): TensorType - - //https://pytorch.org/docs/stable/generated/torch.maximum.html#torch.maximum - public fun maximum(lhs: TensorType, rhs: TensorType) - - //https://pytorch.org/docs/stable/generated/torch.minimum.html#torch.minimum - public fun minimum(lhs: TensorType, rhs: TensorType) - - //https://pytorch.org/docs/stable/generated/torch.sort.html#torch.sort - public fun TensorType.sort(dim: Int, keepDim: Boolean, descending: Boolean): TensorType + //https://pytorch.org/docs/stable/generated/torch.diag_embed.html + public fun diagonalEmbedding( + diagonalEntries: TensorType, + offset: Int = 0, dim1: Int = -2, dim2: Int = -1 + ): TensorType //https://pytorch.org/docs/stable/generated/torch.cat.html#torch.cat public fun cat(tensors: List, dim: Int): TensorType diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensor.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensor.kt index 5d42e6d0f..72179ecbc 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensor.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensor.kt @@ -9,7 +9,7 @@ import kotlin.test.assertTrue class TestRealTensor { @Test - fun valueTest() = RealTensorAlgebra { + fun valueTest() = DoubleTensorAlgebra { val value = 12.5 val tensor = DoubleTensor(intArrayOf(1), doubleArrayOf(value)) assertEquals(tensor.value(), value) diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt index 3e27a1cc2..9dddcf59e 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestRealTensorAlgebra.kt @@ -7,14 +7,14 @@ import kotlin.test.assertTrue class TestRealTensorAlgebra { @Test - fun doublePlus() = RealTensorAlgebra { + fun doublePlus() = DoubleTensorAlgebra { val tensor = DoubleTensor(intArrayOf(2), doubleArrayOf(1.0, 2.0)) val res = 10.0 + tensor assertTrue(res.buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(11.0,12.0)) } @Test - fun transpose1x1() = RealTensorAlgebra { + fun transpose1x1() = DoubleTensorAlgebra { val tensor = DoubleTensor(intArrayOf(1), doubleArrayOf(0.0)) val res = tensor.transpose(0, 0) @@ -23,7 +23,7 @@ class TestRealTensorAlgebra { } @Test - fun transpose3x2() = RealTensorAlgebra { + fun transpose3x2() = DoubleTensorAlgebra { val tensor = DoubleTensor(intArrayOf(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val res = tensor.transpose(1, 0) @@ -32,7 +32,7 @@ class TestRealTensorAlgebra { } @Test - fun transpose1x2x3() = RealTensorAlgebra { + fun transpose1x2x3() = DoubleTensorAlgebra { val tensor = DoubleTensor(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) @@ -48,7 +48,7 @@ class TestRealTensorAlgebra { } @Test - fun broadcastShapes() = RealTensorAlgebra { + fun broadcastShapes() = DoubleTensorAlgebra { assertTrue(broadcastShapes( intArrayOf(2, 3), intArrayOf(1, 3), intArrayOf(1, 1, 1) ) contentEquals intArrayOf(1, 2, 3)) @@ -59,7 +59,7 @@ class TestRealTensorAlgebra { } @Test - fun broadcastTensors() = RealTensorAlgebra { + fun broadcastTensors() = DoubleTensorAlgebra { val tensor1 = DoubleTensor(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor2 = DoubleTensor(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) val tensor3 = DoubleTensor(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) @@ -76,7 +76,7 @@ class TestRealTensorAlgebra { } @Test - fun minusTensor() = RealTensorAlgebra { + fun minusTensor() = DoubleTensorAlgebra { val tensor1 = DoubleTensor(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor2 = DoubleTensor(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) val tensor3 = DoubleTensor(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) From f8e0d4be17baac7e2f5930083b2bfeb7338f99e8 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Mon, 15 Mar 2021 21:18:15 +0000 Subject: [PATCH 031/178] MutableStructure 2D & 1D --- .../space/kscience/kmath/nd/Structure1D.kt | 56 +++++++++++++++++++ .../space/kscience/kmath/nd/Structure2D.kt | 53 +++++++++++++++++- .../space/kscience/kmath/structures/Buffer.kt | 5 ++ .../kscience/kmath/tensors/BufferedTensor.kt | 1 - .../kmath/tensors/DoubleTensorAlgebra.kt | 4 ++ .../kscience/kmath/tensors/TensorAlgebra.kt | 2 + .../kscience/kmath/tensors/TensorStructure.kt | 1 - 7 files changed, 118 insertions(+), 4 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt index 1335a4933..2926b3d1b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt @@ -1,6 +1,8 @@ package space.kscience.kmath.nd import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.MutableBuffer +import space.kscience.kmath.structures.asMutableBuffer import space.kscience.kmath.structures.asSequence /** @@ -17,6 +19,16 @@ public interface Structure1D : NDStructure, Buffer { public override operator fun iterator(): Iterator = (0 until size).asSequence().map(::get).iterator() } +/** + * A mutable structure that is guaranteed to be one-dimensional + */ +public interface MutableStructure1D : Structure1D, MutableNDStructure, MutableBuffer { + public override operator fun set(index: IntArray, value: T) { + require(index.size == 1) { "Index dimension mismatch. Expected 1 but found ${index.size}" } + set(index[0], value) + } +} + /** * A 1D wrapper for nd-structure */ @@ -28,6 +40,25 @@ private inline class Structure1DWrapper(val structure: NDStructure) : Stru override fun elements(): Sequence> = structure.elements() } +/** + * A 1D wrapper for a mutable nd-structure + */ +private inline class MutableStructure1DWrapper(val structure: MutableNDStructure) : MutableStructure1D { + override val shape: IntArray get() = structure.shape + override val size: Int get() = structure.shape[0] + override fun elements(): Sequence> { + TODO("Not yet implemented") + } + + override fun get(index: Int): T = structure[index] + override fun set(index: Int, value: T) { + set(index, value) + } + + override fun copy(): MutableBuffer = + structure.elements().map { it.second }.toMutableList().asMutableBuffer() +} + /** * A structure wrapper for buffer @@ -42,6 +73,21 @@ private inline class Buffer1DWrapper(val buffer: Buffer) : Structure1D override operator fun get(index: Int): T = buffer[index] } +private inline class MutableBuffer1DWrapper(val buffer: MutableBuffer) : MutableStructure1D { + override val shape: IntArray get() = intArrayOf(buffer.size) + override val size: Int get() = buffer.size + + override fun elements(): Sequence> = + buffer.asSequence().mapIndexed { index, value -> intArrayOf(index) to value } + + override operator fun get(index: Int): T = buffer[index] + override fun set(index: Int, value: T) { + buffer[index] = value + } + + override fun copy(): MutableBuffer = buffer.copy() +} + /** * Represent a [NDStructure] as [Structure1D]. Throw error in case of dimension mismatch */ @@ -52,7 +98,17 @@ public fun NDStructure.as1D(): Structure1D = this as? Structure1D ? } } else error("Can't create 1d-structure from ${shape.size}d-structure") +public fun MutableNDStructure.as1D(): MutableStructure1D = + this as? MutableStructure1D ?: if (shape.size == 1) { + when (this) { + is MutableNDBuffer -> MutableBuffer1DWrapper(this.buffer) + else -> MutableStructure1DWrapper(this) + } + } else error("Can't create 1d-structure from ${shape.size}d-structure") + /** * Represent this buffer as 1D structure */ public fun Buffer.asND(): Structure1D = Buffer1DWrapper(this) + +public fun MutableBuffer.asND(): MutableStructure1D = MutableBuffer1DWrapper(this) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt index e9f8234e5..2f2fd653e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt @@ -57,6 +57,20 @@ public interface Structure2D : NDStructure { public companion object } +/** + * Represents mutable [Structure2D]. + */ +public interface MutableStructure2D : Structure2D, MutableNDStructure { + /** + * Inserts an item at the specified indices. + * + * @param i the first index. + * @param j the second index. + * @param value the value. + */ + public operator fun set(i: Int, j: Int, value: T) +} + /** * A 2D wrapper for nd-structure */ @@ -79,11 +93,46 @@ private class Structure2DWrapper(val structure: NDStructure) : Structure2D } /** - * Represent a [NDStructure] as [Structure1D]. Throw error in case of dimension mismatch + * A 2D wrapper for a mutable nd-structure + */ +private class MutableStructure2DWrapper(val structure: MutableNDStructure): MutableStructure2D +{ + override val shape: IntArray get() = structure.shape + + override val rowNum: Int get() = shape[0] + override val colNum: Int get() = shape[1] + + override operator fun get(i: Int, j: Int): T = structure[i, j] + + override fun set(index: IntArray, value: T) { + structure[index] = value + } + + override operator fun set(i: Int, j: Int, value: T){ + structure[intArrayOf(i, j)] = value + } + + override fun elements(): Sequence> = structure.elements() + + override fun equals(other: Any?): Boolean = false + + override fun hashCode(): Int = 0 +} + +/** + * Represent a [NDStructure] as [Structure2D]. Throw error in case of dimension mismatch */ public fun NDStructure.as2D(): Structure2D = this as? Structure2D ?: when (shape.size) { 2 -> Structure2DWrapper(this) else -> error("Can't create 2d-structure from ${shape.size}d-structure") } -internal fun Structure2D.unwrap(): NDStructure = if (this is Structure2DWrapper) structure else this \ No newline at end of file +internal fun Structure2D.unwrap(): NDStructure = if (this is Structure2DWrapper) structure else this + +public fun MutableNDStructure.as2D(): MutableStructure2D = this as? MutableStructure2D ?: when (shape.size) { + 2 -> MutableStructure2DWrapper(this) + else -> error("Can't create 2d-structure from ${shape.size}d-structure") +} + +internal fun MutableStructure2D.unwrap(): MutableNDStructure = + if (this is MutableStructure2DWrapper) structure else this diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt index 2bde18fce..c62fa30ba 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt @@ -236,6 +236,11 @@ public inline class MutableListBuffer(public val list: MutableList) : Muta override fun copy(): MutableBuffer = MutableListBuffer(ArrayList(list)) } +/** + * Returns an [MutableListBuffer] that wraps the original list. + */ +public fun MutableList.asMutableBuffer(): MutableListBuffer = MutableListBuffer(this) + /** * [MutableBuffer] implementation over [Array]. * diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt index d5adf380c..68fc0412e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt @@ -25,7 +25,6 @@ public open class BufferedTensor( this[intArrayOf(i, j)] = value } - } //todo make generator mb nextMatrixIndex? diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt index 8b9701127..76a3c4c9c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt @@ -10,6 +10,10 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra> { public operator fun TensorType.timesAssign(other: TensorType): Unit public operator fun TensorType.unaryMinus(): TensorType + //https://pytorch.org/cppdocs/notes/tensor_indexing.html + public fun TensorType.get(i: Int): TensorType //https://pytorch.org/docs/stable/generated/torch.transpose.html public fun TensorType.transpose(i: Int, j: Int): TensorType diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt index 5463877ce..f5ea39d1b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt @@ -3,4 +3,3 @@ package space.kscience.kmath.tensors import space.kscience.kmath.nd.MutableNDStructure public typealias TensorStructure = MutableNDStructure - From 7cb5cd8f71721e5eb5e77e0849311a3fd3c2374f Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Mon, 15 Mar 2021 22:11:15 +0000 Subject: [PATCH 032/178] BufferedTensor revisited --- .../kscience/kmath/tensors/BufferedTensor.kt | 54 ++++++++------- .../tensors/DoubleLinearOpsTensorAlgebra.kt | 10 ++- .../kmath/tensors/DoubleTensorAlgebra.kt | 69 ++++++++++--------- .../space/kscience/kmath/tensors/utils.kt | 3 +- ...{TestRealTensor.kt => TestDoubleTensor.kt} | 2 +- ...rAlgebra.kt => TestDoubleTensorAlgebra.kt} | 2 +- 6 files changed, 78 insertions(+), 62 deletions(-) rename kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/{TestRealTensor.kt => TestDoubleTensor.kt} (96%) rename kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/{TestRealTensorAlgebra.kt => TestDoubleTensorAlgebra.kt} (99%) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt index 68fc0412e..264692d0c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt @@ -1,32 +1,34 @@ package space.kscience.kmath.tensors -import space.kscience.kmath.nd.MutableNDBuffer import space.kscience.kmath.structures.* public open class BufferedTensor( override val shape: IntArray, - buffer: MutableBuffer -) : - TensorStructure, - MutableNDBuffer( - TensorStrides(shape), - buffer - ) { + public val buffer: MutableBuffer, + internal val bufferStart: Int +) : TensorStructure +{ + public val strides: TensorStrides + get() = TensorStrides(shape) + override fun get(index: IntArray): T = buffer[bufferStart + strides.offset(index)] - public operator fun get(i: Int, j: Int): T { - check(this.dimension == 2) { "Not matrix" } - return this[intArrayOf(i, j)] + override fun set(index: IntArray, value: T) { + buffer[bufferStart + strides.offset(index)] = value } - public operator fun set(i: Int, j: Int, value: T): Unit { - check(this.dimension == 2) { "Not matrix" } - this[intArrayOf(i, j)] = value + override fun elements(): Sequence> = strides.indices().map { + it to this[it] } + override fun equals(other: Any?): Boolean = false + + override fun hashCode(): Int = 0 + } +/* //todo make generator mb nextMatrixIndex? public class InnerMatrix(private val tensor: BufferedTensor){ private var offset: Int = 0 @@ -75,25 +77,29 @@ public class InnerVector(private val tensor: BufferedTensor){ offset += step } } - - //todo default buffer = arrayOf(0)??? + */ + public class IntTensor( shape: IntArray, - buffer: IntArray -) : BufferedTensor(shape, IntBuffer(buffer)) + buffer: IntArray, + offset: Int = 0 +) : BufferedTensor(shape, IntBuffer(buffer), offset) public class LongTensor( shape: IntArray, - buffer: LongArray -) : BufferedTensor(shape, LongBuffer(buffer)) + buffer: LongArray, + offset: Int = 0 +) : BufferedTensor(shape, LongBuffer(buffer), offset) public class FloatTensor( shape: IntArray, - buffer: FloatArray -) : BufferedTensor(shape, FloatBuffer(buffer)) + buffer: FloatArray, + offset: Int = 0 +) : BufferedTensor(shape, FloatBuffer(buffer), offset) public class DoubleTensor( shape: IntArray, - buffer: DoubleArray -) : BufferedTensor(shape, RealBuffer(buffer)) \ No newline at end of file + buffer: DoubleArray, + offset: Int = 0 +) : BufferedTensor(shape, RealBuffer(buffer), offset) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt index 1aaf8df9d..eceb28459 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt @@ -9,6 +9,7 @@ public class DoubleLinearOpsTensorAlgebra : } override fun DoubleTensor.lu(): Pair { + /* // todo checks val luTensor = this.copy() val lu = InnerMatrix(luTensor) @@ -69,11 +70,13 @@ public class DoubleLinearOpsTensorAlgebra : pivot.makeStep() } - return Pair(luTensor, pivotsTensor) + return Pair(luTensor, pivotsTensor)*/ + + TODO("Andrei, first we need to view and get(Int)") } override fun luPivot(lu: DoubleTensor, pivots: IntTensor): Triple { - + /* // todo checks val n = lu.shape[0] val p = lu.zeroesLike() @@ -97,7 +100,8 @@ public class DoubleLinearOpsTensorAlgebra : } } - return Triple(p, l, u) + return Triple(p, l, u)*/ + TODO("Andrei, first we need implement get(Int)") } override fun DoubleTensor.cholesky(): DoubleTensor { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt index 76a3c4c9c..391c2895f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt @@ -7,11 +7,11 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra - other.buffer.unsafeToDoubleArray()[i] + this + val resBuffer = DoubleArray(other.strides.linearSize) { i -> + other.buffer.unsafeToDoubleArray()[other.bufferStart + i] + this } return DoubleTensor(other.shape, resBuffer) } @@ -60,35 +60,36 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra + val resBuffer = DoubleArray(newThis.strides.linearSize) { i -> newThis.buffer.unsafeToDoubleArray()[i] + newOther.buffer.unsafeToDoubleArray()[i] } return DoubleTensor(newThis.shape, resBuffer) } override fun DoubleTensor.plusAssign(value: Double) { - for (i in this.buffer.unsafeToDoubleArray().indices) { - this.buffer.unsafeToDoubleArray()[i] += value + for (i in 0 until this.strides.linearSize) { + this.buffer.unsafeToDoubleArray()[this.bufferStart + i] += value } } override fun DoubleTensor.plusAssign(other: DoubleTensor) { //todo should be change with broadcasting - for (i in this.buffer.unsafeToDoubleArray().indices) { - this.buffer.unsafeToDoubleArray()[i] += other.buffer.unsafeToDoubleArray()[i] + for (i in 0 until this.strides.linearSize) { + this.buffer.unsafeToDoubleArray()[this.bufferStart + i] += + other.buffer.unsafeToDoubleArray()[this.bufferStart + i] } } override fun Double.minus(other: DoubleTensor): DoubleTensor { - val resBuffer = DoubleArray(other.buffer.size) { i -> - this - other.buffer.unsafeToDoubleArray()[i] + val resBuffer = DoubleArray(other.strides.linearSize) { i -> + this - other.buffer.unsafeToDoubleArray()[other.bufferStart + i] } return DoubleTensor(other.shape, resBuffer) } override fun DoubleTensor.minus(value: Double): DoubleTensor { - val resBuffer = DoubleArray(this.buffer.size) { i -> - this.buffer.unsafeToDoubleArray()[i] - value + val resBuffer = DoubleArray(this.strides.linearSize) { i -> + this.buffer.unsafeToDoubleArray()[this.bufferStart + i] - value } return DoubleTensor(this.shape, resBuffer) } @@ -97,15 +98,15 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra + val resBuffer = DoubleArray(newThis.strides.linearSize) { i -> newThis.buffer.unsafeToDoubleArray()[i] - newOther.buffer.unsafeToDoubleArray()[i] } return DoubleTensor(newThis.shape, resBuffer) } override fun DoubleTensor.minusAssign(value: Double) { - for (i in this.buffer.unsafeToDoubleArray().indices) { - this.buffer.unsafeToDoubleArray()[i] -= value + for (i in 0 until this.strides.linearSize) { + this.buffer.unsafeToDoubleArray()[this.bufferStart + i] -= value } } @@ -115,8 +116,8 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra - other.buffer.unsafeToDoubleArray()[i] * this + val resBuffer = DoubleArray(other.strides.linearSize) { i -> + other.buffer.unsafeToDoubleArray()[other.bufferStart + i] * this } return DoubleTensor(other.shape, resBuffer) } @@ -126,36 +127,38 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra - this.buffer.unsafeToDoubleArray()[i] * other.buffer.unsafeToDoubleArray()[i] + val resBuffer = DoubleArray(this.strides.linearSize) { i -> + this.buffer.unsafeToDoubleArray()[other.bufferStart + i] * + other.buffer.unsafeToDoubleArray()[other.bufferStart + i] } return DoubleTensor(this.shape, resBuffer) } override fun DoubleTensor.timesAssign(value: Double) { //todo should be change with broadcasting - for (i in this.buffer.unsafeToDoubleArray().indices) { - this.buffer.unsafeToDoubleArray()[i] *= value + for (i in 0 until this.strides.linearSize) { + this.buffer.unsafeToDoubleArray()[this.bufferStart + i] *= value } } override fun DoubleTensor.timesAssign(other: DoubleTensor) { //todo should be change with broadcasting - for (i in this.buffer.unsafeToDoubleArray().indices) { - this.buffer.unsafeToDoubleArray()[i] *= other.buffer.unsafeToDoubleArray()[i] + for (i in 0 until this.strides.linearSize) { + this.buffer.unsafeToDoubleArray()[this.bufferStart + i] *= + other.buffer.unsafeToDoubleArray()[this.bufferStart + i] } } override fun DoubleTensor.unaryMinus(): DoubleTensor { - val resBuffer = DoubleArray(this.buffer.size) { i -> - this.buffer.unsafeToDoubleArray()[i].unaryMinus() + val resBuffer = DoubleArray(this.strides.linearSize) { i -> + this.buffer.unsafeToDoubleArray()[this.bufferStart + i].unaryMinus() } return DoubleTensor(this.shape, resBuffer) } override fun DoubleTensor.transpose(i: Int, j: Int): DoubleTensor { checkTranspose(this.dimension, i, j) - val n = this.buffer.size + val n = this.strides.linearSize val resBuffer = DoubleArray(n) val resShape = this.shape.copyOf() @@ -169,14 +172,16 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra Date: Mon, 15 Mar 2021 22:39:29 +0000 Subject: [PATCH 033/178] get dim 0 operator for tensors --- .../tensors/DoubleLinearOpsTensorAlgebra.kt | 2 +- .../kmath/tensors/DoubleTensorAlgebra.kt | 49 ++++++++++--------- .../kscience/kmath/tensors/TensorAlgebra.kt | 2 +- .../space/kscience/kmath/tensors/utils.kt | 12 ++--- .../kmath/tensors/TestDoubleTensor.kt | 6 +++ .../kmath/tensors/TestDoubleTensorAlgebra.kt | 24 ++++----- 6 files changed, 52 insertions(+), 43 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt index eceb28459..d6b202556 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt @@ -72,7 +72,7 @@ public class DoubleLinearOpsTensorAlgebra : return Pair(luTensor, pivotsTensor)*/ - TODO("Andrei, first we need to view and get(Int)") + TODO("Andrei, use view, get, as2D, as1D") } override fun luPivot(lu: DoubleTensor, pivots: IntTensor): Triple { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt index 391c2895f..3b65e89da 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt @@ -7,11 +7,14 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra - other.buffer.unsafeToDoubleArray()[other.bufferStart + i] + this + other.buffer.array()[other.bufferStart + i] + this } return DoubleTensor(other.shape, resBuffer) } @@ -61,35 +64,35 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra - newThis.buffer.unsafeToDoubleArray()[i] + newOther.buffer.unsafeToDoubleArray()[i] + newThis.buffer.array()[i] + newOther.buffer.array()[i] } return DoubleTensor(newThis.shape, resBuffer) } override fun DoubleTensor.plusAssign(value: Double) { for (i in 0 until this.strides.linearSize) { - this.buffer.unsafeToDoubleArray()[this.bufferStart + i] += value + this.buffer.array()[this.bufferStart + i] += value } } override fun DoubleTensor.plusAssign(other: DoubleTensor) { //todo should be change with broadcasting for (i in 0 until this.strides.linearSize) { - this.buffer.unsafeToDoubleArray()[this.bufferStart + i] += - other.buffer.unsafeToDoubleArray()[this.bufferStart + i] + this.buffer.array()[this.bufferStart + i] += + other.buffer.array()[this.bufferStart + i] } } override fun Double.minus(other: DoubleTensor): DoubleTensor { val resBuffer = DoubleArray(other.strides.linearSize) { i -> - this - other.buffer.unsafeToDoubleArray()[other.bufferStart + i] + this - other.buffer.array()[other.bufferStart + i] } return DoubleTensor(other.shape, resBuffer) } override fun DoubleTensor.minus(value: Double): DoubleTensor { val resBuffer = DoubleArray(this.strides.linearSize) { i -> - this.buffer.unsafeToDoubleArray()[this.bufferStart + i] - value + this.buffer.array()[this.bufferStart + i] - value } return DoubleTensor(this.shape, resBuffer) } @@ -99,14 +102,14 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra - newThis.buffer.unsafeToDoubleArray()[i] - newOther.buffer.unsafeToDoubleArray()[i] + newThis.buffer.array()[i] - newOther.buffer.array()[i] } return DoubleTensor(newThis.shape, resBuffer) } override fun DoubleTensor.minusAssign(value: Double) { for (i in 0 until this.strides.linearSize) { - this.buffer.unsafeToDoubleArray()[this.bufferStart + i] -= value + this.buffer.array()[this.bufferStart + i] -= value } } @@ -117,7 +120,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra - other.buffer.unsafeToDoubleArray()[other.bufferStart + i] * this + other.buffer.array()[other.bufferStart + i] * this } return DoubleTensor(other.shape, resBuffer) } @@ -128,8 +131,8 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra - this.buffer.unsafeToDoubleArray()[other.bufferStart + i] * - other.buffer.unsafeToDoubleArray()[other.bufferStart + i] + this.buffer.array()[other.bufferStart + i] * + other.buffer.array()[other.bufferStart + i] } return DoubleTensor(this.shape, resBuffer) } @@ -137,21 +140,21 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra - this.buffer.unsafeToDoubleArray()[this.bufferStart + i].unaryMinus() + this.buffer.array()[this.bufferStart + i].unaryMinus() } return DoubleTensor(this.shape, resBuffer) } @@ -172,8 +175,8 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra> { public operator fun TensorType.unaryMinus(): TensorType //https://pytorch.org/cppdocs/notes/tensor_indexing.html - public fun TensorType.get(i: Int): TensorType + public operator fun TensorType.get(i: Int): TensorType //https://pytorch.org/docs/stable/generated/torch.transpose.html public fun TensorType.transpose(i: Int, j: Int): TensorType diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt index 74a774f45..3e32e2b72 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt @@ -55,8 +55,8 @@ internal inline fun broadcastTensors(vararg tensors: DoubleTensor): List, /** * Returns a reference to [IntArray] containing all of the elements of this [Buffer]. */ -internal fun Buffer.unsafeToIntArray(): IntArray = when(this) { +internal fun Buffer.array(): IntArray = when(this) { is IntBuffer -> array else -> throw RuntimeException("Failed to cast Buffer to IntArray") } @@ -107,7 +107,7 @@ internal fun Buffer.unsafeToIntArray(): IntArray = when(this) { /** * Returns a reference to [LongArray] containing all of the elements of this [Buffer]. */ -internal fun Buffer.unsafeToLongArray(): LongArray = when(this) { +internal fun Buffer.array(): LongArray = when(this) { is LongBuffer -> array else -> throw RuntimeException("Failed to cast Buffer to LongArray") } @@ -115,7 +115,7 @@ internal fun Buffer.unsafeToLongArray(): LongArray = when(this) { /** * Returns a reference to [FloatArray] containing all of the elements of this [Buffer]. */ -internal fun Buffer.unsafeToFloatArray(): FloatArray = when(this) { +internal fun Buffer.array(): FloatArray = when(this) { is FloatBuffer -> array else -> throw RuntimeException("Failed to cast Buffer to FloatArray") } @@ -123,7 +123,7 @@ internal fun Buffer.unsafeToFloatArray(): FloatArray = when(this) { /** * Returns a reference to [DoubleArray] containing all of the elements of this [Buffer]. */ -internal fun Buffer.unsafeToDoubleArray(): DoubleArray = when(this) { +internal fun Buffer.array(): DoubleArray = when(this) { is RealBuffer -> array else -> throw RuntimeException("Failed to cast Buffer to DoubleArray") } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt index 31c6ccbbf..b1c8cd6dd 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt @@ -21,4 +21,10 @@ class TestDoubleTensor { assertEquals(tensor[intArrayOf(0,1)], 5.8) assertTrue(tensor.elements().map{ it.second }.toList().toDoubleArray() contentEquals tensor.buffer.toDoubleArray()) } + + @Test + fun getTest() = DoubleTensorAlgebra { + val tensor = DoubleTensor(intArrayOf(2,2), doubleArrayOf(3.5,5.8,58.4,2.4)) + assertTrue(tensor[0].elements().map{ it.second }.toList().toDoubleArray() contentEquals doubleArrayOf(3.5,5.8)) + } } \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensorAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensorAlgebra.kt index 91181484c..226454bf4 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensorAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensorAlgebra.kt @@ -10,7 +10,7 @@ class TestDoubleTensorAlgebra { fun doublePlus() = DoubleTensorAlgebra { val tensor = DoubleTensor(intArrayOf(2), doubleArrayOf(1.0, 2.0)) val res = 10.0 + tensor - assertTrue(res.buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(11.0,12.0)) + assertTrue(res.buffer.array() contentEquals doubleArrayOf(11.0,12.0)) } @Test @@ -18,7 +18,7 @@ class TestDoubleTensorAlgebra { val tensor = DoubleTensor(intArrayOf(1), doubleArrayOf(0.0)) val res = tensor.transpose(0, 0) - assertTrue(res.buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(0.0)) + assertTrue(res.buffer.array() contentEquals doubleArrayOf(0.0)) assertTrue(res.shape contentEquals intArrayOf(1)) } @@ -27,7 +27,7 @@ class TestDoubleTensorAlgebra { val tensor = DoubleTensor(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.unsafeToDoubleArray() contentEquals doubleArrayOf(1.0, 3.0, 5.0, 2.0, 4.0, 6.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)) } @@ -42,9 +42,9 @@ class TestDoubleTensorAlgebra { assertTrue(res02.shape contentEquals intArrayOf(3, 2, 1)) assertTrue(res12.shape contentEquals intArrayOf(1, 3, 2)) - assertTrue(res01.buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - assertTrue(res02.buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0)) - assertTrue(res12.buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0)) + 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 @@ -70,9 +70,9 @@ class TestDoubleTensorAlgebra { assertTrue(res[1].shape contentEquals intArrayOf(1, 2, 3)) assertTrue(res[2].shape contentEquals intArrayOf(1, 2, 3)) - assertTrue(res[0].buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - assertTrue(res[1].buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0)) - assertTrue(res[2].buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(500.0, 500.0, 500.0, 500.0, 500.0, 500.0)) + 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)) } @Test @@ -82,14 +82,14 @@ class TestDoubleTensorAlgebra { val tensor3 = DoubleTensor(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) assertTrue((tensor2 - tensor1).shape contentEquals intArrayOf(2, 3)) - assertTrue((tensor2 - tensor1).buffer.unsafeToDoubleArray() contentEquals doubleArrayOf(9.0, 18.0, 27.0, 6.0, 15.0, 24.0)) + assertTrue((tensor2 - tensor1).buffer.array() 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.unsafeToDoubleArray() + assertTrue((tensor3 - tensor1).buffer.array() 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.unsafeToDoubleArray() contentEquals doubleArrayOf(490.0, 480.0, 470.0)) + assertTrue((tensor3 - tensor2).buffer.array() contentEquals doubleArrayOf(490.0, 480.0, 470.0)) } } \ No newline at end of file From f4454a6cf6b8d54b1ecd818e2c39e6287b382189 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Mon, 15 Mar 2021 22:45:55 +0000 Subject: [PATCH 034/178] Matrices from tensors test --- .../kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt index b1c8cd6dd..3050f064a 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt @@ -1,6 +1,7 @@ package space.kscience.kmath.tensors +import space.kscience.kmath.nd.as2D import space.kscience.kmath.structures.toDoubleArray import kotlin.test.Test import kotlin.test.assertEquals @@ -24,7 +25,8 @@ class TestDoubleTensor { @Test fun getTest() = DoubleTensorAlgebra { - val tensor = DoubleTensor(intArrayOf(2,2), doubleArrayOf(3.5,5.8,58.4,2.4)) - assertTrue(tensor[0].elements().map{ it.second }.toList().toDoubleArray() contentEquals doubleArrayOf(3.5,5.8)) + val tensor = DoubleTensor(intArrayOf(1,2,2), doubleArrayOf(3.5,5.8,58.4,2.4)) + val matrix = tensor[0].as2D() + assertEquals(matrix[0,1], 5.8) } } \ No newline at end of file From 0553a28ee89e0d55f498c578882fece47bc620fe Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 16 Mar 2021 07:47:02 +0000 Subject: [PATCH 035/178] ReduceOpsTensorAlgebra --- .../kmath/tensors/AnalyticTensorAlgebra.kt | 15 +++++++++++- .../tensors/DoubleAnalyticTensorAlgebra.kt | 18 ++++++++++++++- .../tensors/DoubleOrderedTensorAlgebra.kt | 2 +- .../tensors/DoubleReduceOpsTensorAlgebra.kt | 16 +++++++++++++ .../kmath/tensors/DoubleTensorAlgebra.kt | 23 ------------------- .../kmath/tensors/ReduceOpsTensorAlgebra.kt | 7 ++++++ .../kscience/kmath/tensors/TensorAlgebra.kt | 1 - .../tensors/TensorPartialDivisionAlgebra.kt | 14 ----------- .../kmath/tensors/TestDoubleTensor.kt | 12 +++++++++- 9 files changed, 66 insertions(+), 42 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleReduceOpsTensorAlgebra.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ReduceOpsTensorAlgebra.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt index 17a25b6b3..41772da44 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt @@ -2,7 +2,17 @@ package space.kscience.kmath.tensors public interface AnalyticTensorAlgebra> : - TensorPartialDivisionAlgebra { + TensorPartialDivisionAlgebra, + OrderedTensorAlgebra{ + + //https://pytorch.org/docs/stable/generated/torch.quantile.html#torch.quantile + public fun TensorType.quantile(q: T, dim: Int, keepDim: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.std.html#torch.std + public fun TensorType.std(dim: Int, unbiased: Boolean, keepDim: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.var.html#torch.var + public fun TensorType.variance(dim: Int, unbiased: Boolean, keepDim: Boolean): TensorType //https://pytorch.org/docs/stable/generated/torch.exp.html public fun TensorType.exp(): TensorType @@ -109,4 +119,7 @@ public interface AnalyticTensorAlgebra> : //https://pytorch.org/docs/stable/generated/torch.trapz.html#torch.trapz public fun TensorType.trapz(xValues: TensorType, dim: Int): TensorType + //https://pytorch.org/docs/stable/generated/torch.histc.html#torch.histc + public fun TensorType.histc(bins: Int, min: T, max: T): TensorType + } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt index 00e7a7fbd..cccc02789 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt @@ -2,7 +2,7 @@ package space.kscience.kmath.tensors public class DoubleAnalyticTensorAlgebra: AnalyticTensorAlgebra, - DoubleTensorAlgebra() + DoubleOrderedTensorAlgebra() { override fun DoubleTensor.exp(): DoubleTensor { TODO("Not yet implemented") @@ -144,6 +144,22 @@ public class DoubleAnalyticTensorAlgebra: TODO("Not yet implemented") } + override fun DoubleTensor.quantile(q: Double, dim: Int, keepDim: Boolean): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.std(dim: Int, unbiased: Boolean, keepDim: Boolean): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.variance(dim: Int, unbiased: Boolean, keepDim: Boolean): DoubleTensor { + TODO("Not yet implemented") + } + + override fun DoubleTensor.histc(bins: Int, min: Double, max: Double): DoubleTensor { + TODO("Not yet implemented") + } + } public inline fun DoubleAnalyticTensorAlgebra(block: DoubleAnalyticTensorAlgebra.() -> R): R = diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleOrderedTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleOrderedTensorAlgebra.kt index e7ebf6c56..bd6bcfe8f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleOrderedTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleOrderedTensorAlgebra.kt @@ -1,6 +1,6 @@ package space.kscience.kmath.tensors -public class DoubleOrderedTensorAlgebra: +public open class DoubleOrderedTensorAlgebra: OrderedTensorAlgebra, DoubleTensorAlgebra() { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleReduceOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleReduceOpsTensorAlgebra.kt new file mode 100644 index 000000000..00d9b3ff8 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleReduceOpsTensorAlgebra.kt @@ -0,0 +1,16 @@ +package space.kscience.kmath.tensors + +public class DoubleReduceOpsTensorAlgebra: + DoubleTensorAlgebra(), + ReduceOpsTensorAlgebra { + + override fun DoubleTensor.value(): Double { + check(this.shape contentEquals intArrayOf(1)) { + "Inconsistent value for tensor of shape ${shape.toList()}" + } + return this.buffer.array()[this.bufferStart] + } +} + +public inline fun DoubleReduceOpsTensorAlgebra(block: DoubleReduceOpsTensorAlgebra.() -> R): R = + DoubleReduceOpsTensorAlgebra().block() \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt index 3b65e89da..c383387ef 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt @@ -3,13 +3,6 @@ package space.kscience.kmath.tensors public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { - override fun DoubleTensor.value(): Double { - check(this.shape contentEquals intArrayOf(1)) { - "Inconsistent value for tensor of shape ${shape.toList()}" - } - return this.buffer.array()[this.bufferStart] - } - override operator fun DoubleTensor.get(i: Int): DoubleTensor { val lastShape = this.shape.drop(1).toIntArray() val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) @@ -257,22 +250,6 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra> : + TensorAlgebra { + public fun TensorType.value(): T + +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index e56abfaaa..60f0b3379 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -3,7 +3,6 @@ package space.kscience.kmath.tensors // https://proofwiki.org/wiki/Definition:Algebra_over_Ring public interface TensorAlgebra> { - public fun TensorType.value(): T public fun zeros(shape: IntArray): TensorType public fun TensorType.zeroesLike(): TensorType diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt index 2d448fa8c..ca3876e2c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt @@ -3,7 +3,6 @@ package space.kscience.kmath.tensors // https://proofwiki.org/wiki/Definition:Division_Algebra public interface TensorPartialDivisionAlgebra> : TensorAlgebra { - public operator fun TensorType.div(value: T): TensorType public operator fun TensorType.div(other: TensorType): TensorType public operator fun TensorType.divAssign(value: T) @@ -11,17 +10,4 @@ public interface TensorPartialDivisionAlgebra //https://pytorch.org/docs/stable/generated/torch.mean.html#torch.mean public fun TensorType.mean(dim: Int, keepDim: Boolean): TensorType - - //https://pytorch.org/docs/stable/generated/torch.quantile.html#torch.quantile - public fun TensorType.quantile(q: T, dim: Int, keepDim: Boolean): TensorType - - //https://pytorch.org/docs/stable/generated/torch.std.html#torch.std - public fun TensorType.std(dim: Int, unbiased: Boolean, keepDim: Boolean): TensorType - - //https://pytorch.org/docs/stable/generated/torch.var.html#torch.var - public fun TensorType.variance(dim: Int, unbiased: Boolean, keepDim: Boolean): TensorType - - //https://pytorch.org/docs/stable/generated/torch.histc.html#torch.histc - public fun TensorType.histc(bins: Int, min: T, max: T): TensorType - } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt index 3050f064a..006b0273a 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt @@ -1,6 +1,7 @@ package space.kscience.kmath.tensors +import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D import space.kscience.kmath.structures.toDoubleArray import kotlin.test.Test @@ -10,7 +11,7 @@ import kotlin.test.assertTrue class TestDoubleTensor { @Test - fun valueTest() = DoubleTensorAlgebra { + fun valueTest() = DoubleReduceOpsTensorAlgebra { val value = 12.5 val tensor = DoubleTensor(intArrayOf(1), doubleArrayOf(value)) assertEquals(tensor.value(), value) @@ -28,5 +29,14 @@ class TestDoubleTensor { val tensor = DoubleTensor(intArrayOf(1,2,2), doubleArrayOf(3.5,5.8,58.4,2.4)) val matrix = tensor[0].as2D() assertEquals(matrix[0,1], 5.8) + + val vector = tensor[0][1].as1D() + assertEquals(vector[0], 58.4) + + matrix[0,1] = 77.89 + assertEquals(tensor[intArrayOf(0,0,1)], 77.89) + + //vector[0] = 109.56 + //println(tensor[intArrayOf(0,1,0)]) } } \ No newline at end of file From 99ee5aa54a043427d8ade94c82107cdc18e48819 Mon Sep 17 00:00:00 2001 From: AlyaNovikova Date: Tue, 16 Mar 2021 14:57:19 +0300 Subject: [PATCH 036/178] add broadcast to functions --- .../kmath/tensors/DoubleTensorAlgebra.kt | 30 ++++++++------- .../space/kscience/kmath/tensors/utils.kt | 37 +++++++++++++++++++ .../kmath/tensors/TestDoubleTensorAlgebra.kt | 10 +++++ 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt index c383387ef..794a06102 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt @@ -69,10 +69,10 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra other.buffer.array()[other.bufferStart + i] * this } return DoubleTensor(other.shape, resBuffer) } - //todo should be change with broadcasting override fun DoubleTensor.times(value: Double): DoubleTensor = value * this override fun DoubleTensor.times(other: DoubleTensor): DoubleTensor { - //todo should be change with broadcasting - val resBuffer = DoubleArray(this.strides.linearSize) { i -> - this.buffer.array()[other.bufferStart + i] * - other.buffer.array()[other.bufferStart + i] + val broadcast = broadcastTensors(this, other) + val newThis = broadcast[0] + val newOther = broadcast[1] + + val resBuffer = DoubleArray(newThis.strides.linearSize) { i -> + newThis.buffer.array()[newOther.bufferStart + i] * + newOther.buffer.array()[newOther.bufferStart + i] } - return DoubleTensor(this.shape, resBuffer) + return DoubleTensor(newThis.shape, resBuffer) } override fun DoubleTensor.timesAssign(value: Double) { - //todo should be change with broadcasting for (i in 0 until this.strides.linearSize) { this.buffer.array()[this.bufferStart + i] *= value } } override fun DoubleTensor.timesAssign(other: DoubleTensor) { - //todo should be change with broadcasting + val newOther = broadcastTo(other, this.shape) for (i in 0 until this.strides.linearSize) { this.buffer.array()[this.bufferStart + i] *= - other.buffer.array()[this.bufferStart + i] + newOther.buffer.array()[this.bufferStart + i] } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt index 3e32e2b72..e7e043463 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt @@ -32,6 +32,43 @@ internal inline fun broadcastShapes(vararg shapes: IntArray): IntArray { return totalShape } +internal inline fun broadcastTo(tensor: DoubleTensor, newShape: IntArray): DoubleTensor { + if (tensor.shape.size > newShape.size) { + throw RuntimeException("Tensor is not compatible with the new shape") + } + + val n = newShape.reduce { acc, i -> acc * i } + val resTensor = DoubleTensor(newShape, DoubleArray(n)) + + for (i in tensor.shape.indices) { + val curDim = tensor.shape[i] + val offset = newShape.size - tensor.shape.size + if (curDim != 1 && newShape[i + offset] != curDim) { + throw RuntimeException("Tensor is not compatible with the new shape and cannot be broadcast") + } + } + + for (linearIndex in 0 until n) { + val totalMultiIndex = resTensor.strides.index(linearIndex) + val curMultiIndex = tensor.shape.copyOf() + + val offset = totalMultiIndex.size - curMultiIndex.size + + for (i in curMultiIndex.indices) { + if (curMultiIndex[i] != 1) { + curMultiIndex[i] = totalMultiIndex[i + offset] + } else { + curMultiIndex[i] = 0 + } + } + + val curLinearIndex = tensor.strides.offset(curMultiIndex) + resTensor.buffer.array()[linearIndex] = + tensor.buffer.array()[tensor.bufferStart + curLinearIndex] + } + return resTensor +} + internal inline fun broadcastTensors(vararg tensors: DoubleTensor): List { val totalShape = broadcastShapes(*(tensors.map { it.shape }).toTypedArray()) val n = totalShape.reduce { acc, i -> acc * i } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensorAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensorAlgebra.kt index 226454bf4..a060a970f 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensorAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensorAlgebra.kt @@ -58,6 +58,16 @@ class TestDoubleTensorAlgebra { ) contentEquals intArrayOf(5, 6, 7)) } + @Test + fun broadcastTo() = DoubleTensorAlgebra { + val tensor1 = DoubleTensor(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + val tensor2 = DoubleTensor(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) + + val res = broadcastTo(tensor2, tensor1.shape) + assertTrue(res.shape contentEquals intArrayOf(2, 3)) + assertTrue(res.buffer.array() contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0)) + } + @Test fun broadcastTensors() = DoubleTensorAlgebra { val tensor1 = DoubleTensor(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) From 70bebbe8488840a38e84855ca3d3eea1ddb4eebb Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 16 Mar 2021 12:12:28 +0000 Subject: [PATCH 037/178] 1D mutable structure setter fixed --- .../kotlin/space/kscience/kmath/nd/Structure1D.kt | 2 +- .../space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt | 6 ------ .../kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt | 8 -------- .../space/kscience/kmath/tensors/DoubleTensorAlgebra.kt | 8 ++++++++ .../kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt | 3 +++ .../kmath/tensors/TensorPartialDivisionAlgebra.kt | 3 +++ .../space/kscience/kmath/tensors/TestDoubleTensor.kt | 4 ++-- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt index 2926b3d1b..fd965a668 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt @@ -52,7 +52,7 @@ private inline class MutableStructure1DWrapper(val structure: MutableNDStruct override fun get(index: Int): T = structure[index] override fun set(index: Int, value: T) { - set(index, value) + structure[intArrayOf(index)] = value } override fun copy(): MutableBuffer = diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt index 41772da44..c3a558298 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt @@ -11,9 +11,6 @@ public interface AnalyticTensorAlgebra> : //https://pytorch.org/docs/stable/generated/torch.std.html#torch.std public fun TensorType.std(dim: Int, unbiased: Boolean, keepDim: Boolean): TensorType - //https://pytorch.org/docs/stable/generated/torch.var.html#torch.var - public fun TensorType.variance(dim: Int, unbiased: Boolean, keepDim: Boolean): TensorType - //https://pytorch.org/docs/stable/generated/torch.exp.html public fun TensorType.exp(): TensorType @@ -23,9 +20,6 @@ public interface AnalyticTensorAlgebra> : //https://pytorch.org/docs/stable/generated/torch.sqrt.html public fun TensorType.sqrt(): TensorType - //https://pytorch.org/docs/stable/generated/torch.square.html - public fun TensorType.square(): TensorType - //https://pytorch.org/docs/stable/generated/torch.acos.html#torch.cos public fun TensorType.cos(): TensorType diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt index cccc02789..5349a9923 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt @@ -16,10 +16,6 @@ public class DoubleAnalyticTensorAlgebra: TODO("Not yet implemented") } - override fun DoubleTensor.square(): DoubleTensor { - TODO("Not yet implemented") - } - override fun DoubleTensor.cos(): DoubleTensor { TODO("Not yet implemented") } @@ -152,10 +148,6 @@ public class DoubleAnalyticTensorAlgebra: TODO("Not yet implemented") } - override fun DoubleTensor.variance(dim: Int, unbiased: Boolean, keepDim: Boolean): DoubleTensor { - TODO("Not yet implemented") - } - override fun DoubleTensor.histc(bins: Int, min: Double, max: Double): DoubleTensor { TODO("Not yet implemented") } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt index c383387ef..bafbd9a96 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt @@ -254,6 +254,14 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra DoubleTensorAlgebra(block: DoubleTensorAlgebra.() -> R): R = diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index 60f0b3379..0af757d1a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -40,6 +40,9 @@ public interface TensorAlgebra> { public operator fun TensorType.timesAssign(other: TensorType): Unit public operator fun TensorType.unaryMinus(): TensorType + //https://pytorch.org/docs/stable/generated/torch.square.html + public fun TensorType.square(): TensorType + //https://pytorch.org/cppdocs/notes/tensor_indexing.html public operator fun TensorType.get(i: Int): TensorType diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt index ca3876e2c..9f70f9621 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt @@ -10,4 +10,7 @@ public interface TensorPartialDivisionAlgebra //https://pytorch.org/docs/stable/generated/torch.mean.html#torch.mean public fun TensorType.mean(dim: Int, keepDim: Boolean): TensorType + + //https://pytorch.org/docs/stable/generated/torch.var.html#torch.var + public fun TensorType.variance(dim: Int, unbiased: Boolean, keepDim: Boolean): TensorType } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt index 006b0273a..6b20027c7 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt @@ -36,7 +36,7 @@ class TestDoubleTensor { matrix[0,1] = 77.89 assertEquals(tensor[intArrayOf(0,0,1)], 77.89) - //vector[0] = 109.56 - //println(tensor[intArrayOf(0,1,0)]) + vector[0] = 109.56 + assertEquals(tensor[intArrayOf(0,1,0)], 109.56) } } \ No newline at end of file From bd3425e7a545622c117740bba178ec1b1b531eab Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 16 Mar 2021 14:43:20 +0000 Subject: [PATCH 038/178] IndexTensor type added to LinearOps --- .../kotlin/space/kscience/kmath/tensors/BufferedTensor.kt | 3 +++ .../kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt | 2 +- .../space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt index 264692d0c..c9a401ad5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt @@ -12,6 +12,9 @@ public open class BufferedTensor( public val strides: TensorStrides get() = TensorStrides(shape) + public val numel: Int + get() = strides.linearSize + override fun get(index: IntArray): T = buffer[bufferStart + strides.offset(index)] override fun set(index: IntArray, value: T) { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt index d6b202556..689eda9e0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt @@ -1,7 +1,7 @@ package space.kscience.kmath.tensors public class DoubleLinearOpsTensorAlgebra : - LinearOpsTensorAlgebra, + LinearOpsTensorAlgebra, DoubleTensorAlgebra() { override fun DoubleTensor.inv(): DoubleTensor { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt index 7450c09c1..2e1c4a92c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt @@ -1,7 +1,7 @@ package space.kscience.kmath.tensors -public interface LinearOpsTensorAlgebra> : +public interface LinearOpsTensorAlgebra, IndexTensorType: TensorStructure> : TensorPartialDivisionAlgebra { //https://pytorch.org/docs/stable/linalg.html#torch.linalg.inv @@ -14,7 +14,7 @@ public interface LinearOpsTensorAlgebra> : public fun TensorType.qr(): TensorType //https://pytorch.org/docs/stable/generated/torch.lu.html - public fun TensorType.lu(): Pair + public fun TensorType.lu(): Pair //https://pytorch.org/docs/stable/generated/torch.lu_unpack.html public fun luPivot(lu: TensorType, pivots: IntTensor): Triple From efb23591a9efebe3bf86b2757ac482032b5047a7 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 17 Mar 2021 07:36:35 +0000 Subject: [PATCH 039/178] Added squeeze --- .../space/kscience/kmath/tensors/DoubleTensorAlgebra.kt | 4 ++++ .../kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt | 2 ++ 2 files changed, 6 insertions(+) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt index 888f12923..675be2f33 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt @@ -266,6 +266,10 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra DoubleTensorAlgebra(block: DoubleTensorAlgebra.() -> R): R = diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index 0af757d1a..b1adf2962 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -86,4 +86,6 @@ public interface TensorAlgebra> { //https://pytorch.org/docs/stable/generated/torch.flatten.html#torch.flatten public fun TensorType.flatten(startDim: Int, endDim: Int): TensorType + //https://pytorch.org/docs/stable/generated/torch.squeeze.html + public fun TensorType.squeeze(dim: Int): TensorType } From 1fa0da2810d69aa6d9dac669b4ebc353dd5265d1 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Wed, 17 Mar 2021 17:53:14 +0300 Subject: [PATCH 040/178] complete lu and matrix mapping --- .../kscience/kmath/tensors/BufferedTensor.kt | 95 +++++++++---------- .../tensors/DoubleLinearOpsTensorAlgebra.kt | 83 ++++++++-------- .../kscience/kmath/tensors/TensorAlgebra.kt | 2 +- 3 files changed, 85 insertions(+), 95 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt index c9a401ad5..c48e47f4c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt @@ -1,5 +1,7 @@ package space.kscience.kmath.tensors +import space.kscience.kmath.linear.Matrix +import space.kscience.kmath.nd.* import space.kscience.kmath.structures.* @@ -29,59 +31,50 @@ public open class BufferedTensor( override fun hashCode(): Int = 0 + // todo rename to vector + public inline fun forEachVector(vectorAction : (MutableStructure1D) -> Unit): Unit { + check(shape.size >= 1) {"todo"} + val vectorOffset = strides.strides[0] + val vectorShape = intArrayOf(shape.last()) + for (offset in 0 until numel step vectorOffset) { + val vector = BufferedTensor(vectorShape, buffer, offset).as1D() + vectorAction(vector) + } + } + + public inline fun forEachMatrix(matrixAction : (MutableStructure2D) -> Unit): Unit { + check(shape.size >= 2) {"todo"} + val matrixOffset = strides.strides[1] + val matrixShape = intArrayOf(shape[shape.size - 2], shape.last()) //todo better way? + for (offset in 0 until numel step matrixOffset) { + val matrix = BufferedTensor(matrixShape, buffer, offset).as2D() + matrixAction(matrix) + } + } + // todo remove code copy-pasting + + public fun vectorSequence(): Sequence> = sequence { + check(shape.size >= 1) {"todo"} + val vectorOffset = strides.strides[0] + val vectorShape = intArrayOf(shape.last()) + for (offset in 0 until numel step vectorOffset) { + val vector = BufferedTensor(vectorShape, buffer, offset).as1D() + yield(vector) + } + } + + public fun matrixSequence(): Sequence> = sequence { + check(shape.size >= 2) {"todo"} + val matrixOffset = strides.strides[1] + val matrixShape = intArrayOf(shape[shape.size - 2], shape.last()) //todo better way? + for (offset in 0 until numel step matrixOffset) { + val matrix = BufferedTensor(matrixShape, buffer, offset).as2D() + yield(matrix) + } + } + } -/* -//todo make generator mb nextMatrixIndex? -public class InnerMatrix(private val tensor: BufferedTensor){ - private var offset: Int = 0 - private val n : Int = tensor.shape.size - //stride? - private val step = tensor.shape[n - 1] * tensor.shape[n - 2] - - public operator fun get(i: Int, j: Int): T { - val index = tensor.strides.index(offset) - index[n - 2] = i - index[n - 1] = j - return tensor[index] - } - - public operator fun set(i: Int, j: Int, value: T): Unit { - val index = tensor.strides.index(offset) - index[n - 2] = i - index[n - 1] = j - tensor[index] = value - } - - public fun makeStep(){ - offset += step - } -} - -public class InnerVector(private val tensor: BufferedTensor){ - private var offset: Int = 0 - private val n : Int = tensor.shape.size - //stride? - private val step = tensor.shape[n - 1] - - public operator fun get(i: Int): T { - val index = tensor.strides.index(offset) - index[n - 1] = i - return tensor[index] - } - - public operator fun set(i: Int, value: T): Unit { - val index = tensor.strides.index(offset) - index[n - 1] = i - tensor[index] = value - } - - public fun makeStep(){ - offset += step - } -} -//todo default buffer = arrayOf(0)??? - */ public class IntTensor( shape: IntArray, diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt index 689eda9e0..3f44305b1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt @@ -9,27 +9,21 @@ public class DoubleLinearOpsTensorAlgebra : } override fun DoubleTensor.lu(): Pair { - /* + // todo checks + val luTensor = this.copy() - val lu = InnerMatrix(luTensor) - //stride TODO!!! move to generator? - var matCnt = 1 - for (i in 0 until this.shape.size - 2) { - matCnt *= this.shape[i] - } + val n = this.shape.size - val m = this.shape[n - 1] - val pivotsShape = IntArray(n - 1) { i -> - this.shape[i] - } + val m = this.shape.last() + val pivotsShape = IntArray(n - 1) { i -> this.shape[i] } val pivotsTensor = IntTensor( pivotsShape, - IntArray(matCnt * m) { 0 } + IntArray(pivotsShape.reduce(Int::times)) { 0 } //todo default??? ) - val pivot = InnerVector(pivotsTensor) - for (i in 0 until matCnt) { - for (row in 0 until m) pivot[row] = row + + for ((lu, pivots) in luTensor.matrixSequence().zip(pivotsTensor.vectorSequence())){ + for (row in 0 until m) pivots[row] = row for (i in 0 until m) { var maxA = -1.0 @@ -47,9 +41,9 @@ public class DoubleLinearOpsTensorAlgebra : if (iMax != i) { - val j = pivot[i] - pivot[i] = pivot[iMax] - pivot[iMax] = j + val j = pivots[i] + pivots[i] = pivots[iMax] + pivots[iMax] = j for (k in 0 until m) { val tmp = lu[i, k] @@ -66,42 +60,45 @@ public class DoubleLinearOpsTensorAlgebra : } } } - lu.makeStep() - pivot.makeStep() } - return Pair(luTensor, pivotsTensor)*/ - TODO("Andrei, use view, get, as2D, as1D") + return Pair(luTensor, pivotsTensor) + } - override fun luPivot(lu: DoubleTensor, pivots: IntTensor): Triple { - /* - // todo checks - val n = lu.shape[0] - val p = lu.zeroesLike() - pivots.buffer.unsafeToIntArray().forEachIndexed { i, pivot -> - p[i, pivot] = 1.0 + override fun luPivot(luTensor: DoubleTensor, pivotsTensor: IntTensor): Triple { + //todo checks + val n = luTensor.shape.last() + val pTensor = luTensor.zeroesLike() + for ((p, pivot) in pTensor.matrixSequence().zip(pivotsTensor.vectorSequence())){ + for (i in 0 until n){ + p[i, pivot[i]] = 1.0 + } } - val l = lu.zeroesLike() - val u = lu.zeroesLike() - for (i in 0 until n) { - for (j in 0 until n) { - if (i == j) { - l[i, j] = 1.0 - } - if (j < i) { - l[i, j] = lu[i, j] - } - if (j >= i) { - u[i, j] = lu[i, j] + val lTensor = luTensor.zeroesLike() + val uTensor = luTensor.zeroesLike() + + for ((pairLU, lu) in lTensor.matrixSequence().zip(uTensor.matrixSequence()).zip(luTensor.matrixSequence())){ + val (l, u) = pairLU + for (i in 0 until n) { + for (j in 0 until n) { + if (i == j) { + l[i, j] = 1.0 + } + if (j < i) { + l[i, j] = lu[i, j] + } + if (j >= i) { + u[i, j] = lu[i, j] + } } } } - return Triple(p, l, u)*/ - TODO("Andrei, first we need implement get(Int)") + return Triple(pTensor, lTensor, uTensor) + } override fun DoubleTensor.cholesky(): DoubleTensor { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index b1adf2962..7ec920d88 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -5,7 +5,7 @@ public interface TensorAlgebra> { public fun zeros(shape: IntArray): TensorType - public fun TensorType.zeroesLike(): TensorType + public fun TensorType.zeroesLike(): TensorType // mb it shouldn't be tensor but algebra method (like in numpy/torch) ? public fun ones(shape: IntArray): TensorType public fun TensorType.onesLike(): TensorType From 5e94610e2862fc2ecfe5e4f9e709ecc2ab3f428a Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Fri, 19 Mar 2021 17:51:30 +0300 Subject: [PATCH 041/178] imp full and remove copypaste in geners --- .../kscience/kmath/tensors/BufferedTensor.kt | 34 +++++++------------ .../kmath/tensors/DoubleTensorAlgebra.kt | 34 +++++++------------ .../kscience/kmath/tensors/TensorAlgebra.kt | 12 +++---- 3 files changed, 31 insertions(+), 49 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt index c48e47f4c..b9ebf578a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt @@ -31,28 +31,6 @@ public open class BufferedTensor( override fun hashCode(): Int = 0 - // todo rename to vector - public inline fun forEachVector(vectorAction : (MutableStructure1D) -> Unit): Unit { - check(shape.size >= 1) {"todo"} - val vectorOffset = strides.strides[0] - val vectorShape = intArrayOf(shape.last()) - for (offset in 0 until numel step vectorOffset) { - val vector = BufferedTensor(vectorShape, buffer, offset).as1D() - vectorAction(vector) - } - } - - public inline fun forEachMatrix(matrixAction : (MutableStructure2D) -> Unit): Unit { - check(shape.size >= 2) {"todo"} - val matrixOffset = strides.strides[1] - val matrixShape = intArrayOf(shape[shape.size - 2], shape.last()) //todo better way? - for (offset in 0 until numel step matrixOffset) { - val matrix = BufferedTensor(matrixShape, buffer, offset).as2D() - matrixAction(matrix) - } - } - // todo remove code copy-pasting - public fun vectorSequence(): Sequence> = sequence { check(shape.size >= 1) {"todo"} val vectorOffset = strides.strides[0] @@ -73,6 +51,18 @@ public open class BufferedTensor( } } + public inline fun forEachVector(vectorAction : (MutableStructure1D) -> Unit): Unit { + for (vector in vectorSequence()){ + vectorAction(vector) + } + } + + public inline fun forEachMatrix(matrixAction : (MutableStructure2D) -> Unit): Unit { + for (matrix in matrixSequence()){ + matrixAction(matrix) + } + } + } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt index 675be2f33..6459f4510 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt @@ -10,23 +10,24 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra> { - public fun zeros(shape: IntArray): TensorType - public fun TensorType.zeroesLike(): TensorType // mb it shouldn't be tensor but algebra method (like in numpy/torch) ? - public fun ones(shape: IntArray): TensorType - public fun TensorType.onesLike(): TensorType - - //https://pytorch.org/docs/stable/generated/torch.full.html public fun full(shape: IntArray, value: T): TensorType + public fun ones(shape: IntArray): TensorType + public fun zeros(shape: IntArray): TensorType + //https://pytorch.org/docs/stable/generated/torch.full_like.html#torch.full_like public fun TensorType.fullLike(value: T): TensorType + public fun TensorType.zeroesLike(): TensorType + public fun TensorType.onesLike(): TensorType + //https://pytorch.org/docs/stable/generated/torch.eye.html public fun eye(n: Int): TensorType From 274be613302d8cdef5f8a81fc8aeee5c88bf8ccd Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 19 Mar 2021 19:40:17 +0000 Subject: [PATCH 042/178] Explicit broadcasting enforced --- .../kmath/tensors/LinearOpsTensorAlgebra.kt | 2 +- .../BroadcastDoubleTensorAlgebra.kt} | 151 ++++++++++-------- .../tensors/{ => core}/BufferedTensor.kt | 12 +- .../{ => core}/DoubleAnalyticTensorAlgebra.kt | 4 +- .../DoubleLinearOpsTensorAlgebra.kt | 4 +- .../{ => core}/DoubleOrderedTensorAlgebra.kt | 4 +- .../DoubleReduceOpsTensorAlgebra.kt | 6 +- .../tensors/{ => core}/DoubleTensorAlgebra.kt | 107 +++++++------ .../kscience/kmath/tensors/core/checks.kt | 67 ++++++++ .../kscience/kmath/tensors/core/utils.kt | 36 +++++ .../kmath/tensors/TestDoubleTensorAlgebra.kt | 105 ------------ .../kmath/tensors/core/TestBroadcasting.kt | 82 ++++++++++ .../tensors/{ => core}/TestDoubleTensor.kt | 10 +- .../tensors/core/TestDoubleTensorAlgebra.kt | 50 ++++++ 14 files changed, 407 insertions(+), 233 deletions(-) rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/{utils.kt => core/BroadcastDoubleTensorAlgebra.kt} (50%) rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => core}/BufferedTensor.kt (88%) rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => core}/DoubleAnalyticTensorAlgebra.kt (96%) rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => core}/DoubleLinearOpsTensorAlgebra.kt (96%) rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => core}/DoubleOrderedTensorAlgebra.kt (89%) rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => core}/DoubleReduceOpsTensorAlgebra.kt (68%) rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => core}/DoubleTensorAlgebra.kt (77%) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt delete mode 100644 kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensorAlgebra.kt create mode 100644 kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt rename kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/{ => core}/TestDoubleTensor.kt (74%) create mode 100644 kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt index 2e1c4a92c..94176564c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt @@ -17,7 +17,7 @@ public interface LinearOpsTensorAlgebra, Inde public fun TensorType.lu(): Pair //https://pytorch.org/docs/stable/generated/torch.lu_unpack.html - public fun luPivot(lu: TensorType, pivots: IntTensor): Triple + public fun luPivot(lu: TensorType, pivots: IndexTensorType): Triple //https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd public fun TensorType.svd(): Triple diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt similarity index 50% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt index e7e043463..a4767a612 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/utils.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt @@ -1,10 +1,91 @@ -package space.kscience.kmath.tensors +package space.kscience.kmath.tensors.core -import space.kscience.kmath.structures.* import kotlin.math.max +public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { + + override fun DoubleTensor.plus(other: DoubleTensor): DoubleTensor { + val broadcast = broadcastTensors(this, other) + val newThis = broadcast[0] + val newOther = broadcast[1] + val resBuffer = DoubleArray(newThis.strides.linearSize) { i -> + newThis.buffer.array()[i] + newOther.buffer.array()[i] + } + return DoubleTensor(newThis.shape, resBuffer) + } + + override fun DoubleTensor.plusAssign(other: DoubleTensor) { + val newOther = broadcastTo(other, this.shape) + for (i in 0 until this.strides.linearSize) { + this.buffer.array()[this.bufferStart + i] += + newOther.buffer.array()[this.bufferStart + i] + } + } + + override fun DoubleTensor.minus(other: DoubleTensor): DoubleTensor { + val broadcast = broadcastTensors(this, other) + val newThis = broadcast[0] + val newOther = broadcast[1] + val resBuffer = DoubleArray(newThis.strides.linearSize) { i -> + newThis.buffer.array()[i] - newOther.buffer.array()[i] + } + return DoubleTensor(newThis.shape, resBuffer) + } + + override fun DoubleTensor.minusAssign(other: DoubleTensor) { + val newOther = broadcastTo(other, this.shape) + for (i in 0 until this.strides.linearSize) { + this.buffer.array()[this.bufferStart + i] -= + newOther.buffer.array()[this.bufferStart + i] + } + } + + override fun DoubleTensor.times(other: DoubleTensor): DoubleTensor { + val broadcast = broadcastTensors(this, other) + val newThis = broadcast[0] + val newOther = broadcast[1] + val resBuffer = DoubleArray(newThis.strides.linearSize) { i -> + newThis.buffer.array()[newOther.bufferStart + i] * + newOther.buffer.array()[newOther.bufferStart + i] + } + return DoubleTensor(newThis.shape, resBuffer) + } + + override fun DoubleTensor.timesAssign(other: DoubleTensor) { + val newOther = broadcastTo(other, this.shape) + for (i in 0 until this.strides.linearSize) { + this.buffer.array()[this.bufferStart + i] *= + newOther.buffer.array()[this.bufferStart + i] + } + } + + override fun DoubleTensor.div(other: DoubleTensor): DoubleTensor { + val broadcast = broadcastTensors(this, other) + val newThis = broadcast[0] + val newOther = broadcast[1] + val resBuffer = DoubleArray(newThis.strides.linearSize) { i -> + newThis.buffer.array()[newOther.bufferStart + i] / + newOther.buffer.array()[newOther.bufferStart + i] + } + return DoubleTensor(newThis.shape, resBuffer) + } + + override fun DoubleTensor.divAssign(other: DoubleTensor) { + val newOther = broadcastTo(other, this.shape) + for (i in 0 until this.strides.linearSize) { + this.buffer.array()[this.bufferStart + i] /= + newOther.buffer.array()[this.bufferStart + i] + } + } + +} + +public inline fun broadcastDoubleTensorAlgebra(block: BroadcastDoubleTensorAlgebra.() -> R): R = + BroadcastDoubleTensorAlgebra().block() + internal inline fun broadcastShapes(vararg shapes: IntArray): IntArray { + println(shapes) var totalDim = 0 for (shape in shapes) { totalDim = max(totalDim, shape.size) @@ -99,68 +180,4 @@ internal inline fun broadcastTensors(vararg tensors: DoubleTensor): List, - TorchTensorAlgebraType : TensorAlgebra> - TorchTensorAlgebraType.checkDot(a: TensorType, b: TensorType): Unit { - val sa = a.shape - val sb = b.shape - val na = sa.size - val nb = sb.size - var status: Boolean - if (nb == 1) { - status = sa.last() == sb[0] - } else { - status = sa.last() == sb[nb - 2] - if ((na > 2) and (nb > 2)) { - status = status and - (sa.take(nb - 2).toIntArray() contentEquals sb.take(nb - 2).toIntArray()) - } - } - check(status) { "Incompatible shapes $sa and $sb for dot product" } -} - -internal inline fun , - TorchTensorAlgebraType : TensorAlgebra> - TorchTensorAlgebraType.checkTranspose(dim: Int, i: Int, j: Int): Unit = - check((i < dim) and (j < dim)) { - "Cannot transpose $i to $j for a tensor of dim $dim" - } - -internal inline fun , - TorchTensorAlgebraType : TensorAlgebra> - TorchTensorAlgebraType.checkView(a: TensorType, shape: IntArray): Unit = - check(a.shape.reduce(Int::times) == shape.reduce(Int::times)) - -/** - * Returns a reference to [IntArray] containing all of the elements of this [Buffer]. - */ -internal fun Buffer.array(): IntArray = when(this) { - is IntBuffer -> array - else -> throw RuntimeException("Failed to cast Buffer to IntArray") -} - -/** - * Returns a reference to [LongArray] containing all of the elements of this [Buffer]. - */ -internal fun Buffer.array(): LongArray = when(this) { - is LongBuffer -> array - else -> throw RuntimeException("Failed to cast Buffer to LongArray") -} - -/** - * Returns a reference to [FloatArray] containing all of the elements of this [Buffer]. - */ -internal fun Buffer.array(): FloatArray = when(this) { - is FloatBuffer -> array - else -> throw RuntimeException("Failed to cast Buffer to FloatArray") -} - -/** - * Returns a reference to [DoubleArray] containing all of the elements of this [Buffer]. - */ -internal fun Buffer.array(): DoubleArray = when(this) { - is RealBuffer -> array - else -> throw RuntimeException("Failed to cast Buffer to DoubleArray") -} +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt similarity index 88% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index c48e47f4c..cbfb15be0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/BufferedTensor.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -1,8 +1,10 @@ -package space.kscience.kmath.tensors +package space.kscience.kmath.tensors.core import space.kscience.kmath.linear.Matrix import space.kscience.kmath.nd.* import space.kscience.kmath.structures.* +import space.kscience.kmath.tensors.TensorStrides +import space.kscience.kmath.tensors.TensorStructure public open class BufferedTensor( @@ -76,25 +78,25 @@ public open class BufferedTensor( } -public class IntTensor( +public class IntTensor internal constructor( shape: IntArray, buffer: IntArray, offset: Int = 0 ) : BufferedTensor(shape, IntBuffer(buffer), offset) -public class LongTensor( +public class LongTensor internal constructor( shape: IntArray, buffer: LongArray, offset: Int = 0 ) : BufferedTensor(shape, LongBuffer(buffer), offset) -public class FloatTensor( +public class FloatTensor internal constructor( shape: IntArray, buffer: FloatArray, offset: Int = 0 ) : BufferedTensor(shape, FloatBuffer(buffer), offset) -public class DoubleTensor( +public class DoubleTensor internal constructor( shape: IntArray, buffer: DoubleArray, offset: Int = 0 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt similarity index 96% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt index 5349a9923..a34fe4b6c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleAnalyticTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt @@ -1,4 +1,6 @@ -package space.kscience.kmath.tensors +package space.kscience.kmath.tensors.core + +import space.kscience.kmath.tensors.AnalyticTensorAlgebra public class DoubleAnalyticTensorAlgebra: AnalyticTensorAlgebra, diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt similarity index 96% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 3f44305b1..8a16dc3ed 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -1,4 +1,6 @@ -package space.kscience.kmath.tensors +package space.kscience.kmath.tensors.core + +import space.kscience.kmath.tensors.LinearOpsTensorAlgebra public class DoubleLinearOpsTensorAlgebra : LinearOpsTensorAlgebra, diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleOrderedTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleOrderedTensorAlgebra.kt similarity index 89% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleOrderedTensorAlgebra.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleOrderedTensorAlgebra.kt index bd6bcfe8f..a6bea59f4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleOrderedTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleOrderedTensorAlgebra.kt @@ -1,4 +1,6 @@ -package space.kscience.kmath.tensors +package space.kscience.kmath.tensors.core + +import space.kscience.kmath.tensors.OrderedTensorAlgebra public open class DoubleOrderedTensorAlgebra: OrderedTensorAlgebra, diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleReduceOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleReduceOpsTensorAlgebra.kt similarity index 68% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleReduceOpsTensorAlgebra.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleReduceOpsTensorAlgebra.kt index 00d9b3ff8..9a8aa9ebf 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleReduceOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleReduceOpsTensorAlgebra.kt @@ -1,8 +1,10 @@ -package space.kscience.kmath.tensors +package space.kscience.kmath.tensors.core + +import space.kscience.kmath.tensors.ReduceOpsTensorAlgebra public class DoubleReduceOpsTensorAlgebra: DoubleTensorAlgebra(), - ReduceOpsTensorAlgebra { + ReduceOpsTensorAlgebra { override fun DoubleTensor.value(): Double { check(this.shape contentEquals intArrayOf(1)) { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt similarity index 77% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 675be2f33..9decc0e6a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -1,8 +1,18 @@ -package space.kscience.kmath.tensors +package space.kscience.kmath.tensors.core + +import space.kscience.kmath.tensors.TensorPartialDivisionAlgebra public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { + public fun fromArray(shape: IntArray, buffer: DoubleArray): DoubleTensor { + checkEmptyShape(shape) + checkEmptyDoubleBuffer(buffer) + checkBufferShapeConsistency(shape, buffer) + return DoubleTensor(shape, buffer, 0) + } + + override operator fun DoubleTensor.get(i: Int): DoubleTensor { val lastShape = this.shape.drop(1).toIntArray() val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) @@ -53,13 +63,11 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra - newThis.buffer.array()[i] + newOther.buffer.array()[i] + checkShapesCompatible(this, other) + val resBuffer = DoubleArray(this.strides.linearSize) { i -> + this.buffer.array()[i] + other.buffer.array()[i] } - return DoubleTensor(newThis.shape, resBuffer) + return DoubleTensor(this.shape, resBuffer) } override fun DoubleTensor.plusAssign(value: Double) { @@ -69,10 +77,10 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra - newThis.buffer.array()[i] - newOther.buffer.array()[i] + checkShapesCompatible(this, other) + val resBuffer = DoubleArray(this.strides.linearSize) { i -> + this.buffer.array()[i] - other.buffer.array()[i] } - return DoubleTensor(newThis.shape, resBuffer) + return DoubleTensor(this.shape, resBuffer) } override fun DoubleTensor.minusAssign(value: Double) { @@ -107,10 +113,10 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra - newThis.buffer.array()[newOther.bufferStart + i] * - newOther.buffer.array()[newOther.bufferStart + i] + checkShapesCompatible(this, other) + val resBuffer = DoubleArray(this.strides.linearSize) { i -> + this.buffer.array()[other.bufferStart + i] * + other.buffer.array()[other.bufferStart + i] } - return DoubleTensor(newThis.shape, resBuffer) + return DoubleTensor(this.shape, resBuffer) } override fun DoubleTensor.timesAssign(value: Double) { @@ -142,10 +145,40 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra + this.buffer.array()[this.bufferStart + i] / value + } + return DoubleTensor(this.shape, resBuffer) + } + + override fun DoubleTensor.div(other: DoubleTensor): DoubleTensor { + checkShapesCompatible(this, other) + val resBuffer = DoubleArray(this.strides.linearSize) { i -> + this.buffer.array()[other.bufferStart + i] / + other.buffer.array()[other.bufferStart + i] + } + return DoubleTensor(this.shape, resBuffer) + } + + override fun DoubleTensor.divAssign(value: Double) { + for (i in 0 until this.strides.linearSize) { + this.buffer.array()[this.bufferStart + i] /= value + } + } + + override fun DoubleTensor.divAssign(other: DoubleTensor) { + checkShapesCompatible(this, other) + for (i in 0 until this.strides.linearSize) { + this.buffer.array()[this.bufferStart + i] /= + other.buffer.array()[this.bufferStart + i] } } @@ -229,27 +262,10 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra DoubleTensorAlgebra(block: DoubleTensorAlgebra.() -> R): R = - DoubleTensorAlgebra().block() \ No newline at end of file + DoubleTensorAlgebra().block() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt new file mode 100644 index 000000000..f1ae89490 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -0,0 +1,67 @@ +package space.kscience.kmath.tensors.core + +import space.kscience.kmath.tensors.TensorAlgebra +import space.kscience.kmath.tensors.TensorStructure + + +internal inline fun , + TorchTensorAlgebraType : TensorAlgebra> + TorchTensorAlgebraType.checkEmptyShape(shape: IntArray): Unit = + check(shape.isNotEmpty()) { + "Illegal empty shape provided" + } + +internal inline fun < TensorType : TensorStructure, + TorchTensorAlgebraType : TensorAlgebra> + TorchTensorAlgebraType.checkEmptyDoubleBuffer(buffer: DoubleArray): Unit = + check(buffer.isNotEmpty()) { + "Illegal empty buffer provided" + } + +internal inline fun < TensorType : TensorStructure, + TorchTensorAlgebraType : TensorAlgebra> + TorchTensorAlgebraType.checkBufferShapeConsistency(shape: IntArray, buffer: DoubleArray): Unit = + check(buffer.size == shape.reduce(Int::times)) { + "Inconsistent shape ${shape.toList()} for buffer of size ${buffer.size} provided" + } + + +internal inline fun , + TorchTensorAlgebraType : TensorAlgebra> + TorchTensorAlgebraType.checkShapesCompatible(a: TensorType, b: TensorType): Unit = + check(a.shape contentEquals b.shape) { + "Incompatible shapes ${a.shape.toList()} and ${b.shape.toList()} " + } + + +internal inline fun , + TorchTensorAlgebraType : TensorAlgebra> + TorchTensorAlgebraType.checkDot(a: TensorType, b: TensorType): Unit { + val sa = a.shape + val sb = b.shape + val na = sa.size + val nb = sb.size + var status: Boolean + if (nb == 1) { + status = sa.last() == sb[0] + } else { + status = sa.last() == sb[nb - 2] + if ((na > 2) and (nb > 2)) { + status = status and + (sa.take(nb - 2).toIntArray() contentEquals sb.take(nb - 2).toIntArray()) + } + } + check(status) { "Incompatible shapes ${sa.toList()} and ${sb.toList()} provided for dot product" } +} + +internal inline fun , + TorchTensorAlgebraType : TensorAlgebra> + TorchTensorAlgebraType.checkTranspose(dim: Int, i: Int, j: Int): Unit = + check((i < dim) and (j < dim)) { + "Cannot transpose $i to $j for a tensor of dim $dim" + } + +internal inline fun , + TorchTensorAlgebraType : TensorAlgebra> + TorchTensorAlgebraType.checkView(a: TensorType, shape: IntArray): Unit = + check(a.shape.reduce(Int::times) == shape.reduce(Int::times)) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt new file mode 100644 index 000000000..69c8afde5 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -0,0 +1,36 @@ +package space.kscience.kmath.tensors.core + +import space.kscience.kmath.structures.* + + +/** + * Returns a reference to [IntArray] containing all of the elements of this [Buffer]. + */ +internal fun Buffer.array(): IntArray = when (this) { + is IntBuffer -> array + else -> throw RuntimeException("Failed to cast Buffer to IntArray") +} + +/** + * Returns a reference to [LongArray] containing all of the elements of this [Buffer]. + */ +internal fun Buffer.array(): LongArray = when (this) { + is LongBuffer -> array + else -> throw RuntimeException("Failed to cast Buffer to LongArray") +} + +/** + * Returns a reference to [FloatArray] containing all of the elements of this [Buffer]. + */ +internal fun Buffer.array(): FloatArray = when (this) { + is FloatBuffer -> array + else -> throw RuntimeException("Failed to cast Buffer to FloatArray") +} + +/** + * Returns a reference to [DoubleArray] containing all of the elements of this [Buffer]. + */ +internal fun Buffer.array(): DoubleArray = when (this) { + is RealBuffer -> array + else -> throw RuntimeException("Failed to cast Buffer to DoubleArray") +} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensorAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensorAlgebra.kt deleted file mode 100644 index a060a970f..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensorAlgebra.kt +++ /dev/null @@ -1,105 +0,0 @@ -package space.kscience.kmath.tensors - - -import kotlin.test.Test -import kotlin.test.assertTrue - -class TestDoubleTensorAlgebra { - - @Test - fun doublePlus() = DoubleTensorAlgebra { - val tensor = DoubleTensor(intArrayOf(2), doubleArrayOf(1.0, 2.0)) - val res = 10.0 + tensor - assertTrue(res.buffer.array() contentEquals doubleArrayOf(11.0,12.0)) - } - - @Test - fun transpose1x1() = DoubleTensorAlgebra { - val tensor = DoubleTensor(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() = DoubleTensorAlgebra { - val tensor = DoubleTensor(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() = DoubleTensorAlgebra { - val tensor = DoubleTensor(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 broadcastShapes() = DoubleTensorAlgebra { - assertTrue(broadcastShapes( - intArrayOf(2, 3), intArrayOf(1, 3), intArrayOf(1, 1, 1) - ) contentEquals intArrayOf(1, 2, 3)) - - assertTrue(broadcastShapes( - intArrayOf(6, 7), intArrayOf(5, 6, 1), intArrayOf(7,), intArrayOf(5, 1, 7) - ) contentEquals intArrayOf(5, 6, 7)) - } - - @Test - fun broadcastTo() = DoubleTensorAlgebra { - val tensor1 = DoubleTensor(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = DoubleTensor(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) - - val res = broadcastTo(tensor2, tensor1.shape) - assertTrue(res.shape contentEquals intArrayOf(2, 3)) - assertTrue(res.buffer.array() contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0)) - } - - @Test - fun broadcastTensors() = DoubleTensorAlgebra { - val tensor1 = DoubleTensor(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = DoubleTensor(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) - val tensor3 = DoubleTensor(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) - - val res = broadcastTensors(tensor1, tensor2, tensor3) - - assertTrue(res[0].shape contentEquals intArrayOf(1, 2, 3)) - 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)) - } - - @Test - fun minusTensor() = DoubleTensorAlgebra { - val tensor1 = DoubleTensor(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = DoubleTensor(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) - val tensor3 = DoubleTensor(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((tensor3 - tensor1).shape contentEquals intArrayOf(1, 2, 3)) - assertTrue((tensor3 - tensor1).buffer.array() - 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)) - } - -} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt new file mode 100644 index 000000000..2633229ea --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt @@ -0,0 +1,82 @@ +package space.kscience.kmath.tensors.core + +import kotlin.test.Test +import kotlin.test.assertTrue + +class TestBroadcasting { + + @Test + fun broadcastShapes() = DoubleTensorAlgebra { + assertTrue( + broadcastShapes( + intArrayOf(2, 3), intArrayOf(1, 3), intArrayOf(1, 1, 1) + ) contentEquals intArrayOf(1, 2, 3) + ) + + assertTrue( + broadcastShapes( + intArrayOf(6, 7), intArrayOf(5, 6, 1), intArrayOf(7), intArrayOf(5, 1, 7) + ) contentEquals intArrayOf(5, 6, 7) + ) + } + + @Test + fun broadcastTo() = DoubleTensorAlgebra { + 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 res = broadcastTo(tensor2, tensor1.shape) + assertTrue(res.shape contentEquals intArrayOf(2, 3)) + assertTrue(res.buffer.array() contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0)) + } + + @Test + fun broadcastTensors() = DoubleTensorAlgebra { + 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 tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) + + val res = broadcastTensors(tensor1, tensor2, tensor3) + + assertTrue(res[0].shape contentEquals intArrayOf(1, 2, 3)) + 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)) + } + + @Test + fun minusTensor() = DoubleTensorAlgebra { + 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 tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) + + val tensor21 = broadcastDoubleTensorAlgebra { + tensor2 - tensor1 + } + + val tensor31 = broadcastDoubleTensorAlgebra { + tensor3 - tensor1 + } + + val tensor32 = broadcastDoubleTensorAlgebra { + tensor3 - tensor2 + } + + + assertTrue(tensor21.shape contentEquals intArrayOf(2, 3)) + assertTrue(tensor21.buffer.array() contentEquals doubleArrayOf(9.0, 18.0, 27.0, 6.0, 15.0, 24.0)) + + assertTrue(tensor31.shape contentEquals intArrayOf(1, 2, 3)) + assertTrue( + tensor31.buffer.array() + contentEquals doubleArrayOf(499.0, 498.0, 497.0, 496.0, 495.0, 494.0) + ) + + assertTrue(tensor32.shape contentEquals intArrayOf(1, 1, 3)) + assertTrue(tensor32.buffer.array() contentEquals doubleArrayOf(490.0, 480.0, 470.0)) + } + +} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt similarity index 74% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt rename to kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index 6b20027c7..b12b08b52 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/TestDoubleTensor.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -1,4 +1,4 @@ -package space.kscience.kmath.tensors +package space.kscience.kmath.tensors.core import space.kscience.kmath.nd.as1D @@ -13,20 +13,20 @@ class TestDoubleTensor { @Test fun valueTest() = DoubleReduceOpsTensorAlgebra { val value = 12.5 - val tensor = DoubleTensor(intArrayOf(1), doubleArrayOf(value)) + val tensor = fromArray(intArrayOf(1), doubleArrayOf(value)) assertEquals(tensor.value(), value) } @Test - fun stridesTest(){ - val tensor = DoubleTensor(intArrayOf(2,2), doubleArrayOf(3.5,5.8,58.4,2.4)) + fun stridesTest() = DoubleTensorAlgebra { + val tensor = fromArray(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.toDoubleArray()) } @Test fun getTest() = DoubleTensorAlgebra { - val tensor = DoubleTensor(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() assertEquals(matrix[0,1], 5.8) diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt new file mode 100644 index 000000000..8b4d5ca16 --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -0,0 +1,50 @@ +package space.kscience.kmath.tensors.core + + +import kotlin.test.Test +import kotlin.test.assertTrue + +class TestDoubleTensorAlgebra { + + @Test + fun doublePlus() = DoubleTensorAlgebra { + val tensor = fromArray(intArrayOf(2), doubleArrayOf(1.0, 2.0)) + val res = 10.0 + tensor + assertTrue(res.buffer.array() contentEquals doubleArrayOf(11.0, 12.0)) + } + + @Test + fun transpose1x1() = DoubleTensorAlgebra { + val tensor = fromArray(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() = DoubleTensorAlgebra { + 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) + + 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() = DoubleTensorAlgebra { + 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 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)) + } + +} \ No newline at end of file From 3535e512483b74f00867858b18e38a2150f3451c Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 19 Mar 2021 19:52:58 +0000 Subject: [PATCH 043/178] Broadcasting as its own algebra --- .../core/BroadcastDoubleTensorAlgebra.kt | 2 +- .../kmath/tensors/core/TestBroadcasting.kt | 17 ++++------------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt index a4767a612..20f64f469 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt @@ -80,7 +80,7 @@ public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { } -public inline fun broadcastDoubleTensorAlgebra(block: BroadcastDoubleTensorAlgebra.() -> R): R = +public inline fun BroadcastDoubleTensorAlgebra(block: BroadcastDoubleTensorAlgebra.() -> R): R = BroadcastDoubleTensorAlgebra().block() diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt index 2633229ea..73e3993a1 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt @@ -48,23 +48,14 @@ class TestBroadcasting { } @Test - fun minusTensor() = DoubleTensorAlgebra { + fun minusTensor() = BroadcastDoubleTensorAlgebra { 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 tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) - val tensor21 = broadcastDoubleTensorAlgebra { - tensor2 - tensor1 - } - - val tensor31 = broadcastDoubleTensorAlgebra { - tensor3 - tensor1 - } - - val tensor32 = broadcastDoubleTensorAlgebra { - tensor3 - tensor2 - } - + val tensor21 = tensor2 - tensor1 + val tensor31 = tensor3 - tensor1 + val tensor32 = tensor3 - tensor2 assertTrue(tensor21.shape contentEquals intArrayOf(2, 3)) assertTrue(tensor21.buffer.array() contentEquals doubleArrayOf(9.0, 18.0, 27.0, 6.0, 15.0, 24.0)) From 93d3cb47bed67d95c75d6e9f54283f7428dd150e Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 19 Mar 2021 20:10:08 +0000 Subject: [PATCH 044/178] Testing linear structure --- .../kscience/kmath/tensors/TensorAlgebra.kt | 12 +++---- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 35 ++++++++----------- .../tensors/core/TestDoubleTensorAlgebra.kt | 32 +++++++++++++++++ 3 files changed, 51 insertions(+), 28 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index 7ec920d88..1673657d3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -3,19 +3,17 @@ package space.kscience.kmath.tensors // https://proofwiki.org/wiki/Definition:Algebra_over_Ring public interface TensorAlgebra> { + //https://pytorch.org/docs/stable/generated/torch.full.html + public fun full(value: T, shape: IntArray): TensorType + + //https://pytorch.org/docs/stable/generated/torch.full_like.html#torch.full_like + public fun TensorType.fullLike(value: T): TensorType public fun zeros(shape: IntArray): TensorType public fun TensorType.zeroesLike(): TensorType // mb it shouldn't be tensor but algebra method (like in numpy/torch) ? public fun ones(shape: IntArray): TensorType public fun TensorType.onesLike(): TensorType - - //https://pytorch.org/docs/stable/generated/torch.full.html - public fun full(shape: IntArray, value: T): TensorType - - //https://pytorch.org/docs/stable/generated/torch.full_like.html#torch.full_like - public fun TensorType.fullLike(value: T): TensorType - //https://pytorch.org/docs/stable/generated/torch.eye.html public fun eye(n: Int): TensorType diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 9decc0e6a..1c156b4e3 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -20,23 +20,25 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra Date: Fri, 19 Mar 2021 20:32:57 +0000 Subject: [PATCH 045/178] merge PR --- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 465c2ddc1..875f21687 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -12,7 +12,6 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra>>>>>> ups/feature/tensor-algebra:kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt override fun DoubleTensor.fullLike(value: Double): DoubleTensor { val shape = this.shape val buffer = DoubleArray(this.strides.linearSize) { value } return DoubleTensor(shape, buffer) } -<<<<<<< HEAD:kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/DoubleTensorAlgebra.kt - override fun DoubleTensor.zeroesLike(): DoubleTensor = this.fullLike(0.0) - -======= override fun zeros(shape: IntArray): DoubleTensor = full(0.0, shape) override fun DoubleTensor.zeroesLike(): DoubleTensor = this.fullLike(0.0) override fun ones(shape: IntArray): DoubleTensor = full(1.0, shape) ->>>>>>> ups/feature/tensor-algebra:kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt override fun DoubleTensor.onesLike(): DoubleTensor = this.fullLike(1.0) override fun eye(n: Int): DoubleTensor { @@ -71,7 +53,6 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra other.buffer.array()[other.bufferStart + i] + this From b7e1349eadc0cfe9b573006c79e714333655a2d1 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Sat, 20 Mar 2021 18:59:54 +0000 Subject: [PATCH 046/178] atanh as example --- .../kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt index a34fe4b6c..8a579b7da 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt @@ -1,6 +1,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.tensors.AnalyticTensorAlgebra +import kotlin.math.* public class DoubleAnalyticTensorAlgebra: AnalyticTensorAlgebra, @@ -63,7 +64,11 @@ public class DoubleAnalyticTensorAlgebra: } override fun DoubleTensor.atanh(): DoubleTensor { - TODO("Not yet implemented") + return DoubleTensor( + this.shape, + this.buffer.array().map(::atanh).toDoubleArray(), + this.bufferStart + ) } override fun DoubleTensor.ceil(): DoubleTensor { From 94e5ee4a6de020d77c49ce57e7795d3a33abe80e Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Sun, 21 Mar 2021 08:01:52 +0000 Subject: [PATCH 047/178] TensorLinearStructure introduced --- .../space/kscience/kmath/nd/StructureND.kt | 17 +++---- .../core/BroadcastDoubleTensorAlgebra.kt | 24 +++++----- .../kmath/tensors/core/BufferedTensor.kt | 18 ++++---- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 44 +++++++++---------- .../TensorLinearStructure.kt} | 33 ++++++++------ 5 files changed, 69 insertions(+), 67 deletions(-) rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/{TensorStrides.kt => core/TensorLinearStructure.kt} (55%) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt index 86b867130..f28d29e47 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt @@ -177,7 +177,7 @@ public interface Strides { /** * Array strides */ - public val strides: IntArray + public val strides: List /** * Get linear index from multidimensional index @@ -209,12 +209,6 @@ public interface Strides { } } -internal inline 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() - /** * Simple implementation of [Strides]. */ @@ -225,7 +219,7 @@ public class DefaultStrides private constructor(override val shape: IntArray) : /** * Strides for memory access */ - override val strides: IntArray by lazy { + override val strides: List by lazy { sequence { var current = 1 yield(1) @@ -234,10 +228,13 @@ public class DefaultStrides private constructor(override val shape: IntArray) : current *= it yield(current) } - }.toList().toIntArray() + }.toList() } - override fun offset(index: IntArray): Int = offsetFromIndex(index, shape, strides) + override fun offset(index: 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() override fun index(offset: Int): IntArray { val res = IntArray(shape.size) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt index 20f64f469..4bfbe5863 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt @@ -8,7 +8,7 @@ public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val broadcast = broadcastTensors(this, other) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.strides.linearSize) { i -> + val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> newThis.buffer.array()[i] + newOther.buffer.array()[i] } return DoubleTensor(newThis.shape, resBuffer) @@ -16,7 +16,7 @@ public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun DoubleTensor.plusAssign(other: DoubleTensor) { val newOther = broadcastTo(other, this.shape) - for (i in 0 until this.strides.linearSize) { + for (i in 0 until this.linearStructure.size) { this.buffer.array()[this.bufferStart + i] += newOther.buffer.array()[this.bufferStart + i] } @@ -26,7 +26,7 @@ public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val broadcast = broadcastTensors(this, other) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.strides.linearSize) { i -> + val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> newThis.buffer.array()[i] - newOther.buffer.array()[i] } return DoubleTensor(newThis.shape, resBuffer) @@ -34,7 +34,7 @@ public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun DoubleTensor.minusAssign(other: DoubleTensor) { val newOther = broadcastTo(other, this.shape) - for (i in 0 until this.strides.linearSize) { + for (i in 0 until this.linearStructure.size) { this.buffer.array()[this.bufferStart + i] -= newOther.buffer.array()[this.bufferStart + i] } @@ -44,7 +44,7 @@ public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val broadcast = broadcastTensors(this, other) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.strides.linearSize) { i -> + val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> newThis.buffer.array()[newOther.bufferStart + i] * newOther.buffer.array()[newOther.bufferStart + i] } @@ -53,7 +53,7 @@ public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun DoubleTensor.timesAssign(other: DoubleTensor) { val newOther = broadcastTo(other, this.shape) - for (i in 0 until this.strides.linearSize) { + for (i in 0 until this.linearStructure.size) { this.buffer.array()[this.bufferStart + i] *= newOther.buffer.array()[this.bufferStart + i] } @@ -63,7 +63,7 @@ public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val broadcast = broadcastTensors(this, other) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.strides.linearSize) { i -> + val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> newThis.buffer.array()[newOther.bufferStart + i] / newOther.buffer.array()[newOther.bufferStart + i] } @@ -72,7 +72,7 @@ public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun DoubleTensor.divAssign(other: DoubleTensor) { val newOther = broadcastTo(other, this.shape) - for (i in 0 until this.strides.linearSize) { + for (i in 0 until this.linearStructure.size) { this.buffer.array()[this.bufferStart + i] /= newOther.buffer.array()[this.bufferStart + i] } @@ -130,7 +130,7 @@ internal inline fun broadcastTo(tensor: DoubleTensor, newShape: IntArray): Doubl } for (linearIndex in 0 until n) { - val totalMultiIndex = resTensor.strides.index(linearIndex) + val totalMultiIndex = resTensor.linearStructure.index(linearIndex) val curMultiIndex = tensor.shape.copyOf() val offset = totalMultiIndex.size - curMultiIndex.size @@ -143,7 +143,7 @@ internal inline fun broadcastTo(tensor: DoubleTensor, newShape: IntArray): Doubl } } - val curLinearIndex = tensor.strides.offset(curMultiIndex) + val curLinearIndex = tensor.linearStructure.offset(curMultiIndex) resTensor.buffer.array()[linearIndex] = tensor.buffer.array()[tensor.bufferStart + curLinearIndex] } @@ -159,7 +159,7 @@ internal inline fun broadcastTensors(vararg tensors: DoubleTensor): List( internal val bufferStart: Int ) : TensorStructure { - public val strides: TensorStrides - get() = TensorStrides(shape) + public val linearStructure: TensorLinearStructure + get() = TensorLinearStructure(shape) public val numel: Int - get() = strides.linearSize + get() = linearStructure.size - override fun get(index: IntArray): T = buffer[bufferStart + strides.offset(index)] + override fun get(index: IntArray): T = buffer[bufferStart + linearStructure.offset(index)] override fun set(index: IntArray, value: T) { - buffer[bufferStart + strides.offset(index)] = value + buffer[bufferStart + linearStructure.offset(index)] = value } - override fun elements(): Sequence> = strides.indices().map { + override fun elements(): Sequence> = linearStructure.indices().map { it to this[it] } @@ -35,7 +33,7 @@ public open class BufferedTensor( public fun vectorSequence(): Sequence> = sequence { check(shape.size >= 1) {"todo"} - val vectorOffset = strides.strides[0] + val vectorOffset = linearStructure.strides[0] val vectorShape = intArrayOf(shape.last()) for (offset in 0 until numel step vectorOffset) { val vector = BufferedTensor(vectorShape, buffer, offset).as1D() @@ -45,7 +43,7 @@ public open class BufferedTensor( public fun matrixSequence(): Sequence> = sequence { check(shape.size >= 2) {"todo"} - val matrixOffset = strides.strides[1] + val matrixOffset = linearStructure.strides[1] val matrixShape = intArrayOf(shape[shape.size - 2], shape.last()) //todo better way? for (offset in 0 until numel step matrixOffset) { val matrix = BufferedTensor(matrixShape, buffer, offset).as2D() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 875f21687..385118d97 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -27,7 +27,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra + val resBuffer = DoubleArray(other.linearStructure.size) { i -> other.buffer.array()[other.bufferStart + i] + this } return DoubleTensor(other.shape, resBuffer) @@ -64,35 +64,35 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra + val resBuffer = DoubleArray(this.linearStructure.size) { i -> this.buffer.array()[i] + other.buffer.array()[i] } return DoubleTensor(this.shape, resBuffer) } override fun DoubleTensor.plusAssign(value: Double) { - for (i in 0 until this.strides.linearSize) { + for (i in 0 until this.linearStructure.size) { this.buffer.array()[this.bufferStart + i] += value } } override fun DoubleTensor.plusAssign(other: DoubleTensor) { checkShapesCompatible(this, other) - for (i in 0 until this.strides.linearSize) { + for (i in 0 until this.linearStructure.size) { this.buffer.array()[this.bufferStart + i] += other.buffer.array()[this.bufferStart + i] } } override fun Double.minus(other: DoubleTensor): DoubleTensor { - val resBuffer = DoubleArray(other.strides.linearSize) { i -> + val resBuffer = DoubleArray(other.linearStructure.size) { i -> this - other.buffer.array()[other.bufferStart + i] } return DoubleTensor(other.shape, resBuffer) } override fun DoubleTensor.minus(value: Double): DoubleTensor { - val resBuffer = DoubleArray(this.strides.linearSize) { i -> + val resBuffer = DoubleArray(this.linearStructure.size) { i -> this.buffer.array()[this.bufferStart + i] - value } return DoubleTensor(this.shape, resBuffer) @@ -100,28 +100,28 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra + val resBuffer = DoubleArray(this.linearStructure.size) { i -> this.buffer.array()[i] - other.buffer.array()[i] } return DoubleTensor(this.shape, resBuffer) } override fun DoubleTensor.minusAssign(value: Double) { - for (i in 0 until this.strides.linearSize) { + for (i in 0 until this.linearStructure.size) { this.buffer.array()[this.bufferStart + i] -= value } } override fun DoubleTensor.minusAssign(other: DoubleTensor) { checkShapesCompatible(this, other) - for (i in 0 until this.strides.linearSize) { + for (i in 0 until this.linearStructure.size) { this.buffer.array()[this.bufferStart + i] -= other.buffer.array()[this.bufferStart + i] } } override fun Double.times(other: DoubleTensor): DoubleTensor { - val resBuffer = DoubleArray(other.strides.linearSize) { i -> + val resBuffer = DoubleArray(other.linearStructure.size) { i -> other.buffer.array()[other.bufferStart + i] * this } return DoubleTensor(other.shape, resBuffer) @@ -131,7 +131,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra + val resBuffer = DoubleArray(this.linearStructure.size) { i -> this.buffer.array()[other.bufferStart + i] * other.buffer.array()[other.bufferStart + i] } @@ -139,21 +139,21 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra + val resBuffer = DoubleArray(this.linearStructure.size) { i -> this.buffer.array()[this.bufferStart + i] / value } return DoubleTensor(this.shape, resBuffer) @@ -161,7 +161,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra + val resBuffer = DoubleArray(this.linearStructure.size) { i -> this.buffer.array()[other.bufferStart + i] / other.buffer.array()[other.bufferStart + i] } @@ -169,21 +169,21 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra + val resBuffer = DoubleArray(this.linearStructure.size) { i -> this.buffer.array()[this.bufferStart + i].unaryMinus() } return DoubleTensor(this.shape, resBuffer) @@ -191,7 +191,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra + if (value < 0 || value >= shape[i]) throw IndexOutOfBoundsException("Index $value out of shape bounds: (0,${shape[i]})") + value * strides[i] + }.sum() + internal inline fun stridesFromShape(shape: IntArray): IntArray { val nDim = shape.size val res = IntArray(nDim) @@ -35,7 +39,7 @@ internal inline fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): return res } -internal inline fun nextIndex(index: IntArray, shape: IntArray, nDim: Int): IntArray { +internal inline fun stepIndex(index: IntArray, shape: IntArray, nDim: Int): IntArray { val res = index.copyOf() var current = nDim - 1 var carry = 0 @@ -47,26 +51,29 @@ internal inline fun nextIndex(index: IntArray, shape: IntArray, nDim: Int): IntA res[current] = 0 } current-- - } while(carry != 0 && current >= 0) + } while (carry != 0 && current >= 0) return res } - -public class TensorStrides(override val shape: IntArray): Strides +public class TensorLinearStructure(public val shape: IntArray) { - override val strides: IntArray + public val strides: IntArray get() = stridesFromShape(shape) - override fun offset(index: IntArray): Int = offsetFromIndex(index, shape, strides) + public fun offset(index: IntArray): Int = offsetFromIndex(index, shape, strides) - override fun index(offset: Int): IntArray = + public fun index(offset: Int): IntArray = indexFromOffset(offset, strides, shape.size) - override fun nextIndex(index: IntArray): IntArray = - nextIndex(index, shape, shape.size) + public fun stepIndex(index: IntArray): IntArray = + stepIndex(index, shape, shape.size) - override val linearSize: Int + public val size: Int get() = shape.reduce(Int::times) + + public fun indices(): Sequence = (0 until size).asSequence().map { + index(it) + } } \ No newline at end of file From d8ef190ed8912476aaf7901431cc7e24d6449d94 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Sun, 21 Mar 2021 08:07:17 +0000 Subject: [PATCH 048/178] UnaryPlus fails API check --- .../kotlin/space/kscience/kmath/nd/StructureND.kt | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt index f28d29e47..78eac1809 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt @@ -189,11 +189,6 @@ public interface Strides { */ 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 */ @@ -232,7 +227,7 @@ public class DefaultStrides private constructor(override val shape: IntArray) : } override fun offset(index: IntArray): Int = index.mapIndexed { i, value -> - if (value < 0 || value >= shape[i]) throw IndexOutOfBoundsException("Index $value out of shape bounds: (0,${shape[i]})") + if (value < 0 || value >= shape[i]) throw IndexOutOfBoundsException("Index $value out of shape bounds: (0,${this.shape[i]})") value * strides[i] }.sum() @@ -250,10 +245,6 @@ public class DefaultStrides private constructor(override val shape: IntArray) : return res } - override fun nextIndex(index: IntArray): IntArray { - TODO("Not yet implemented") - } - override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is DefaultStrides) return false @@ -275,7 +266,6 @@ public class DefaultStrides private constructor(override val shape: IntArray) : } } - public inline fun StructureND.combine( struct: StructureND, crossinline block: (T, T) -> T, From fa78ed1f45f3598e26d74d21d6f79c623c9e8e8e Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Sun, 21 Mar 2021 19:05:11 +0300 Subject: [PATCH 049/178] map and analytic funcions --- .../kmath/tensors/LinearOpsTensorAlgebra.kt | 4 +- .../kscience/kmath/tensors/TensorAlgebra.kt | 5 ++ .../kmath/tensors/core/BufferedTensor.kt | 1 + .../core/DoubleAnalyticTensorAlgebra.kt | 73 +++++-------------- .../core/DoubleLinearOpsTensorAlgebra.kt | 63 +++++++++++----- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 39 +++++++++- .../kscience/kmath/tensors/core/checks.kt | 14 +++- 7 files changed, 122 insertions(+), 77 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt index 94176564c..c4fa3e0a8 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt @@ -14,10 +14,10 @@ public interface LinearOpsTensorAlgebra, Inde public fun TensorType.qr(): TensorType //https://pytorch.org/docs/stable/generated/torch.lu.html - public fun TensorType.lu(): Pair + public fun TensorType.lu(tol: T): Pair //https://pytorch.org/docs/stable/generated/torch.lu_unpack.html - public fun luPivot(lu: TensorType, pivots: IndexTensorType): Triple + public fun luPivot(luTensor: TensorType, pivotsTensor: IndexTensorType): Triple //https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd public fun TensorType.svd(): Triple diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index e41b7546c..8be0dc149 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -3,6 +3,11 @@ package space.kscience.kmath.tensors // https://proofwiki.org/wiki/Definition:Algebra_over_Ring public interface TensorAlgebra> { + public fun TensorType.map(transform: (T) -> T): TensorType + + public fun TensorType.eq(other: TensorType, eqFunction: (T, T) -> Boolean): Boolean + public fun TensorType.contentEquals(other: TensorType, eqFunction: (T, T) -> Boolean): Boolean + //https://pytorch.org/docs/stable/generated/torch.full.html public fun full(value: T, shape: IntArray): TensorType diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 5a0fc6c75..ca9168c91 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -5,6 +5,7 @@ import space.kscience.kmath.nd.* import space.kscience.kmath.structures.* import space.kscience.kmath.tensors.TensorStrides import space.kscience.kmath.tensors.TensorStructure +import kotlin.math.atanh public open class BufferedTensor( diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt index 8a579b7da..1eb4c3b63 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt @@ -7,77 +7,40 @@ public class DoubleAnalyticTensorAlgebra: AnalyticTensorAlgebra, DoubleOrderedTensorAlgebra() { - override fun DoubleTensor.exp(): DoubleTensor { - TODO("Not yet implemented") - } + override fun DoubleTensor.exp(): DoubleTensor = this.map(::exp) - override fun DoubleTensor.log(): DoubleTensor { - TODO("Not yet implemented") - } + // todo log with other base???? + override fun DoubleTensor.log(): DoubleTensor = this.map(::ln) - override fun DoubleTensor.sqrt(): DoubleTensor { - TODO("Not yet implemented") - } + override fun DoubleTensor.sqrt(): DoubleTensor = this.map(::sqrt) - override fun DoubleTensor.cos(): DoubleTensor { - TODO("Not yet implemented") - } + override fun DoubleTensor.cos(): DoubleTensor = this.map(::cos) - override fun DoubleTensor.acos(): DoubleTensor { - TODO("Not yet implemented") - } + override fun DoubleTensor.acos(): DoubleTensor = this.map(::acos) - override fun DoubleTensor.cosh(): DoubleTensor { - TODO("Not yet implemented") - } + override fun DoubleTensor.cosh(): DoubleTensor = this.map(::cosh) - override fun DoubleTensor.acosh(): DoubleTensor { - TODO("Not yet implemented") - } + override fun DoubleTensor.acosh(): DoubleTensor = this.map(::acosh) - override fun DoubleTensor.sin(): DoubleTensor { - TODO("Not yet implemented") - } + override fun DoubleTensor.sin(): DoubleTensor = this.map(::sin) - override fun DoubleTensor.asin(): DoubleTensor { - TODO("Not yet implemented") - } + override fun DoubleTensor.asin(): DoubleTensor = this.map(::asin) - override fun DoubleTensor.sinh(): DoubleTensor { - TODO("Not yet implemented") - } + override fun DoubleTensor.sinh(): DoubleTensor = this.map(::sinh) - override fun DoubleTensor.asinh(): DoubleTensor { - TODO("Not yet implemented") - } + override fun DoubleTensor.asinh(): DoubleTensor = this.map(::asinh) - override fun DoubleTensor.tan(): DoubleTensor { - TODO("Not yet implemented") - } + override fun DoubleTensor.tan(): DoubleTensor = this.map(::tan) - override fun DoubleTensor.atan(): DoubleTensor { - TODO("Not yet implemented") - } + override fun DoubleTensor.atan(): DoubleTensor = this.map(::atan) - override fun DoubleTensor.tanh(): DoubleTensor { - TODO("Not yet implemented") - } + override fun DoubleTensor.tanh(): DoubleTensor = this.map(::tanh) - override fun DoubleTensor.atanh(): DoubleTensor { - return DoubleTensor( - this.shape, - this.buffer.array().map(::atanh).toDoubleArray(), - this.bufferStart - ) - } + override fun DoubleTensor.atanh(): DoubleTensor = this.map(::atanh) - override fun DoubleTensor.ceil(): DoubleTensor { - TODO("Not yet implemented") - } + override fun DoubleTensor.ceil(): DoubleTensor = this.map(::ceil) - override fun DoubleTensor.floor(): DoubleTensor { - TODO("Not yet implemented") - } + override fun DoubleTensor.floor(): DoubleTensor = this.map(::floor) override fun DoubleTensor.clamp(min: Double, max: Double): DoubleTensor { TODO("Not yet implemented") diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 8a16dc3ed..e0abc49b7 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -1,6 +1,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.tensors.LinearOpsTensorAlgebra +import kotlin.math.sqrt public class DoubleLinearOpsTensorAlgebra : LinearOpsTensorAlgebra, @@ -10,47 +11,47 @@ public class DoubleLinearOpsTensorAlgebra : TODO("Not yet implemented") } - override fun DoubleTensor.lu(): Pair { + override fun DoubleTensor.lu(tol: Double): Pair { - // todo checks + checkSquareMatrix(shape) - val luTensor = this.copy() + val luTensor = copy() - val n = this.shape.size - val m = this.shape.last() - val pivotsShape = IntArray(n - 1) { i -> this.shape[i] } + val n = shape.size + val m = shape.last() + val pivotsShape = IntArray(n - 1) { i -> shape[i] } val pivotsTensor = IntTensor( pivotsShape, - IntArray(pivotsShape.reduce(Int::times)) { 0 } //todo default??? + IntArray(pivotsShape.reduce(Int::times)) { 0 } ) for ((lu, pivots) in luTensor.matrixSequence().zip(pivotsTensor.vectorSequence())){ for (row in 0 until m) pivots[row] = row for (i in 0 until m) { - var maxA = -1.0 - var iMax = i + var maxVal = -1.0 + var maxInd = i for (k in i until m) { val absA = kotlin.math.abs(lu[k, i]) - if (absA > maxA) { - maxA = absA - iMax = k + if (absA > maxVal) { + maxVal = absA + maxInd = k } } //todo check singularity - if (iMax != i) { + if (maxInd != i) { val j = pivots[i] - pivots[i] = pivots[iMax] - pivots[iMax] = j + pivots[i] = pivots[maxInd] + pivots[maxInd] = j for (k in 0 until m) { val tmp = lu[i, k] - lu[i, k] = lu[iMax, k] - lu[iMax, k] = tmp + lu[i, k] = lu[maxInd, k] + lu[maxInd, k] = tmp } } @@ -71,6 +72,9 @@ public class DoubleLinearOpsTensorAlgebra : override fun luPivot(luTensor: DoubleTensor, pivotsTensor: IntTensor): Triple { //todo checks + checkSquareMatrix(luTensor.shape) + check(luTensor.shape.dropLast(1).toIntArray() contentEquals pivotsTensor.shape) { "Bed shapes (("} //todo rewrite + val n = luTensor.shape.last() val pTensor = luTensor.zeroesLike() for ((p, pivot) in pTensor.matrixSequence().zip(pivotsTensor.vectorSequence())){ @@ -104,7 +108,30 @@ public class DoubleLinearOpsTensorAlgebra : } override fun DoubleTensor.cholesky(): DoubleTensor { - TODO("Not yet implemented") + // todo checks + checkSquareMatrix(shape) + + val n = shape.last() + val lTensor = zeroesLike() + + for ((a, l) in this.matrixSequence().zip(lTensor.matrixSequence())) { + for (i in 0 until n) { + for (j in 0 until i) { + var h = a[i, j] + for (k in 0 until j) { + h -= l[i, k] * l[j, k] + } + l[i, j] = h / l[j, j] + } + var h = a[i, i] + for (j in 0 until i) { + h -= l[i, j] * l[i, j] + } + l[i, i] = sqrt(h) + } + } + + return lTensor } override fun DoubleTensor.qr(): DoubleTensor { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 875f21687..daa8b6d74 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -1,7 +1,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.tensors.TensorPartialDivisionAlgebra - +import kotlin.math.abs public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { @@ -277,6 +277,43 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra Double): DoubleTensor { + return DoubleTensor( + this.shape, + this.buffer.array().map { transform(it) }.toDoubleArray(), + this.bufferStart + ) + } + + public fun DoubleTensor.contentEquals(other: DoubleTensor, delta: Double = 1e-5): Boolean { + return this.contentEquals(other) { x, y -> abs(x - y) < delta } + } + + public fun DoubleTensor.eq(other: DoubleTensor, delta: Double = 1e-5): Boolean { + return this.eq(other) { x, y -> abs(x - y) < delta } + } + + override fun DoubleTensor.contentEquals(other: DoubleTensor, eqFunction: (Double, Double) -> Boolean): Boolean { + if (!(this.shape contentEquals other.shape)){ + return false + } + return this.eq(other, eqFunction) + } + + override fun DoubleTensor.eq(other: DoubleTensor, eqFunction: (Double, Double) -> Boolean): Boolean { + // todo broadcasting checking + val n = this.strides.linearSize + if (n != other.strides.linearSize){ + return false + } + for (i in 0 until n){ + if (!eqFunction(this.buffer[this.bufferStart + i], other.buffer[other.bufferStart + i])) { + return false + } + } + return true + } + } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt index f1ae89490..ec7a123a9 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -64,4 +64,16 @@ internal inline fun , internal inline fun , TorchTensorAlgebraType : TensorAlgebra> TorchTensorAlgebraType.checkView(a: TensorType, shape: IntArray): Unit = - check(a.shape.reduce(Int::times) == shape.reduce(Int::times)) \ No newline at end of file + check(a.shape.reduce(Int::times) == shape.reduce(Int::times)) + +internal inline fun , + TorchTensorAlgebraType : TensorAlgebra> + TorchTensorAlgebraType.checkSquareMatrix(shape: IntArray): Unit { + val n = shape.size + check(n >= 2) { + "Expected tensor with 2 or more dimensions, got size $n instead" + } + check(shape[n - 1] == shape[n - 2]) { + "Tensor must be batches of square matrices, but they are ${shape[n - 1]} by ${shape[n - 1]} matrices" + } +} From df402086daeb0b15c78a1a0d987cd46dd5122801 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Sun, 21 Mar 2021 19:08:30 +0300 Subject: [PATCH 050/178] init test for analytic algebra --- .../core/TestDoubleAnalyticTensorAlgebra.kt | 35 +++++++++++++++++++ .../tensors/core/TestDoubleTensorAlgebra.kt | 4 +++ 2 files changed, 39 insertions(+) create mode 100644 kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt new file mode 100644 index 000000000..8028ce175 --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt @@ -0,0 +1,35 @@ +package space.kscience.kmath.tensors.core + +import kotlin.math.abs +import kotlin.math.exp +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class TestDoubleAnalyticTensorAlgebra { + + val shape = intArrayOf(2, 1, 3, 2) + val buffer = doubleArrayOf(27.1, 20.0, 19.84, 23.123, 0.0, 1.0, 3.23, 133.7, 25.3, 100.3, 11.0, 12.012) + val tensor = DoubleTensor(shape, buffer) + + fun DoubleArray.fmap(transform: (Double) -> Double): DoubleArray { + return this.map(transform).toDoubleArray() + } + + fun DoubleArray.deltaEqual(other: DoubleArray, delta: Double = 1e-5): Boolean { + for ((elem1, elem2) in this.asSequence().zip(other.asSequence())) { + if (abs(elem1 - elem2) > delta) { + return false + } + } + return true + } + + @Test + fun testExp() = DoubleAnalyticTensorAlgebra { + tensor.exp().let { + assertTrue { shape contentEquals it.shape } + assertTrue { buffer.fmap(::exp).deltaEqual(it.buffer.array())} + } + } +} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index ddfba0d59..06aa3ebf7 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -79,4 +79,8 @@ class TestDoubleTensorAlgebra { assertTrue(expected.buffer.array() contentEquals assignResult.buffer.array()) } + @Test + fun testContentEqual() = DoubleTensorAlgebra { + //TODO() + } } \ No newline at end of file From 0365d41f317af785f4963611f4c3899171618720 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Sun, 21 Mar 2021 17:57:19 +0000 Subject: [PATCH 051/178] Merged PR --- kmath-core/api/kmath-core.api | 485 ++++++++++++++++++ .../kscience/kmath/tensors/TensorAlgebra.kt | 5 - .../kmath/tensors/core/DoubleTensorAlgebra.kt | 10 +- 3 files changed, 490 insertions(+), 10 deletions(-) diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index 04325379e..70bec600d 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -972,6 +972,30 @@ public final class space/kscience/kmath/nd/GroupND$DefaultImpls { public static fun unaryPlus (Lspace/kscience/kmath/nd/GroupND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; } +public abstract interface class space/kscience/kmath/nd/MutableStructure1D : space/kscience/kmath/nd/MutableStructureND, space/kscience/kmath/nd/Structure1D, space/kscience/kmath/structures/MutableBuffer { + public abstract fun set ([ILjava/lang/Object;)V +} + +public final class space/kscience/kmath/nd/MutableStructure1D$DefaultImpls { + public static fun get (Lspace/kscience/kmath/nd/MutableStructure1D;[I)Ljava/lang/Object; + public static fun getDimension (Lspace/kscience/kmath/nd/MutableStructure1D;)I + public static fun iterator (Lspace/kscience/kmath/nd/MutableStructure1D;)Ljava/util/Iterator; + public static fun set (Lspace/kscience/kmath/nd/MutableStructure1D;[ILjava/lang/Object;)V +} + +public abstract interface class space/kscience/kmath/nd/MutableStructure2D : space/kscience/kmath/nd/MutableStructureND, space/kscience/kmath/nd/Structure2D { + public abstract fun set (IILjava/lang/Object;)V +} + +public final class space/kscience/kmath/nd/MutableStructure2D$DefaultImpls { + public static fun elements (Lspace/kscience/kmath/nd/MutableStructure2D;)Lkotlin/sequences/Sequence; + public static fun get (Lspace/kscience/kmath/nd/MutableStructure2D;[I)Ljava/lang/Object; + public static fun getColumns (Lspace/kscience/kmath/nd/MutableStructure2D;)Ljava/util/List; + public static fun getDimension (Lspace/kscience/kmath/nd/MutableStructure2D;)I + public static fun getRows (Lspace/kscience/kmath/nd/MutableStructure2D;)Ljava/util/List; + public static fun getShape (Lspace/kscience/kmath/nd/MutableStructure2D;)[I +} + public abstract interface class space/kscience/kmath/nd/MutableStructureND : space/kscience/kmath/nd/StructureND { public abstract fun set ([ILjava/lang/Object;)V } @@ -1072,6 +1096,7 @@ public final class space/kscience/kmath/nd/Structure1D$DefaultImpls { } public final class space/kscience/kmath/nd/Structure1DKt { + public static final fun as1D (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructure1D; public static final fun as1D (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Structure1D; public static final fun asND (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/nd/Structure1D; } @@ -1101,6 +1126,7 @@ public final class space/kscience/kmath/nd/Structure2D$DefaultImpls { } public final class space/kscience/kmath/nd/Structure2DKt { + public static final fun as2D (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructure2D; public static final fun as2D (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Structure2D; } @@ -2582,3 +2608,462 @@ public final class space/kscience/kmath/structures/VirtualBuffer : space/kscienc public fun iterator ()Ljava/util/Iterator; } +public abstract interface class space/kscience/kmath/tensors/AnalyticTensorAlgebra : space/kscience/kmath/tensors/OrderedTensorAlgebra, space/kscience/kmath/tensors/TensorPartialDivisionAlgebra { + public abstract fun acos (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun acosh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun asin (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun asinh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun atan (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun atanh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun ceil (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun clamp (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun cos (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun cosh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun erf (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun erfc (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun erfinv (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun exp (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun floor (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun heaviside (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun histc (Lspace/kscience/kmath/nd/MutableStructureND;ILjava/lang/Object;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun igamma (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun igammac (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun lerp (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun lgamma (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun log (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun logit (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun mvlgamma (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun polygamma (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun pow (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun quantile (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun round (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun sigmoid (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun sin (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun sinc (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun sinh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun sqrt (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun std (Lspace/kscience/kmath/nd/MutableStructureND;IZZ)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun tan (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun tanh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun trapz (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; +} + +public abstract interface class space/kscience/kmath/tensors/ComplexTensorAlgebra : space/kscience/kmath/tensors/TensorPartialDivisionAlgebra { + public abstract fun angle (Lspace/kscience/kmath/tensors/ComplexTensorStructure;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun bartlettWindow (IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun blackmanWindow (IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun cartesianEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/tensors/ComplexTensorStructure; + public abstract fun hammingWindow (IZLjava/lang/Object;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun inverseShortTimeFourierTransform (Lspace/kscience/kmath/tensors/ComplexTensorStructure;IIILspace/kscience/kmath/nd/MutableStructureND;ZZZI)V + public abstract fun kaiserWindow (IZLjava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun polarEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/tensors/ComplexTensorStructure; + public abstract fun shortTimeFourierTransform (Lspace/kscience/kmath/tensors/ComplexTensorStructure;IIILspace/kscience/kmath/nd/MutableStructureND;ZZ)V + public abstract fun viewAsComplex (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/tensors/ComplexTensorStructure; +} + +public abstract interface class space/kscience/kmath/tensors/ComplexTensorStructure : space/kscience/kmath/nd/MutableStructureND { + public abstract fun imaginaryPart ()Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun realPart ()Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun viewAsReal ()Lspace/kscience/kmath/nd/MutableStructureND; +} + +public final class space/kscience/kmath/tensors/ComplexTensorStructure$DefaultImpls { + public static fun getDimension (Lspace/kscience/kmath/tensors/ComplexTensorStructure;)I +} + +public abstract interface class space/kscience/kmath/tensors/LinearOpsTensorAlgebra : space/kscience/kmath/tensors/TensorPartialDivisionAlgebra { + public abstract fun cholesky (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun inv (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun lu (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lkotlin/Pair; + public abstract fun luPivot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; + public abstract fun qr (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun svd (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; + public abstract fun symEig (Lspace/kscience/kmath/nd/MutableStructureND;Z)Lkotlin/Pair; +} + +public final class space/kscience/kmath/tensors/LinearOpsTensorAlgebra$DefaultImpls { + public static synthetic fun symEig$default (Lspace/kscience/kmath/tensors/LinearOpsTensorAlgebra;Lspace/kscience/kmath/nd/MutableStructureND;ZILjava/lang/Object;)Lkotlin/Pair; +} + +public abstract interface class space/kscience/kmath/tensors/OrderedTensorAlgebra : space/kscience/kmath/tensors/TensorAlgebra { + public abstract fun cummax (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun cummin (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun max (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun maximum (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public abstract fun median (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun min (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun minimum (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public abstract fun sort (Lspace/kscience/kmath/nd/MutableStructureND;IZZ)Lspace/kscience/kmath/nd/MutableStructureND; +} + +public abstract interface class space/kscience/kmath/tensors/ReduceOpsTensorAlgebra : space/kscience/kmath/tensors/TensorAlgebra { + public abstract fun value (Lspace/kscience/kmath/nd/MutableStructureND;)Ljava/lang/Object; +} + +public abstract interface class space/kscience/kmath/tensors/TensorAlgebra { + public abstract fun abs (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun cat (Ljava/util/List;I)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun copy (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun cumprod (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun cumsum (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun det (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun diagonalEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;III)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun dot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun eye (I)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun flatten (Lspace/kscience/kmath/nd/MutableStructureND;II)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun full (Ljava/lang/Object;[I)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun fullLike (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun get (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun minus (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun minus (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V + public abstract fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public abstract fun ones ([I)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun onesLike (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun plus (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun plus (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun plus (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V + public abstract fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public abstract fun prod (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun square (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun squeeze (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun sum (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun times (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun times (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun times (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun timesAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V + public abstract fun timesAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public abstract fun transpose (Lspace/kscience/kmath/nd/MutableStructureND;II)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun unaryMinus (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun view (Lspace/kscience/kmath/nd/MutableStructureND;[I)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun viewAs (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun zeroesLike (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun zeros ([I)Lspace/kscience/kmath/nd/MutableStructureND; +} + +public final class space/kscience/kmath/tensors/TensorAlgebra$DefaultImpls { + public static synthetic fun diagonalEmbedding$default (Lspace/kscience/kmath/tensors/TensorAlgebra;Lspace/kscience/kmath/nd/MutableStructureND;IIIILjava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; +} + +public abstract interface class space/kscience/kmath/tensors/TensorPartialDivisionAlgebra : space/kscience/kmath/tensors/TensorAlgebra { + public abstract fun div (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun div (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun divAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V + public abstract fun divAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public abstract fun mean (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun variance (Lspace/kscience/kmath/nd/MutableStructureND;IZZ)Lspace/kscience/kmath/nd/MutableStructureND; +} + +public final class space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra : space/kscience/kmath/tensors/core/DoubleTensorAlgebra { + public fun ()V + public synthetic fun div (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun div (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun divAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public fun divAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V + public synthetic fun minus (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun minus (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public fun minusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V + public synthetic fun plus (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun plus (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public fun plusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V + public synthetic fun times (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun times (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun timesAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public fun timesAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V +} + +public final class space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebraKt { + public static final fun BroadcastDoubleTensorAlgebra (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; +} + +public class space/kscience/kmath/tensors/core/BufferedTensor : space/kscience/kmath/nd/MutableStructureND { + public fun ([ILspace/kscience/kmath/structures/MutableBuffer;I)V + public fun elements ()Lkotlin/sequences/Sequence; + public fun equals (Ljava/lang/Object;)Z + public final fun forEachMatrix (Lkotlin/jvm/functions/Function1;)V + public final fun forEachVector (Lkotlin/jvm/functions/Function1;)V + public fun get ([I)Ljava/lang/Object; + public final fun getBuffer ()Lspace/kscience/kmath/structures/MutableBuffer; + public fun getDimension ()I + public final fun getLinearStructure ()Lspace/kscience/kmath/tensors/core/TensorLinearStructure; + public final fun getNumel ()I + public fun getShape ()[I + public fun hashCode ()I + public final fun matrixSequence ()Lkotlin/sequences/Sequence; + public fun set ([ILjava/lang/Object;)V + public final fun vectorSequence ()Lkotlin/sequences/Sequence; +} + +public final class space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra : space/kscience/kmath/tensors/core/DoubleOrderedTensorAlgebra, space/kscience/kmath/tensors/AnalyticTensorAlgebra { + public fun ()V + public synthetic fun acos (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun acos (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun acosh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun acosh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun asin (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun asin (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun asinh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun asinh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun atan (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun atan (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun atanh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun atanh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun ceil (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun ceil (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun clamp (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun clamp (Lspace/kscience/kmath/tensors/core/DoubleTensor;DD)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun cos (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun cos (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun cosh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun cosh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun erf (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun erf (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun erfc (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun erfc (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun erfinv (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun erfinv (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun exp (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun exp (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun floor (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun floor (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun heaviside (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun heaviside (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun histc (Lspace/kscience/kmath/nd/MutableStructureND;ILjava/lang/Object;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun histc (Lspace/kscience/kmath/tensors/core/DoubleTensor;IDD)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun igamma (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun igamma (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun igammac (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun igammac (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun lerp (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun lerp (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun lgamma (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun lgamma (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun log (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun log (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun logit (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun logit (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun mvlgamma (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public fun mvlgamma (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun polygamma (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public fun polygamma (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun pow (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun pow (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun quantile (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public fun quantile (Lspace/kscience/kmath/tensors/core/DoubleTensor;DIZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun round (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun round (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun sigmoid (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun sigmoid (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun sin (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun sin (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun sinc (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun sinc (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun sinh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun sinh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun sqrt (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun sqrt (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun std (Lspace/kscience/kmath/nd/MutableStructureND;IZZ)Lspace/kscience/kmath/nd/MutableStructureND; + public fun std (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun tan (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun tan (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun tanh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun tanh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun trapz (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public fun trapz (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; +} + +public final class space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebraKt { + public static final fun DoubleAnalyticTensorAlgebra (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; +} + +public final class space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra : space/kscience/kmath/tensors/core/DoubleTensorAlgebra, space/kscience/kmath/tensors/LinearOpsTensorAlgebra { + public fun ()V + public synthetic fun cholesky (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun cholesky (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun inv (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun inv (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun lu (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lkotlin/Pair; + public fun lu (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lkotlin/Pair; + public synthetic fun luPivot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; + public fun luPivot (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/IntTensor;)Lkotlin/Triple; + public synthetic fun qr (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun qr (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun svd (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; + public fun svd (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lkotlin/Triple; + public synthetic fun symEig (Lspace/kscience/kmath/nd/MutableStructureND;Z)Lkotlin/Pair; + public fun symEig (Lspace/kscience/kmath/tensors/core/DoubleTensor;Z)Lkotlin/Pair; +} + +public final class space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebraKt { + public static final fun DoubleLinearOpsTensorAlgebra (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; +} + +public class space/kscience/kmath/tensors/core/DoubleOrderedTensorAlgebra : space/kscience/kmath/tensors/core/DoubleTensorAlgebra, space/kscience/kmath/tensors/OrderedTensorAlgebra { + public fun ()V + public synthetic fun cummax (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public fun cummax (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun cummin (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public fun cummin (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun max (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public fun max (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun maximum (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public fun maximum (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V + public synthetic fun median (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public fun median (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun min (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public fun min (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun minimum (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public fun minimum (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V + public synthetic fun sort (Lspace/kscience/kmath/nd/MutableStructureND;IZZ)Lspace/kscience/kmath/nd/MutableStructureND; + public fun sort (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; +} + +public final class space/kscience/kmath/tensors/core/DoubleOrderedTensorAlgebraKt { + public static final fun DoubleOrderedTensorAlgebra (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; +} + +public final class space/kscience/kmath/tensors/core/DoubleReduceOpsTensorAlgebra : space/kscience/kmath/tensors/core/DoubleTensorAlgebra, space/kscience/kmath/tensors/ReduceOpsTensorAlgebra { + public fun ()V + public synthetic fun value (Lspace/kscience/kmath/nd/MutableStructureND;)Ljava/lang/Object; + public fun value (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Ljava/lang/Double; +} + +public final class space/kscience/kmath/tensors/core/DoubleReduceOpsTensorAlgebraKt { + public static final fun DoubleReduceOpsTensorAlgebra (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; +} + +public final class space/kscience/kmath/tensors/core/DoubleTensor : space/kscience/kmath/tensors/core/BufferedTensor { +} + +public class space/kscience/kmath/tensors/core/DoubleTensorAlgebra : space/kscience/kmath/tensors/TensorPartialDivisionAlgebra { + public fun ()V + public synthetic fun abs (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun abs (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun cat (Ljava/util/List;I)Lspace/kscience/kmath/nd/MutableStructureND; + public fun cat (Ljava/util/List;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public final fun contentEquals (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Z + public final fun contentEquals (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lkotlin/jvm/functions/Function2;)Z + public static synthetic fun contentEquals$default (Lspace/kscience/kmath/tensors/core/DoubleTensorAlgebra;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;DILjava/lang/Object;)Z + public synthetic fun copy (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun copy (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun cumprod (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public fun cumprod (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun cumsum (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public fun cumsum (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun det (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun det (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun diagonalEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;III)Lspace/kscience/kmath/nd/MutableStructureND; + public fun diagonalEmbedding (Lspace/kscience/kmath/tensors/core/DoubleTensor;III)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun div (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public synthetic fun div (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun div (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public fun div (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun divAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V + public synthetic fun divAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public fun divAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)V + public fun divAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V + public synthetic fun dot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun dot (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public final fun eq (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Z + public final fun eq (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lkotlin/jvm/functions/Function2;)Z + public static synthetic fun eq$default (Lspace/kscience/kmath/tensors/core/DoubleTensorAlgebra;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;DILjava/lang/Object;)Z + public synthetic fun eye (I)Lspace/kscience/kmath/nd/MutableStructureND; + public fun eye (I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun flatten (Lspace/kscience/kmath/nd/MutableStructureND;II)Lspace/kscience/kmath/nd/MutableStructureND; + public fun flatten (Lspace/kscience/kmath/tensors/core/DoubleTensor;II)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public final fun fromArray ([I[D)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public fun full (D[I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun full (Ljava/lang/Object;[I)Lspace/kscience/kmath/nd/MutableStructureND; + public synthetic fun fullLike (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun fullLike (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun get (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public fun get (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public final fun map (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun mean (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public fun mean (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public fun minus (DLspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public synthetic fun minus (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public synthetic fun minus (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun minus (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public fun minus (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V + public synthetic fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public fun minusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)V + public fun minusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V + public synthetic fun ones ([I)Lspace/kscience/kmath/nd/MutableStructureND; + public fun ones ([I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun onesLike (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun onesLike (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public fun plus (DLspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun plus (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public synthetic fun plus (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public synthetic fun plus (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun plus (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public fun plus (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V + public synthetic fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public fun plusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)V + public fun plusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V + public synthetic fun prod (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public fun prod (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun square (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun square (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun squeeze (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; + public fun squeeze (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun sum (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; + public fun sum (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public fun times (DLspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun times (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public synthetic fun times (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public synthetic fun times (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun times (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public fun times (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun timesAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V + public synthetic fun timesAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V + public fun timesAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)V + public fun timesAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V + public synthetic fun transpose (Lspace/kscience/kmath/nd/MutableStructureND;II)Lspace/kscience/kmath/nd/MutableStructureND; + public fun transpose (Lspace/kscience/kmath/tensors/core/DoubleTensor;II)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun unaryMinus (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun unaryMinus (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun variance (Lspace/kscience/kmath/nd/MutableStructureND;IZZ)Lspace/kscience/kmath/nd/MutableStructureND; + public fun variance (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun view (Lspace/kscience/kmath/nd/MutableStructureND;[I)Lspace/kscience/kmath/nd/MutableStructureND; + public fun view (Lspace/kscience/kmath/tensors/core/DoubleTensor;[I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun viewAs (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun viewAs (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun zeroesLike (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun zeroesLike (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun zeros ([I)Lspace/kscience/kmath/nd/MutableStructureND; + public fun zeros ([I)Lspace/kscience/kmath/tensors/core/DoubleTensor; +} + +public final class space/kscience/kmath/tensors/core/DoubleTensorAlgebraKt { + public static final fun DoubleTensorAlgebra (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; +} + +public final class space/kscience/kmath/tensors/core/FloatTensor : space/kscience/kmath/tensors/core/BufferedTensor { +} + +public final class space/kscience/kmath/tensors/core/IntTensor : space/kscience/kmath/tensors/core/BufferedTensor { +} + +public final class space/kscience/kmath/tensors/core/LongTensor : space/kscience/kmath/tensors/core/BufferedTensor { +} + +public final class space/kscience/kmath/tensors/core/TensorLinearStructure { + public fun ([I)V + public final fun getShape ()[I + public final fun getSize ()I + public final fun getStrides ()[I + public final fun index (I)[I + public final fun indices ()Lkotlin/sequences/Sequence; + public final fun offset ([I)I + public final fun stepIndex ([I)[I +} + diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index 8be0dc149..e41b7546c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -3,11 +3,6 @@ package space.kscience.kmath.tensors // https://proofwiki.org/wiki/Definition:Algebra_over_Ring public interface TensorAlgebra> { - public fun TensorType.map(transform: (T) -> T): TensorType - - public fun TensorType.eq(other: TensorType, eqFunction: (T, T) -> Boolean): Boolean - public fun TensorType.contentEquals(other: TensorType, eqFunction: (T, T) -> Boolean): Boolean - //https://pytorch.org/docs/stable/generated/torch.full.html public fun full(value: T, shape: IntArray): TensorType diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 57339adfa..67b50970b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -277,7 +277,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra Double): DoubleTensor { + public fun DoubleTensor.map(transform: (Double) -> Double): DoubleTensor { return DoubleTensor( this.shape, this.buffer.array().map { transform(it) }.toDoubleArray(), @@ -293,17 +293,17 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra abs(x - y) < delta } } - override fun DoubleTensor.contentEquals(other: DoubleTensor, eqFunction: (Double, Double) -> Boolean): Boolean { + public fun DoubleTensor.contentEquals(other: DoubleTensor, eqFunction: (Double, Double) -> Boolean): Boolean { if (!(this.shape contentEquals other.shape)){ return false } return this.eq(other, eqFunction) } - override fun DoubleTensor.eq(other: DoubleTensor, eqFunction: (Double, Double) -> Boolean): Boolean { + public fun DoubleTensor.eq(other: DoubleTensor, eqFunction: (Double, Double) -> Boolean): Boolean { // todo broadcasting checking - val n = this.strides.linearSize - if (n != other.strides.linearSize){ + val n = this.linearStructure.size + if (n != other.linearStructure.size){ return false } for (i in 0 until n){ From 2d2c4bd4744af9f3d841571d213170b1d661fa8f Mon Sep 17 00:00:00 2001 From: AlyaNovikova Date: Tue, 23 Mar 2021 14:53:54 +0300 Subject: [PATCH 052/178] add broadcast of all dims except the last 2, add tensors dot, fix bug in function times --- .../core/BroadcastDoubleTensorAlgebra.kt | 59 +++++++++++++- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 80 ++++++++++++++++++- .../kmath/tensors/core/TestBroadcasting.kt | 30 +++++++ .../tensors/core/TestDoubleTensorAlgebra.kt | 14 ++++ 4 files changed, 180 insertions(+), 3 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt index 4bfbe5863..425178fc1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt @@ -85,7 +85,6 @@ public inline fun BroadcastDoubleTensorAlgebra(block: BroadcastDoubleTensorA internal inline fun broadcastShapes(vararg shapes: IntArray): IntArray { - println(shapes) var totalDim = 0 for (shape in shapes) { totalDim = max(totalDim, shape.size) @@ -179,5 +178,63 @@ internal inline fun broadcastTensors(vararg tensors: DoubleTensor): List { + var onlyTwoDims = true + for (tensor in tensors) { + if (tensor.shape.size < 2) { + throw RuntimeException("Tensors must have at least 2 dimensions") + } + if (tensor.shape.size != 2) { + onlyTwoDims = false + } + } + + if (onlyTwoDims) { + return tensors.asList() + } + + val totalShape = broadcastShapes(*(tensors.map { it.shape.sliceArray(0..it.shape.size - 3) }).toTypedArray()) + val n = totalShape.reduce { acc, i -> acc * i } + + val res = ArrayList(0) + for (tensor in tensors) { + val matrixShape = tensor.shape.sliceArray(tensor.shape.size - 2 until tensor.shape.size).copyOf() + val matrixSize = matrixShape[0] * matrixShape[1] + val matrix = DoubleTensor(matrixShape, DoubleArray(matrixSize)) + + val outerTensor = DoubleTensor(totalShape, DoubleArray(n)) + val resTensor = DoubleTensor(totalShape + matrixShape, DoubleArray(n * matrixSize)) + + for (linearIndex in 0 until n) { + val totalMultiIndex = outerTensor.linearStructure.index(linearIndex) + var curMultiIndex = tensor.shape.sliceArray(0..tensor.shape.size - 3).copyOf() + curMultiIndex = IntArray(totalMultiIndex.size - curMultiIndex.size) {1} + curMultiIndex + + val newTensor = DoubleTensor(curMultiIndex + matrixShape, tensor.buffer.array()) + + for (i in curMultiIndex.indices) { + if (curMultiIndex[i] != 1) { + curMultiIndex[i] = totalMultiIndex[i] + } else { + curMultiIndex[i] = 0 + } + } + + for (i in 0 until matrixSize) { + val curLinearIndex = newTensor.linearStructure.offset(curMultiIndex + + matrix.linearStructure.index(i)) + val newLinearIndex = resTensor.linearStructure.offset(totalMultiIndex + + matrix.linearStructure.index(i)) + + resTensor.buffer.array()[resTensor.bufferStart + newLinearIndex] = + newTensor.buffer.array()[newTensor.bufferStart + curLinearIndex] + } + } + res.add(resTensor) + } + return res } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 67b50970b..9cdc6c130 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -132,7 +132,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra - this.buffer.array()[other.bufferStart + i] * + this.buffer.array()[this.bufferStart + i] * other.buffer.array()[other.bufferStart + i] } return DoubleTensor(this.shape, resBuffer) @@ -241,8 +241,84 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra 2 || other.shape.size > 2) { + throw RuntimeException("Both tensors must have a maximum of 2 dimensions") + } + + if (this.shape[1] != other.shape[0]) { + throw RuntimeException("Tensors dot operation dimension mismatch: " + + "(${this.shape[0]}, ${this.shape[1]}) x (${other.shape[0]}, ${other.shape[1]})") + } + + val l = this.shape[0] + val m = this.shape[1] + val n = other.shape[1] + + val res = DoubleTensor(intArrayOf(l, n), DoubleArray(l * n)) + + for (i in 0 until l) { + for (j in 0 until n) { + var curr = 0.0 + for (k in 0 until m) { + val ik = this.linearStructure.offset(intArrayOf(i, k)) + val kj = other.linearStructure.offset(intArrayOf(k, j)) + curr += this.buffer.array()[ik] * other.buffer.array()[kj] + } + val linearIndex = res.linearStructure.offset(intArrayOf(i, j)) + res.buffer.array()[linearIndex] = curr + } + } + return res + } + override fun DoubleTensor.dot(other: DoubleTensor): DoubleTensor { - TODO("Alya") + if (this.shape.size == 1 && other.shape.size == 1) { + return DoubleTensor(intArrayOf(1), doubleArrayOf(this.times(other).buffer.array().sum())) + } + + var newThis = this.copy() + var newOther = other.copy() + if (this.shape.size == 1) { + newThis = this.view(intArrayOf(1) + this.shape) + } + if (other.shape.size == 1) { + newOther = other.view(other.shape + intArrayOf(1) ) + } + + val broadcastTensors = broadcastOuterTensors(newThis, newOther) + newThis = broadcastTensors[0] + newOther = broadcastTensors[1] + + val l = newThis.shape[newThis.shape.size - 2] + val m1= newThis.shape[newThis.shape.size - 1] + val m2 = newOther.shape[newOther.shape.size - 2] + val n = newOther.shape[newOther.shape.size - 1] + if (m1 != m2) { + throw RuntimeException("Tensors dot operation dimension mismatch: ($l, $m1) x ($m2, $n)") + } + val m = m1 + + var resShape = newThis.shape.sliceArray(0..(newThis.shape.size - 2)) + intArrayOf(newOther.shape.last()) + val resSize = resShape.reduce { acc, i -> acc * i } + val resTensor = DoubleTensor(resShape, DoubleArray(resSize)) + + for ((res, ab) in resTensor.matrixSequence().zip(newThis.matrixSequence().zip(newOther.matrixSequence()))) { + val a = ab.first + val b = ab.second + + for (i in 0 until l) { + for (j in 0 until n) { + var curr = 0.0 + for (k in 0 until m) { + curr += a[i, k] * b[k, j] + } + res[i, j] = curr + } + } + } + + return resTensor } override fun diagonalEmbedding(diagonalEntries: DoubleTensor, offset: Int, dim1: Int, dim2: Int): DoubleTensor { diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt index 73e3993a1..41c9b72f7 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt @@ -47,6 +47,36 @@ class TestBroadcasting { assertTrue(res[2].buffer.array() contentEquals doubleArrayOf(500.0, 500.0, 500.0, 500.0, 500.0, 500.0)) } + @Test + fun broadcastOuterTensors() = DoubleTensorAlgebra { + 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 tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) + + val res = broadcastOuterTensors(tensor1, tensor2, tensor3) + + assertTrue(res[0].shape contentEquals intArrayOf(1, 2, 3)) + assertTrue(res[1].shape contentEquals intArrayOf(1, 1, 3)) + assertTrue(res[2].shape contentEquals intArrayOf(1, 1, 1)) + + 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)) + assertTrue(res[2].buffer.array() contentEquals doubleArrayOf(500.0)) + } + + @Test + fun broadcastOuterTensorsShapes() = DoubleTensorAlgebra { + 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 tensor3 = fromArray(intArrayOf(1, 1), doubleArrayOf(500.0)) + + val res = broadcastOuterTensors(tensor1, tensor2, tensor3) + + assertTrue(res[0].shape contentEquals intArrayOf(4, 2, 5, 3, 2, 3)) + assertTrue(res[1].shape contentEquals intArrayOf(4, 2, 5, 3, 3, 3)) + assertTrue(res[2].shape contentEquals intArrayOf(4, 2, 5, 3, 1, 1)) + } + @Test fun minusTensor() = BroadcastDoubleTensorAlgebra { val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index 06aa3ebf7..aa3c14412 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -79,6 +79,20 @@ class TestDoubleTensorAlgebra { assertTrue(expected.buffer.array() contentEquals assignResult.buffer.array()) } + @Test + fun dot() = DoubleTensorAlgebra { + val tensor1 = fromArray(intArrayOf(2, 3), 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 res12 = tensor1.dot(tensor2) + + assertTrue(res12.buffer.array() contentEquals doubleArrayOf(140.0, 320.0)) + assertTrue(res12.shape contentEquals intArrayOf(2, 1)) + + val tensor4 = fromArray(intArrayOf(10, 3, 4), DoubleArray(10 * 3 * 4) {0.0}) + val tensor5 = fromArray(intArrayOf(10, 4, 5), DoubleArray(10 * 4 * 5) {0.0}) + assertTrue(tensor4.dot(tensor5).shape contentEquals intArrayOf(10, 3, 5)) + } + @Test fun testContentEqual() = DoubleTensorAlgebra { //TODO() From 078686a04660e78b9929d2ed9a3c61f3fa888e62 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Tue, 23 Mar 2021 15:59:55 +0300 Subject: [PATCH 053/178] hotfix sequence --- .../space/kscience/kmath/tensors/core/BufferedTensor.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 4f5e1f9f0..160c61260 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -34,7 +34,8 @@ public open class BufferedTensor( public fun vectorSequence(): Sequence> = sequence { check(shape.size >= 1) {"todo"} - val vectorOffset = linearStructure.strides[0] + val n = shape.size + val vectorOffset = shape[n - 1] val vectorShape = intArrayOf(shape.last()) for (offset in 0 until numel step vectorOffset) { val vector = BufferedTensor(vectorShape, buffer, offset).as1D() @@ -44,8 +45,9 @@ public open class BufferedTensor( public fun matrixSequence(): Sequence> = sequence { check(shape.size >= 2) {"todo"} - val matrixOffset = linearStructure.strides[1] - val matrixShape = intArrayOf(shape[shape.size - 2], shape.last()) //todo better way? + val n = shape.size + val matrixOffset = shape[n - 1] * shape[n - 2] + val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) //todo better way? for (offset in 0 until numel step matrixOffset) { val matrix = BufferedTensor(matrixShape, buffer, offset).as2D() yield(matrix) From e01ca38fb3a7b05037582f561298928be552100e Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 23 Mar 2021 13:51:52 +0000 Subject: [PATCH 054/178] Tasks for Andrei and Alya --- .../kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt | 8 ++++---- .../kscience/kmath/tensors/core/DoubleTensorAlgebra.kt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index e0abc49b7..8a16a991d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -8,7 +8,7 @@ public class DoubleLinearOpsTensorAlgebra : DoubleTensorAlgebra() { override fun DoubleTensor.inv(): DoubleTensor { - TODO("Not yet implemented") + TODO("ANDREI") } override fun DoubleTensor.lu(tol: Double): Pair { @@ -135,16 +135,16 @@ public class DoubleLinearOpsTensorAlgebra : } override fun DoubleTensor.qr(): DoubleTensor { - TODO("Not yet implemented") + TODO("ANDREI") } override fun DoubleTensor.svd(): Triple { - TODO("Not yet implemented") + TODO("ALYA") } override fun DoubleTensor.symEig(eigenvectors: Boolean): Pair { - TODO("Not yet implemented") + TODO("ANDREI") } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 67b50970b..c67687a09 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -262,7 +262,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra Date: Wed, 24 Mar 2021 14:00:47 +0300 Subject: [PATCH 055/178] fix --- .../space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt | 2 +- .../kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt index c4fa3e0a8..e412af7c6 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt @@ -14,7 +14,7 @@ public interface LinearOpsTensorAlgebra, Inde public fun TensorType.qr(): TensorType //https://pytorch.org/docs/stable/generated/torch.lu.html - public fun TensorType.lu(tol: T): Pair + public fun TensorType.lu(): Pair //https://pytorch.org/docs/stable/generated/torch.lu_unpack.html public fun luPivot(luTensor: TensorType, pivotsTensor: IndexTensorType): Triple diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index e0abc49b7..d090ce79c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -11,7 +11,7 @@ public class DoubleLinearOpsTensorAlgebra : TODO("Not yet implemented") } - override fun DoubleTensor.lu(tol: Double): Pair { + override fun DoubleTensor.lu(): Pair { checkSquareMatrix(shape) @@ -138,7 +138,6 @@ public class DoubleLinearOpsTensorAlgebra : TODO("Not yet implemented") } - override fun DoubleTensor.svd(): Triple { TODO("Not yet implemented") } From 206bcfc909d56a859ec783a30cc75a8ade178786 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Wed, 24 Mar 2021 18:08:36 +0300 Subject: [PATCH 056/178] lu inv and det complete + tests --- .../kmath/tensors/LinearOpsTensorAlgebra.kt | 2 +- .../core/DoubleLinearOpsTensorAlgebra.kt | 79 +++++++++++++++++++ .../kmath/tensors/core/DoubleTensorAlgebra.kt | 35 +++++++- .../core/TestDoubleAnalyticTensorAlgebra.kt | 7 +- .../core/TestDoubleLinearOpsAlgebra.kt | 73 +++++++++++++++++ 5 files changed, 187 insertions(+), 9 deletions(-) create mode 100644 kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt index e412af7c6..f551d524a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt @@ -13,7 +13,7 @@ public interface LinearOpsTensorAlgebra, Inde //https://pytorch.org/docs/stable/linalg.html#torch.linalg.qr public fun TensorType.qr(): TensorType - //https://pytorch.org/docs/stable/generated/torch.lu.html + //htt ps://pytorch.org/docs/stable/generated/torch.lu.html public fun TensorType.lu(): Pair //https://pytorch.org/docs/stable/generated/torch.lu_unpack.html diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 7779ad029..c8c4c413f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -1,5 +1,8 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.nd.MutableStructure2D +import space.kscience.kmath.nd.Structure1D +import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.tensors.LinearOpsTensorAlgebra import kotlin.math.sqrt @@ -20,6 +23,8 @@ public class DoubleLinearOpsTensorAlgebra : val n = shape.size val m = shape.last() val pivotsShape = IntArray(n - 1) { i -> shape[i] } + pivotsShape[n - 2] = m + 1 + val pivotsTensor = IntTensor( pivotsShape, IntArray(pivotsShape.reduce(Int::times)) { 0 } @@ -54,6 +59,8 @@ public class DoubleLinearOpsTensorAlgebra : lu[maxInd, k] = tmp } + pivots[m] += 1 + } for (j in i + 1 until m) { @@ -146,6 +153,78 @@ public class DoubleLinearOpsTensorAlgebra : TODO("ANDREI") } + private fun luMatrixDet(lu: Structure2D, pivots: Structure1D): Double { + val m = lu.shape[0] + val sign = if((pivots[m] - m) % 2 == 0) 1.0 else -1.0 + var det = sign + for (i in 0 until m){ + det *= lu[i, i] + } + return det + } + + public fun DoubleTensor.detLU(): DoubleTensor { + val (luTensor, pivotsTensor) = this.lu() + val n = shape.size + + val detTensorShape = IntArray(n - 1) { i -> shape[i] } + detTensorShape[n - 2] = 1 + val resBuffer = DoubleArray(detTensorShape.reduce(Int::times)) { 0.0 } + + val detTensor = DoubleTensor( + detTensorShape, + resBuffer + ) + + luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).forEachIndexed { index, (luMatrix, pivots) -> + resBuffer[index] = luMatrixDet(luMatrix, pivots) + } + + return detTensor + } + + private fun luMatrixInv( + lu: Structure2D, + pivots: Structure1D, + invMatrix : MutableStructure2D + ): Unit { + val m = lu.shape[0] + + for (j in 0 until m) { + for (i in 0 until m) { + if (pivots[i] == j){ + invMatrix[i, j] = 1.0 + } + + for (k in 0 until i){ + invMatrix[i, j] -= lu[i, k] * invMatrix[k, j] + } + } + + for (i in m - 1 downTo 0) { + for (k in i + 1 until m) { + invMatrix[i, j] -= lu[i, k] * invMatrix[k, j] + } + invMatrix[i, j] /= lu[i, i] + } + } + } + + public fun DoubleTensor.invLU(): DoubleTensor { + val (luTensor, pivotsTensor) = this.lu() + val n = shape.size + val invTensor = luTensor.zeroesLike() + + for ( + (luP, invMatrix) in + luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).zip(invTensor.matrixSequence()) + ) { + val (lu, pivots) = luP + luMatrixInv(lu, pivots, invMatrix) + } + + return invTensor + } } public inline fun DoubleLinearOpsTensorAlgebra(block: DoubleLinearOpsTensorAlgebra.() -> R): R = diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index c67687a09..ff65ca027 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -1,5 +1,8 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.linear.Matrix +import space.kscience.kmath.nd.MutableStructure2D +import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.tensors.TensorPartialDivisionAlgebra import kotlin.math.abs @@ -262,7 +265,31 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra shape[i] } + detTensorShape[n - 1] = 1 + val resBuffer = DoubleArray(detTensorShape.reduce(Int::times)) { 0.0 } + + val detTensor = DoubleTensor( + detTensorShape, + resBuffer + ) + + this.matrixSequence().forEachIndexed{i, matrix -> + // todo need Matrix determinant algo + // todo resBuffer[i] = matrix.det() + } + + + return detTensor + + */ } override fun DoubleTensor.square(): DoubleTensor { @@ -294,7 +321,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra Boolean): Boolean { - if (!(this.shape contentEquals other.shape)){ + if (!(this.shape contentEquals other.shape)) { return false } return this.eq(other, eqFunction) @@ -303,10 +330,10 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra Boolean): Boolean { // todo broadcasting checking val n = this.linearStructure.size - if (n != other.linearStructure.size){ + if (n != other.linearStructure.size) { return false } - for (i in 0 until n){ + for (i in 0 until n) { if (!eqFunction(this.buffer[this.bufferStart + i], other.buffer[other.bufferStart + i])) { return false } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt index 8028ce175..4dcdb7848 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt @@ -3,7 +3,6 @@ package space.kscience.kmath.tensors.core import kotlin.math.abs import kotlin.math.exp import kotlin.test.Test -import kotlin.test.assertEquals import kotlin.test.assertTrue class TestDoubleAnalyticTensorAlgebra { @@ -16,9 +15,9 @@ class TestDoubleAnalyticTensorAlgebra { return this.map(transform).toDoubleArray() } - fun DoubleArray.deltaEqual(other: DoubleArray, delta: Double = 1e-5): Boolean { + fun DoubleArray.epsEqual(other: DoubleArray, eps: Double = 1e-5): Boolean { for ((elem1, elem2) in this.asSequence().zip(other.asSequence())) { - if (abs(elem1 - elem2) > delta) { + if (abs(elem1 - elem2) > eps) { return false } } @@ -29,7 +28,7 @@ class TestDoubleAnalyticTensorAlgebra { fun testExp() = DoubleAnalyticTensorAlgebra { tensor.exp().let { assertTrue { shape contentEquals it.shape } - assertTrue { buffer.fmap(::exp).deltaEqual(it.buffer.array())} + assertTrue { buffer.fmap(::exp).epsEqual(it.buffer.array())} } } } \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt new file mode 100644 index 000000000..2da79382f --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -0,0 +1,73 @@ +package space.kscience.kmath.tensors.core + +import kotlin.math.abs +import kotlin.math.exp +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class TestDoubleLinearOpsTensorAlgebra { + + private val eps = 1e-5 + + private fun Double.epsEqual(other: Double): Boolean { + return abs(this - other) < eps + } + + fun DoubleArray.epsEqual(other: DoubleArray, eps: Double = 1e-5): Boolean { + for ((elem1, elem2) in this.asSequence().zip(other.asSequence())) { + if (abs(elem1 - elem2) > eps) { + return false + } + } + return true + } + + @Test + fun testDetLU() = DoubleLinearOpsTensorAlgebra { + val tensor = fromArray( + intArrayOf(2, 2, 2), + doubleArrayOf( + 1.0, 3.0, + 1.0, 2.0, + 1.5, 1.0, + 10.0, 2.0 + ) + ) + + val expectedShape = intArrayOf(2, 1) + val expectedBuffer = doubleArrayOf( + -1.0, + -7.0 + ) + val detTensor = tensor.detLU() + + assertTrue { detTensor.shape contentEquals expectedShape } + assertTrue { detTensor.buffer.array().epsEqual(expectedBuffer) } + } + + @Test + fun testInvLU() = DoubleLinearOpsTensorAlgebra { + val tensor = fromArray( + intArrayOf(2, 2, 2), + doubleArrayOf( + 1.0, 0.0, + 0.0, 2.0, + 1.0, 1.0, + 1.0, 0.0 + ) + ) + + val expectedShape = intArrayOf(2, 2, 2) + val expectedBuffer = doubleArrayOf( + 1.0, 0.0, + 0.0, 0.5, + 0.0, 1.0, + 1.0, -1.0 + ) + + val invTensor = tensor.invLU() + assertTrue { invTensor.shape contentEquals expectedShape } + assertTrue { invTensor.buffer.array().epsEqual(expectedBuffer) } + } +} From ab8137000146c52f10b3213c960b03917a0ada4f Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Wed, 24 Mar 2021 18:42:41 +0300 Subject: [PATCH 057/178] fixes --- .../kmath/tensors/LinearOpsTensorAlgebra.kt | 2 +- .../core/DoubleLinearOpsTensorAlgebra.kt | 22 +++++++------------ 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt index f551d524a..e412af7c6 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt @@ -13,7 +13,7 @@ public interface LinearOpsTensorAlgebra, Inde //https://pytorch.org/docs/stable/linalg.html#torch.linalg.qr public fun TensorType.qr(): TensorType - //htt ps://pytorch.org/docs/stable/generated/torch.lu.html + //https://pytorch.org/docs/stable/generated/torch.lu.html public fun TensorType.lu(): Pair //https://pytorch.org/docs/stable/generated/torch.lu_unpack.html diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index c8c4c413f..0b9d824f0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -10,9 +10,9 @@ public class DoubleLinearOpsTensorAlgebra : LinearOpsTensorAlgebra, DoubleTensorAlgebra() { - override fun DoubleTensor.inv(): DoubleTensor { - TODO("ANDREI") - } + override fun DoubleTensor.inv(): DoubleTensor = invLU() + + override fun DoubleTensor.det(): DoubleTensor = detLU() override fun DoubleTensor.lu(): Pair { @@ -156,15 +156,11 @@ public class DoubleLinearOpsTensorAlgebra : private fun luMatrixDet(lu: Structure2D, pivots: Structure1D): Double { val m = lu.shape[0] val sign = if((pivots[m] - m) % 2 == 0) 1.0 else -1.0 - var det = sign - for (i in 0 until m){ - det *= lu[i, i] - } - return det + return (0 until m).asSequence().map { lu[it, it] }.fold(sign) { left, right -> left * right } } public fun DoubleTensor.detLU(): DoubleTensor { - val (luTensor, pivotsTensor) = this.lu() + val (luTensor, pivotsTensor) = lu() val n = shape.size val detTensorShape = IntArray(n - 1) { i -> shape[i] } @@ -211,14 +207,12 @@ public class DoubleLinearOpsTensorAlgebra : } public fun DoubleTensor.invLU(): DoubleTensor { - val (luTensor, pivotsTensor) = this.lu() + val (luTensor, pivotsTensor) = lu() val n = shape.size val invTensor = luTensor.zeroesLike() - for ( - (luP, invMatrix) in - luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).zip(invTensor.matrixSequence()) - ) { + val seq = luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).zip(invTensor.matrixSequence()) + for ((luP, invMatrix) in seq) { val (lu, pivots) = luP luMatrixInv(lu, pivots, invMatrix) } From a4aa4b80d27cecef092a1a411163e24ff70d08ec Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 24 Mar 2021 15:51:58 +0000 Subject: [PATCH 058/178] Updated API --- kmath-core/api/kmath-core.api | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index 70bec600d..295df69e3 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -2674,7 +2674,7 @@ public final class space/kscience/kmath/tensors/ComplexTensorStructure$DefaultIm public abstract interface class space/kscience/kmath/tensors/LinearOpsTensorAlgebra : space/kscience/kmath/tensors/TensorPartialDivisionAlgebra { public abstract fun cholesky (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun inv (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun lu (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lkotlin/Pair; + public abstract fun lu (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Pair; public abstract fun luPivot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; public abstract fun qr (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun svd (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; @@ -2884,10 +2884,14 @@ public final class space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebr public fun ()V public synthetic fun cholesky (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun cholesky (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun det (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public fun det (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public final fun detLU (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun inv (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun inv (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun lu (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lkotlin/Pair; - public fun lu (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lkotlin/Pair; + public final fun invLU (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun lu (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Pair; + public fun lu (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lkotlin/Pair; public synthetic fun luPivot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; public fun luPivot (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/IntTensor;)Lkotlin/Triple; public synthetic fun qr (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; From f70f60c0e8d5a3c830bc1ce577a63fa5ddfad290 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 24 Mar 2021 15:58:25 +0000 Subject: [PATCH 059/178] Moved det to LinearOps --- kmath-core/api/kmath-core.api | 4 +-- .../kmath/tensors/LinearOpsTensorAlgebra.kt | 3 ++ .../kscience/kmath/tensors/TensorAlgebra.kt | 3 -- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 28 ------------------- 4 files changed, 4 insertions(+), 34 deletions(-) diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index 295df69e3..502628920 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -2673,6 +2673,7 @@ public final class space/kscience/kmath/tensors/ComplexTensorStructure$DefaultIm public abstract interface class space/kscience/kmath/tensors/LinearOpsTensorAlgebra : space/kscience/kmath/tensors/TensorPartialDivisionAlgebra { public abstract fun cholesky (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun det (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun inv (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun lu (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Pair; public abstract fun luPivot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; @@ -2706,7 +2707,6 @@ public abstract interface class space/kscience/kmath/tensors/TensorAlgebra { public abstract fun copy (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun cumprod (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun cumsum (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun det (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun diagonalEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;III)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun dot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun eye (I)Lspace/kscience/kmath/nd/MutableStructureND; @@ -2958,8 +2958,6 @@ public class space/kscience/kmath/tensors/core/DoubleTensorAlgebra : space/kscie public fun cumprod (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun cumsum (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; public fun cumsum (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun det (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun det (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun diagonalEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;III)Lspace/kscience/kmath/nd/MutableStructureND; public fun diagonalEmbedding (Lspace/kscience/kmath/tensors/core/DoubleTensor;III)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun div (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt index e412af7c6..3d1625a50 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt @@ -4,6 +4,9 @@ package space.kscience.kmath.tensors public interface LinearOpsTensorAlgebra, IndexTensorType: TensorStructure> : TensorPartialDivisionAlgebra { + //https://pytorch.org/docs/stable/linalg.html#torch.linalg.det + public fun TensorType.det(): TensorType + //https://pytorch.org/docs/stable/linalg.html#torch.linalg.inv public fun TensorType.inv(): TensorType diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index e41b7546c..702dc15e2 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -52,9 +52,6 @@ public interface TensorAlgebra> { public fun TensorType.view(shape: IntArray): TensorType public fun TensorType.viewAs(other: TensorType): TensorType - //https://pytorch.org/docs/stable/linalg.html#torch.linalg.det - public fun TensorType.det(): TensorType - //https://pytorch.org/docs/stable/generated/torch.abs.html public fun TensorType.abs(): TensorType diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 3ac09c8c7..df4a32bd8 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -320,34 +320,6 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra shape[i] } - detTensorShape[n - 1] = 1 - val resBuffer = DoubleArray(detTensorShape.reduce(Int::times)) { 0.0 } - - val detTensor = DoubleTensor( - detTensorShape, - resBuffer - ) - - this.matrixSequence().forEachIndexed{i, matrix -> - // todo need Matrix determinant algo - // todo resBuffer[i] = matrix.det() - } - - - return detTensor - - */ - } - override fun DoubleTensor.square(): DoubleTensor { TODO("Not yet implemented") } From 94b5afa6c475c4595ecb602f3ac1b66938ab04e6 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 24 Mar 2021 18:39:40 +0000 Subject: [PATCH 060/178] eq moved to interface --- .../kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt | 4 ++++ .../space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index 702dc15e2..37c6a34f8 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -1,5 +1,7 @@ package space.kscience.kmath.tensors +import space.kscience.kmath.tensors.core.DoubleTensor + // https://proofwiki.org/wiki/Definition:Algebra_over_Ring public interface TensorAlgebra> { @@ -52,6 +54,8 @@ public interface TensorAlgebra> { public fun TensorType.view(shape: IntArray): TensorType public fun TensorType.viewAs(other: TensorType): TensorType + public fun TensorType.eq(other: TensorType, delta: T): Boolean + //https://pytorch.org/docs/stable/generated/torch.abs.html public fun TensorType.abs(): TensorType diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index df4a32bd8..0c82ec9c8 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -344,10 +344,12 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra abs(x - y) < delta } } - public fun DoubleTensor.eq(other: DoubleTensor, delta: Double = 1e-5): Boolean { + override fun DoubleTensor.eq(other: DoubleTensor, delta: Double): Boolean { return this.eq(other) { x, y -> abs(x - y) < delta } } + public fun DoubleTensor.eq(other: DoubleTensor): Boolean = this.eq(other, 1e-5) + public fun DoubleTensor.contentEquals(other: DoubleTensor, eqFunction: (Double, Double) -> Boolean): Boolean { if (!(this.shape contentEquals other.shape)) { return false From daa077718299839d80256ef1705cb48f31d36c9f Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 24 Mar 2021 18:43:03 +0000 Subject: [PATCH 061/178] removed unused code --- .../kscience/kmath/tensors/core/checks.kt | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt index ec7a123a9..c644a295c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -34,26 +34,6 @@ internal inline fun , } -internal inline fun , - TorchTensorAlgebraType : TensorAlgebra> - TorchTensorAlgebraType.checkDot(a: TensorType, b: TensorType): Unit { - val sa = a.shape - val sb = b.shape - val na = sa.size - val nb = sb.size - var status: Boolean - if (nb == 1) { - status = sa.last() == sb[0] - } else { - status = sa.last() == sb[nb - 2] - if ((na > 2) and (nb > 2)) { - status = status and - (sa.take(nb - 2).toIntArray() contentEquals sb.take(nb - 2).toIntArray()) - } - } - check(status) { "Incompatible shapes ${sa.toList()} and ${sb.toList()} provided for dot product" } -} - internal inline fun , TorchTensorAlgebraType : TensorAlgebra> TorchTensorAlgebraType.checkTranspose(dim: Int, i: Int, j: Int): Unit = From 1056fc7200b5fbbb03b75c66ca09c30483f12e5c Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 26 Mar 2021 13:48:59 +0000 Subject: [PATCH 062/178] Test for scalar product --- .../kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 2da79382f..d77f33f9d 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -70,4 +70,14 @@ class TestDoubleLinearOpsTensorAlgebra { assertTrue { invTensor.shape contentEquals expectedShape } assertTrue { invTensor.buffer.array().epsEqual(expectedBuffer) } } + + @Test + fun testScalarProduct() = DoubleLinearOpsTensorAlgebra { + val a = fromArray(intArrayOf(3), doubleArrayOf(1.8,2.5, 6.8)) + val b = fromArray(intArrayOf(3), doubleArrayOf(5.5,2.6, 6.4)) + DoubleReduceOpsTensorAlgebra { + assertEquals(a.dot(b).value(), 59.92) + } + + } } From 9162867fc28a4e948b0a520c67fca6cdf20ce53e Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 26 Mar 2021 14:37:27 +0000 Subject: [PATCH 063/178] Mutable structures 2D functionality added --- kmath-core/api/kmath-core.api | 17 ++++++++++++-- .../kscience/kmath/linear/LinearSpace.kt | 1 + .../space/kscience/kmath/nd/Structure2D.kt | 14 ++++++++++++ .../space/kscience/kmath/structures/Buffer.kt | 22 +++++++++++++++---- .../tensors/TensorPartialDivisionAlgebra.kt | 4 ++-- 5 files changed, 50 insertions(+), 8 deletions(-) diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index 502628920..a109aaab5 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -984,6 +984,8 @@ public final class space/kscience/kmath/nd/MutableStructure1D$DefaultImpls { } public abstract interface class space/kscience/kmath/nd/MutableStructure2D : space/kscience/kmath/nd/MutableStructureND, space/kscience/kmath/nd/Structure2D { + public abstract fun getColumns ()Ljava/util/List; + public abstract fun getRows ()Ljava/util/List; public abstract fun set (IILjava/lang/Object;)V } @@ -2608,6 +2610,15 @@ public final class space/kscience/kmath/structures/VirtualBuffer : space/kscienc public fun iterator ()Ljava/util/Iterator; } +public final class space/kscience/kmath/structures/VirtualMutableBuffer : space/kscience/kmath/structures/MutableBuffer { + public fun (ILkotlin/jvm/functions/Function1;)V + public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; + public fun get (I)Ljava/lang/Object; + public fun getSize ()I + public fun iterator ()Ljava/util/Iterator; + public fun set (ILjava/lang/Object;)V +} + public abstract interface class space/kscience/kmath/tensors/AnalyticTensorAlgebra : space/kscience/kmath/tensors/OrderedTensorAlgebra, space/kscience/kmath/tensors/TensorPartialDivisionAlgebra { public abstract fun acos (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun acosh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; @@ -2709,6 +2720,7 @@ public abstract interface class space/kscience/kmath/tensors/TensorAlgebra { public abstract fun cumsum (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun diagonalEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;III)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun dot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun eq (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Z public abstract fun eye (I)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun flatten (Lspace/kscience/kmath/nd/MutableStructureND;II)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun full (Ljava/lang/Object;[I)Lspace/kscience/kmath/nd/MutableStructureND; @@ -2970,9 +2982,10 @@ public class space/kscience/kmath/tensors/core/DoubleTensorAlgebra : space/kscie public fun divAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V public synthetic fun dot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun dot (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public final fun eq (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Z + public synthetic fun eq (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Z + public final fun eq (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Z + public fun eq (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Z public final fun eq (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lkotlin/jvm/functions/Function2;)Z - public static synthetic fun eq$default (Lspace/kscience/kmath/tensors/core/DoubleTensorAlgebra;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;DILjava/lang/Object;)Z public synthetic fun eye (I)Lspace/kscience/kmath/nd/MutableStructureND; public fun eye (I)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun flatten (Lspace/kscience/kmath/nd/MutableStructureND;II)Lspace/kscience/kmath/nd/MutableStructureND; diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt index 6a587270b..4f2afc6fa 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt @@ -14,6 +14,7 @@ import kotlin.reflect.KClass * @param T the type of items. */ public typealias Matrix = Structure2D +public typealias MutableMatrix = MutableStructure2D /** * Alias or using [Buffer] as a point/vector in a many-dimensional space. diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt index d49438b2c..762b59b28 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt @@ -2,7 +2,9 @@ package space.kscience.kmath.nd import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.VirtualBuffer +import space.kscience.kmath.structures.VirtualMutableBuffer import kotlin.reflect.KClass /** @@ -69,6 +71,18 @@ public interface MutableStructure2D : Structure2D, MutableStructureND { * @param value the value. */ public operator fun set(i: Int, j: Int, value: T) + + /** + * The buffer of rows of this structure. It gets elements from the structure dynamically. + */ + override val rows: List> + get() = List(rowNum) { i -> VirtualMutableBuffer(colNum) { j -> get(i, j) } } + + /** + * The buffer of columns of this structure. It gets elements from the structure dynamically. + */ + override val columns: List> + get() = List(colNum) { j -> VirtualMutableBuffer(rowNum) { i -> get(i, j) } } } /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt index c85c6c5e3..72a6e3cae 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt @@ -223,11 +223,7 @@ public inline class MutableListBuffer(public val list: MutableList) : Muta } /** -<<<<<<< HEAD * Returns an [MutableListBuffer] that wraps the original list. -======= - * Returns an [ListBuffer] that wraps the original list. ->>>>>>> dev */ public fun MutableList.asMutableBuffer(): MutableListBuffer = MutableListBuffer(this) @@ -286,6 +282,24 @@ public class VirtualBuffer(override val size: Int, private val generator: (In override operator fun iterator(): Iterator = (0 until size).asSequence().map(generator).iterator() } +public class VirtualMutableBuffer(override val size: Int, private val generator: (Int) -> T) : MutableBuffer { + + private val bufferHolder: MutableListBuffer = (0 until size).map(generator).toMutableList().asMutableBuffer() + + override operator fun get(index: Int): T { + if (index < 0 || index >= size) throw IndexOutOfBoundsException("Expected index from 0 to ${size - 1}, but found $index") + return bufferHolder[index] + } + + override operator fun iterator(): Iterator = bufferHolder.iterator() + + override fun set(index: Int, value: T) { + bufferHolder[index] = value + } + + override fun copy(): MutableBuffer = bufferHolder.copy() +} + /** * Convert this buffer to read-only buffer. */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt index 9f70f9621..54417e842 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt @@ -9,8 +9,8 @@ public interface TensorPartialDivisionAlgebra public operator fun TensorType.divAssign(other: TensorType) //https://pytorch.org/docs/stable/generated/torch.mean.html#torch.mean - public fun TensorType.mean(dim: Int, keepDim: Boolean): TensorType + public fun TensorType.mean(dim: Int = 0, keepDim: Boolean = false): TensorType //https://pytorch.org/docs/stable/generated/torch.var.html#torch.var - public fun TensorType.variance(dim: Int, unbiased: Boolean, keepDim: Boolean): TensorType + public fun TensorType.variance(dim: Int = 0, unbiased: Boolean = true, keepDim: Boolean = false): TensorType } From 1f19ac88aee34ed5b790356a81f762b21c1752f3 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Fri, 26 Mar 2021 17:43:08 +0300 Subject: [PATCH 064/178] qr fix --- .../kmath/tensors/LinearOpsTensorAlgebra.kt | 2 +- .../tensors/core/DoubleLinearOpsTensorAlgebra.kt | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt index 3d1625a50..d980c510f 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt @@ -14,7 +14,7 @@ public interface LinearOpsTensorAlgebra, Inde public fun TensorType.cholesky(): TensorType //https://pytorch.org/docs/stable/linalg.html#torch.linalg.qr - public fun TensorType.qr(): TensorType + public fun TensorType.qr(): Pair //https://pytorch.org/docs/stable/generated/torch.lu.html public fun TensorType.lu(): Pair diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 0b9d824f0..d49fc941a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -1,8 +1,10 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.linear.Matrix import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.Structure1D import space.kscience.kmath.nd.Structure2D +import space.kscience.kmath.nd.asND import space.kscience.kmath.tensors.LinearOpsTensorAlgebra import kotlin.math.sqrt @@ -141,7 +143,15 @@ public class DoubleLinearOpsTensorAlgebra : return lTensor } - override fun DoubleTensor.qr(): DoubleTensor { + private fun matrixQR( + matrix: Structure2D, + q: MutableStructure2D, + r: MutableStructure2D + ) { + + } + + override fun DoubleTensor.qr(): Pair { TODO("ANDREI") } @@ -154,6 +164,7 @@ public class DoubleLinearOpsTensorAlgebra : } private fun luMatrixDet(lu: Structure2D, pivots: Structure1D): Double { + // todo check val m = lu.shape[0] val sign = if((pivots[m] - m) % 2 == 0) 1.0 else -1.0 return (0 until m).asSequence().map { lu[it, it] }.fold(sign) { left, right -> left * right } @@ -184,6 +195,7 @@ public class DoubleLinearOpsTensorAlgebra : pivots: Structure1D, invMatrix : MutableStructure2D ): Unit { + //todo check val m = lu.shape[0] for (j in 0 until m) { From a6354623ec08bb0c66d1e2a45eacde3b08e29c57 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 26 Mar 2021 15:06:05 +0000 Subject: [PATCH 065/178] returning cols/rows as vectors --- kmath-core/api/kmath-core.api | 5 +++++ .../kotlin/space/kscience/kmath/nd/Structure1D.kt | 15 +++++++++++++++ .../kotlin/space/kscience/kmath/nd/Structure2D.kt | 8 ++++---- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index a109aaab5..0a3e3721d 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -2768,6 +2768,11 @@ public abstract interface class space/kscience/kmath/tensors/TensorPartialDivisi public abstract fun variance (Lspace/kscience/kmath/nd/MutableStructureND;IZZ)Lspace/kscience/kmath/nd/MutableStructureND; } +public final class space/kscience/kmath/tensors/TensorPartialDivisionAlgebra$DefaultImpls { + public static synthetic fun mean$default (Lspace/kscience/kmath/tensors/TensorPartialDivisionAlgebra;Lspace/kscience/kmath/nd/MutableStructureND;IZILjava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; + public static synthetic fun variance$default (Lspace/kscience/kmath/tensors/TensorPartialDivisionAlgebra;Lspace/kscience/kmath/nd/MutableStructureND;IZZILjava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; +} + public final class space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra : space/kscience/kmath/tensors/core/DoubleTensorAlgebra { public fun ()V public synthetic fun div (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt index c157f9a2f..354f3d802 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt @@ -71,6 +71,21 @@ private inline class Buffer1DWrapper(val buffer: Buffer) : Structure1D override operator fun get(index: Int): T = buffer[index] } +internal inline class MutableBuffer1DWrapper(val buffer: MutableBuffer) : MutableStructure1D { + override val shape: IntArray get() = intArrayOf(buffer.size) + override val size: Int get() = buffer.size + + override fun elements(): Sequence> = + buffer.asSequence().mapIndexed { index, value -> intArrayOf(index) to value } + + override operator fun get(index: Int): T = buffer[index] + override fun set(index: Int, value: T) { + buffer[index] = value + } + + override fun copy(): MutableBuffer = buffer.copy() +} + /** * Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt index 762b59b28..e1a1d37de 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt @@ -75,14 +75,14 @@ public interface MutableStructure2D : Structure2D, MutableStructureND { /** * The buffer of rows of this structure. It gets elements from the structure dynamically. */ - override val rows: List> - get() = List(rowNum) { i -> VirtualMutableBuffer(colNum) { j -> get(i, j) } } + override val rows: List> + get() = List(rowNum) { i -> MutableBuffer1DWrapper(VirtualMutableBuffer(colNum) { j -> get(i, j) })} /** * The buffer of columns of this structure. It gets elements from the structure dynamically. */ - override val columns: List> - get() = List(colNum) { j -> VirtualMutableBuffer(rowNum) { i -> get(i, j) } } + override val columns: List> + get() = List(colNum) { j -> MutableBuffer1DWrapper(VirtualMutableBuffer(rowNum) { i -> get(i, j) }) } } /** From 1588b5d94ff751fdf2d1d91686173068430723cd Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 26 Mar 2021 15:09:18 +0000 Subject: [PATCH 066/178] once mutable stay it and enjoy --- .../kotlin/space/kscience/kmath/nd/Structure2D.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt index e1a1d37de..8e41110fe 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt @@ -75,14 +75,14 @@ public interface MutableStructure2D : Structure2D, MutableStructureND { /** * The buffer of rows of this structure. It gets elements from the structure dynamically. */ - override val rows: List> - get() = List(rowNum) { i -> MutableBuffer1DWrapper(VirtualMutableBuffer(colNum) { j -> get(i, j) })} + override val rows: MutableList> + get() = MutableList(rowNum) { i -> MutableBuffer1DWrapper(VirtualMutableBuffer(colNum) { j -> get(i, j) })} /** * The buffer of columns of this structure. It gets elements from the structure dynamically. */ - override val columns: List> - get() = List(colNum) { j -> MutableBuffer1DWrapper(VirtualMutableBuffer(rowNum) { i -> get(i, j) }) } + override val columns: MutableList> + get() = MutableList(colNum) { j -> MutableBuffer1DWrapper(VirtualMutableBuffer(rowNum) { i -> get(i, j) }) } } /** From e03910354e5ba02b6ec5551357ba629fa8cd8cca Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 26 Mar 2021 15:14:23 +0000 Subject: [PATCH 067/178] ok reverting --- .../kotlin/space/kscience/kmath/nd/Structure2D.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt index 8e41110fe..e1a1d37de 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt @@ -75,14 +75,14 @@ public interface MutableStructure2D : Structure2D, MutableStructureND { /** * The buffer of rows of this structure. It gets elements from the structure dynamically. */ - override val rows: MutableList> - get() = MutableList(rowNum) { i -> MutableBuffer1DWrapper(VirtualMutableBuffer(colNum) { j -> get(i, j) })} + override val rows: List> + get() = List(rowNum) { i -> MutableBuffer1DWrapper(VirtualMutableBuffer(colNum) { j -> get(i, j) })} /** * The buffer of columns of this structure. It gets elements from the structure dynamically. */ - override val columns: MutableList> - get() = MutableList(colNum) { j -> MutableBuffer1DWrapper(VirtualMutableBuffer(rowNum) { i -> get(i, j) }) } + override val columns: List> + get() = List(colNum) { j -> MutableBuffer1DWrapper(VirtualMutableBuffer(rowNum) { i -> get(i, j) }) } } /** From 516cd90677700d3f49096194bffa2cfd17ea78eb Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 26 Mar 2021 15:36:53 +0000 Subject: [PATCH 068/178] Moved out to archive unimplemented API --- kmath-core/api/kmath-core.api | 160 +----------------- .../kmath/tensors/AnalyticTensorAlgebra.kt | 63 +------ .../kmath/tensors/ComplexTensorAlgebra.kt | 53 ------ .../kmath/tensors/ComplexTensorStructure.kt | 14 -- .../kmath/tensors/OrderedTensorAlgebra.kt | 29 ---- .../kscience/kmath/tensors/TensorAlgebra.kt | 26 --- .../tensors/TensorPartialDivisionAlgebra.kt | 6 - .../core/DoubleAnalyticTensorAlgebra.kt | 83 +-------- .../core/DoubleOrderedTensorAlgebra.kt | 43 ----- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 43 ----- 10 files changed, 4 insertions(+), 516 deletions(-) delete mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt delete mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorStructure.kt delete mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/OrderedTensorAlgebra.kt delete mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleOrderedTensorAlgebra.kt diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index 0a3e3721d..a45f00a55 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -2619,7 +2619,7 @@ public final class space/kscience/kmath/structures/VirtualMutableBuffer : space/ public fun set (ILjava/lang/Object;)V } -public abstract interface class space/kscience/kmath/tensors/AnalyticTensorAlgebra : space/kscience/kmath/tensors/OrderedTensorAlgebra, space/kscience/kmath/tensors/TensorPartialDivisionAlgebra { +public abstract interface class space/kscience/kmath/tensors/AnalyticTensorAlgebra : space/kscience/kmath/tensors/TensorPartialDivisionAlgebra { public abstract fun acos (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun acosh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun asin (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; @@ -2627,59 +2627,16 @@ public abstract interface class space/kscience/kmath/tensors/AnalyticTensorAlgeb public abstract fun atan (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun atanh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun ceil (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun clamp (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun cos (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun cosh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun erf (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun erfc (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun erfinv (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun exp (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun floor (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun heaviside (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun histc (Lspace/kscience/kmath/nd/MutableStructureND;ILjava/lang/Object;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun igamma (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun igammac (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun lerp (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun lgamma (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun log (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun logit (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun mvlgamma (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun polygamma (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun pow (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun quantile (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;IZ)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun round (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun sigmoid (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun sin (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun sinc (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun sinh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun sqrt (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun std (Lspace/kscience/kmath/nd/MutableStructureND;IZZ)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun tan (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun tanh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun trapz (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; -} - -public abstract interface class space/kscience/kmath/tensors/ComplexTensorAlgebra : space/kscience/kmath/tensors/TensorPartialDivisionAlgebra { - public abstract fun angle (Lspace/kscience/kmath/tensors/ComplexTensorStructure;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun bartlettWindow (IZ)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun blackmanWindow (IZ)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun cartesianEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/tensors/ComplexTensorStructure; - public abstract fun hammingWindow (IZLjava/lang/Object;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun inverseShortTimeFourierTransform (Lspace/kscience/kmath/tensors/ComplexTensorStructure;IIILspace/kscience/kmath/nd/MutableStructureND;ZZZI)V - public abstract fun kaiserWindow (IZLjava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun polarEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/tensors/ComplexTensorStructure; - public abstract fun shortTimeFourierTransform (Lspace/kscience/kmath/tensors/ComplexTensorStructure;IIILspace/kscience/kmath/nd/MutableStructureND;ZZ)V - public abstract fun viewAsComplex (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/tensors/ComplexTensorStructure; -} - -public abstract interface class space/kscience/kmath/tensors/ComplexTensorStructure : space/kscience/kmath/nd/MutableStructureND { - public abstract fun imaginaryPart ()Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun realPart ()Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun viewAsReal ()Lspace/kscience/kmath/nd/MutableStructureND; -} - -public final class space/kscience/kmath/tensors/ComplexTensorStructure$DefaultImpls { - public static fun getDimension (Lspace/kscience/kmath/tensors/ComplexTensorStructure;)I } public abstract interface class space/kscience/kmath/tensors/LinearOpsTensorAlgebra : space/kscience/kmath/tensors/TensorPartialDivisionAlgebra { @@ -2697,32 +2654,16 @@ public final class space/kscience/kmath/tensors/LinearOpsTensorAlgebra$DefaultIm public static synthetic fun symEig$default (Lspace/kscience/kmath/tensors/LinearOpsTensorAlgebra;Lspace/kscience/kmath/nd/MutableStructureND;ZILjava/lang/Object;)Lkotlin/Pair; } -public abstract interface class space/kscience/kmath/tensors/OrderedTensorAlgebra : space/kscience/kmath/tensors/TensorAlgebra { - public abstract fun cummax (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun cummin (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun max (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun maximum (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public abstract fun median (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun min (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun minimum (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public abstract fun sort (Lspace/kscience/kmath/nd/MutableStructureND;IZZ)Lspace/kscience/kmath/nd/MutableStructureND; -} - public abstract interface class space/kscience/kmath/tensors/ReduceOpsTensorAlgebra : space/kscience/kmath/tensors/TensorAlgebra { public abstract fun value (Lspace/kscience/kmath/nd/MutableStructureND;)Ljava/lang/Object; } public abstract interface class space/kscience/kmath/tensors/TensorAlgebra { - public abstract fun abs (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun cat (Ljava/util/List;I)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun copy (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun cumprod (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun cumsum (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun diagonalEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;III)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun dot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun eq (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Z public abstract fun eye (I)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun flatten (Lspace/kscience/kmath/nd/MutableStructureND;II)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun full (Ljava/lang/Object;[I)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun fullLike (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun get (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; @@ -2738,10 +2679,6 @@ public abstract interface class space/kscience/kmath/tensors/TensorAlgebra { public abstract fun plus (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V public abstract fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public abstract fun prod (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun square (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun squeeze (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun sum (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun times (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun times (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun times (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; @@ -2764,13 +2701,6 @@ public abstract interface class space/kscience/kmath/tensors/TensorPartialDivisi public abstract fun div (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun divAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V public abstract fun divAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public abstract fun mean (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun variance (Lspace/kscience/kmath/nd/MutableStructureND;IZZ)Lspace/kscience/kmath/nd/MutableStructureND; -} - -public final class space/kscience/kmath/tensors/TensorPartialDivisionAlgebra$DefaultImpls { - public static synthetic fun mean$default (Lspace/kscience/kmath/tensors/TensorPartialDivisionAlgebra;Lspace/kscience/kmath/nd/MutableStructureND;IZILjava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public static synthetic fun variance$default (Lspace/kscience/kmath/tensors/TensorPartialDivisionAlgebra;Lspace/kscience/kmath/nd/MutableStructureND;IZZILjava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; } public final class space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra : space/kscience/kmath/tensors/core/DoubleTensorAlgebra { @@ -2815,7 +2745,7 @@ public class space/kscience/kmath/tensors/core/BufferedTensor : space/kscience/k public final fun vectorSequence ()Lkotlin/sequences/Sequence; } -public final class space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra : space/kscience/kmath/tensors/core/DoubleOrderedTensorAlgebra, space/kscience/kmath/tensors/AnalyticTensorAlgebra { +public final class space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra : space/kscience/kmath/tensors/core/DoubleTensorAlgebra, space/kscience/kmath/tensors/AnalyticTensorAlgebra { public fun ()V public synthetic fun acos (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun acos (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; @@ -2831,66 +2761,26 @@ public final class space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra public fun atanh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun ceil (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun ceil (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun clamp (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun clamp (Lspace/kscience/kmath/tensors/core/DoubleTensor;DD)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun cos (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun cos (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun cosh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun cosh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun erf (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun erf (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun erfc (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun erfc (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun erfinv (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun erfinv (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun exp (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun exp (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun floor (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun floor (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun heaviside (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun heaviside (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun histc (Lspace/kscience/kmath/nd/MutableStructureND;ILjava/lang/Object;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun histc (Lspace/kscience/kmath/tensors/core/DoubleTensor;IDD)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun igamma (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun igamma (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun igammac (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun igammac (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun lerp (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun lerp (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun lgamma (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun lgamma (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun log (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun log (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun logit (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun logit (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun mvlgamma (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public fun mvlgamma (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun polygamma (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public fun polygamma (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun pow (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun pow (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun quantile (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;IZ)Lspace/kscience/kmath/nd/MutableStructureND; - public fun quantile (Lspace/kscience/kmath/tensors/core/DoubleTensor;DIZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun round (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun round (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun sigmoid (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun sigmoid (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun sin (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun sin (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun sinc (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun sinc (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun sinh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun sinh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun sqrt (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun sqrt (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun std (Lspace/kscience/kmath/nd/MutableStructureND;IZZ)Lspace/kscience/kmath/nd/MutableStructureND; - public fun std (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun tan (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun tan (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun tanh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun tanh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun trapz (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public fun trapz (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; } public final class space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebraKt { @@ -2923,30 +2813,6 @@ public final class space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebr public static final fun DoubleLinearOpsTensorAlgebra (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; } -public class space/kscience/kmath/tensors/core/DoubleOrderedTensorAlgebra : space/kscience/kmath/tensors/core/DoubleTensorAlgebra, space/kscience/kmath/tensors/OrderedTensorAlgebra { - public fun ()V - public synthetic fun cummax (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public fun cummax (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun cummin (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public fun cummin (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun max (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; - public fun max (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun maximum (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public fun maximum (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V - public synthetic fun median (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; - public fun median (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun min (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; - public fun min (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun minimum (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public fun minimum (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V - public synthetic fun sort (Lspace/kscience/kmath/nd/MutableStructureND;IZZ)Lspace/kscience/kmath/nd/MutableStructureND; - public fun sort (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; -} - -public final class space/kscience/kmath/tensors/core/DoubleOrderedTensorAlgebraKt { - public static final fun DoubleOrderedTensorAlgebra (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; -} - public final class space/kscience/kmath/tensors/core/DoubleReduceOpsTensorAlgebra : space/kscience/kmath/tensors/core/DoubleTensorAlgebra, space/kscience/kmath/tensors/ReduceOpsTensorAlgebra { public fun ()V public synthetic fun value (Lspace/kscience/kmath/nd/MutableStructureND;)Ljava/lang/Object; @@ -2962,19 +2828,11 @@ public final class space/kscience/kmath/tensors/core/DoubleTensor : space/kscien public class space/kscience/kmath/tensors/core/DoubleTensorAlgebra : space/kscience/kmath/tensors/TensorPartialDivisionAlgebra { public fun ()V - public synthetic fun abs (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun abs (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun cat (Ljava/util/List;I)Lspace/kscience/kmath/nd/MutableStructureND; - public fun cat (Ljava/util/List;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; public final fun contentEquals (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Z public final fun contentEquals (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lkotlin/jvm/functions/Function2;)Z public static synthetic fun contentEquals$default (Lspace/kscience/kmath/tensors/core/DoubleTensorAlgebra;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;DILjava/lang/Object;)Z public synthetic fun copy (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun copy (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun cumprod (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public fun cumprod (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun cumsum (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public fun cumsum (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun diagonalEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;III)Lspace/kscience/kmath/nd/MutableStructureND; public fun diagonalEmbedding (Lspace/kscience/kmath/tensors/core/DoubleTensor;III)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun div (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; @@ -2993,8 +2851,6 @@ public class space/kscience/kmath/tensors/core/DoubleTensorAlgebra : space/kscie public final fun eq (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lkotlin/jvm/functions/Function2;)Z public synthetic fun eye (I)Lspace/kscience/kmath/nd/MutableStructureND; public fun eye (I)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun flatten (Lspace/kscience/kmath/nd/MutableStructureND;II)Lspace/kscience/kmath/nd/MutableStructureND; - public fun flatten (Lspace/kscience/kmath/tensors/core/DoubleTensor;II)Lspace/kscience/kmath/tensors/core/DoubleTensor; public final fun fromArray ([I[D)Lspace/kscience/kmath/tensors/core/DoubleTensor; public fun full (D[I)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun full (Ljava/lang/Object;[I)Lspace/kscience/kmath/nd/MutableStructureND; @@ -3003,8 +2859,6 @@ public class space/kscience/kmath/tensors/core/DoubleTensorAlgebra : space/kscie public synthetic fun get (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; public fun get (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; public final fun map (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun mean (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; - public fun mean (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; public fun minus (DLspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public synthetic fun minus (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; @@ -3029,14 +2883,6 @@ public class space/kscience/kmath/tensors/core/DoubleTensorAlgebra : space/kscie public synthetic fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V public fun plusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)V public fun plusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V - public synthetic fun prod (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; - public fun prod (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun square (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun square (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun squeeze (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public fun squeeze (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun sum (Lspace/kscience/kmath/nd/MutableStructureND;IZ)Lspace/kscience/kmath/nd/MutableStructureND; - public fun sum (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; public fun times (DLspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun times (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public synthetic fun times (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; @@ -3051,8 +2897,6 @@ public class space/kscience/kmath/tensors/core/DoubleTensorAlgebra : space/kscie public fun transpose (Lspace/kscience/kmath/tensors/core/DoubleTensor;II)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun unaryMinus (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun unaryMinus (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun variance (Lspace/kscience/kmath/nd/MutableStructureND;IZZ)Lspace/kscience/kmath/nd/MutableStructureND; - public fun variance (Lspace/kscience/kmath/tensors/core/DoubleTensor;IZZ)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun view (Lspace/kscience/kmath/nd/MutableStructureND;[I)Lspace/kscience/kmath/nd/MutableStructureND; public fun view (Lspace/kscience/kmath/tensors/core/DoubleTensor;[I)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun viewAs (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt index c3a558298..fa1de81fa 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt @@ -2,14 +2,7 @@ package space.kscience.kmath.tensors public interface AnalyticTensorAlgebra> : - TensorPartialDivisionAlgebra, - OrderedTensorAlgebra{ - - //https://pytorch.org/docs/stable/generated/torch.quantile.html#torch.quantile - public fun TensorType.quantile(q: T, dim: Int, keepDim: Boolean): TensorType - - //https://pytorch.org/docs/stable/generated/torch.std.html#torch.std - public fun TensorType.std(dim: Int, unbiased: Boolean, keepDim: Boolean): TensorType + TensorPartialDivisionAlgebra { //https://pytorch.org/docs/stable/generated/torch.exp.html public fun TensorType.exp(): TensorType @@ -62,58 +55,4 @@ public interface AnalyticTensorAlgebra> : //https://pytorch.org/docs/stable/generated/torch.floor.html#torch.floor public fun TensorType.floor(): TensorType - //https://pytorch.org/docs/stable/generated/torch.clamp.html#torch.clamp - public fun TensorType.clamp(min: T, max: T): TensorType - - //https://pytorch.org/docs/stable/generated/torch.erf.html#torch.erf - public fun TensorType.erf(): TensorType - - //https://pytorch.org/docs/stable/generated/torch.erfinv.html#torch.erfinv - public fun TensorType.erfinv(): TensorType - - //https://pytorch.org/docs/stable/generated/torch.erfc.html#torch.erfc - public fun TensorType.erfc(): TensorType - - //https://pytorch.org/docs/stable/generated/torch.lerp.html#torch.lerp - public fun TensorType.lerp(end: TensorType, weight: TensorType): TensorType - - //https://pytorch.org/docs/stable/generated/torch.lgamma.html#torch.lgamma - public fun TensorType.lgamma(): TensorType - - //https://pytorch.org/docs/stable/generated/torch.logit.html#torch.logit - public fun TensorType.logit(eps: T): TensorType - - //https://pytorch.org/docs/stable/generated/torch.igamma.html#torch.igamma - public fun TensorType.igamma(other: TensorType): TensorType - - //https://pytorch.org/docs/stable/generated/torch.igammac.html#torch.igammac - public fun TensorType.igammac(other: TensorType): TensorType - - //https://pytorch.org/docs/stable/generated/torch.mvlgamma.html#torch.mvlgamma - public fun TensorType.mvlgamma(dimensions: Int): TensorType - - //https://pytorch.org/docs/stable/generated/torch.polygamma.html#torch.polygamma - public fun TensorType.polygamma(order: Int): TensorType - - //https://pytorch.org/docs/stable/generated/torch.pow.html#torch.pow - public fun TensorType.pow(exponent: T): TensorType - - //https://pytorch.org/docs/stable/generated/torch.round.html#torch.round - public fun TensorType.round(): TensorType - - //https://pytorch.org/docs/stable/generated/torch.sigmoid.html#torch.sigmoid - public fun TensorType.sigmoid(): TensorType - - //https://pytorch.org/docs/stable/generated/torch.sinc.html#torch.sinc - public fun TensorType.sinc(): TensorType - - //https://pytorch.org/docs/stable/generated/torch.heaviside.html#torch.heaviside - public fun TensorType.heaviside(values: TensorType): TensorType - - //https://pytorch.org/docs/stable/generated/torch.trapz.html#torch.trapz - public fun TensorType.trapz(xValues: TensorType, dim: Int): TensorType - - //https://pytorch.org/docs/stable/generated/torch.histc.html#torch.histc - public fun TensorType.histc(bins: Int, min: T, max: T): TensorType - } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt deleted file mode 100644 index e56920916..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorAlgebra.kt +++ /dev/null @@ -1,53 +0,0 @@ -package space.kscience.kmath.tensors - -public interface ComplexTensorAlgebra, - ComplexTensorType : ComplexTensorStructure> - : TensorPartialDivisionAlgebra{ - - //https://pytorch.org/docs/stable/generated/torch.view_as_complex.html - public fun RealTensorType.viewAsComplex(): ComplexTensorType - - // Embed a real tensor as real + i * imaginary - public fun RealTensorType.cartesianEmbedding(imaginary: RealTensorType): ComplexTensorType - - // Embed a real tensor as real * exp(i * angle) - public fun RealTensorType.polarEmbedding(angle: RealTensorType): ComplexTensorType - - //https://pytorch.org/docs/stable/generated/torch.angle.html - public fun ComplexTensorType.angle(): RealTensorType - - //https://pytorch.org/docs/stable/generated/torch.stft.html#torch.stft - public fun ComplexTensorType.shortTimeFourierTransform( - nFFT: Int, - hopLength: Int, - winLength: Int, - window: RealTensorType, - normalised: Boolean, - oneSided: Boolean - ) - - //https://pytorch.org/docs/stable/generated/torch.istft.html#torch.istft - public fun ComplexTensorType.inverseShortTimeFourierTransform( - nFFT: Int, - hopLength: Int, - winLength: Int, - window: RealTensorType, - center: Boolean, - normalised: Boolean, - oneSided: Boolean, - length: Int - ) - - //https://pytorch.org/docs/stable/generated/torch.bartlett_window.html#torch.bartlett_window - public fun bartlettWindow(windowLength: Int, periodic: Boolean): RealTensorType - - //https://pytorch.org/docs/stable/generated/torch.blackman_window.html#torch.blackman_window - public fun blackmanWindow(windowLength: Int, periodic: Boolean): RealTensorType - - //https://pytorch.org/docs/stable/generated/torch.hamming_window.html#torch.hamming_window - public fun hammingWindow(windowLength: Int, periodic: Boolean, alpha: T, beta: T): RealTensorType - - //https://pytorch.org/docs/stable/generated/torch.kaiser_window.html#torch.kaiser_window - public fun kaiserWindow(windowLength: Int, periodic: Boolean, beta: T): RealTensorType -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorStructure.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorStructure.kt deleted file mode 100644 index 0e0975830..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ComplexTensorStructure.kt +++ /dev/null @@ -1,14 +0,0 @@ -package space.kscience.kmath.tensors - -public interface ComplexTensorStructure> : TensorStructure { - - //https://pytorch.org/docs/master/generated/torch.view_as_real.html - public fun viewAsReal(): RealTensorType - - //https://pytorch.org/docs/stable/generated/torch.real.html - public fun realPart(): RealTensorType - - //https://pytorch.org/docs/stable/generated/torch.imag.html - public fun imaginaryPart(): RealTensorType - -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/OrderedTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/OrderedTensorAlgebra.kt deleted file mode 100644 index 3320c3a1e..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/OrderedTensorAlgebra.kt +++ /dev/null @@ -1,29 +0,0 @@ -package space.kscience.kmath.tensors - -public interface OrderedTensorAlgebra> : - TensorAlgebra { - - //https://pytorch.org/docs/stable/generated/torch.max.html#torch.max - public fun TensorType.max(dim: Int, keepDim: Boolean): TensorType - - //https://pytorch.org/docs/stable/generated/torch.cummax.html#torch.cummax - public fun TensorType.cummax(dim: Int): TensorType - - //https://pytorch.org/docs/stable/generated/torch.min.html#torch.min - public fun TensorType.min(dim: Int, keepDim: Boolean): TensorType - - //https://pytorch.org/docs/stable/generated/torch.cummin.html#torch.cummin - public fun TensorType.cummin(dim: Int): TensorType - - //https://pytorch.org/docs/stable/generated/torch.median.html#torch.median - public fun TensorType.median(dim: Int, keepDim: Boolean): TensorType - - //https://pytorch.org/docs/stable/generated/torch.maximum.html#torch.maximum - public fun maximum(lhs: TensorType, rhs: TensorType) - - //https://pytorch.org/docs/stable/generated/torch.minimum.html#torch.minimum - public fun minimum(lhs: TensorType, rhs: TensorType) - - //https://pytorch.org/docs/stable/generated/torch.sort.html#torch.sort - public fun TensorType.sort(dim: Int, keepDim: Boolean, descending: Boolean): TensorType -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index 37c6a34f8..b05105ed8 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -41,9 +41,6 @@ public interface TensorAlgebra> { public operator fun TensorType.timesAssign(other: TensorType): Unit public operator fun TensorType.unaryMinus(): TensorType - //https://pytorch.org/docs/stable/generated/torch.square.html - public fun TensorType.square(): TensorType - //https://pytorch.org/cppdocs/notes/tensor_indexing.html public operator fun TensorType.get(i: Int): TensorType @@ -56,21 +53,6 @@ public interface TensorAlgebra> { public fun TensorType.eq(other: TensorType, delta: T): Boolean - //https://pytorch.org/docs/stable/generated/torch.abs.html - public fun TensorType.abs(): TensorType - - //https://pytorch.org/docs/stable/generated/torch.sum.html - public fun TensorType.sum(dim: Int, keepDim: Boolean): TensorType - - //https://pytorch.org/docs/stable/generated/torch.cumsum.html#torch.cumsum - public fun TensorType.cumsum(dim: Int): TensorType - - //https://pytorch.org/docs/stable/generated/torch.prod.html#torch.prod - public fun TensorType.prod(dim: Int, keepDim: Boolean): TensorType - - //https://pytorch.org/docs/stable/generated/torch.cumprod.html#torch.cumprod - public fun TensorType.cumprod(dim: Int): TensorType - //https://pytorch.org/docs/stable/generated/torch.matmul.html public infix fun TensorType.dot(other: TensorType): TensorType @@ -80,12 +62,4 @@ public interface TensorAlgebra> { offset: Int = 0, dim1: Int = -2, dim2: Int = -1 ): TensorType - //https://pytorch.org/docs/stable/generated/torch.cat.html#torch.cat - public fun cat(tensors: List, dim: Int): TensorType - - //https://pytorch.org/docs/stable/generated/torch.flatten.html#torch.flatten - public fun TensorType.flatten(startDim: Int, endDim: Int): TensorType - - //https://pytorch.org/docs/stable/generated/torch.squeeze.html - public fun TensorType.squeeze(dim: Int): TensorType } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt index 54417e842..67b9c9d73 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt @@ -7,10 +7,4 @@ public interface TensorPartialDivisionAlgebra public operator fun TensorType.div(other: TensorType): TensorType public operator fun TensorType.divAssign(value: T) public operator fun TensorType.divAssign(other: TensorType) - - //https://pytorch.org/docs/stable/generated/torch.mean.html#torch.mean - public fun TensorType.mean(dim: Int = 0, keepDim: Boolean = false): TensorType - - //https://pytorch.org/docs/stable/generated/torch.var.html#torch.var - public fun TensorType.variance(dim: Int = 0, unbiased: Boolean = true, keepDim: Boolean = false): TensorType } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt index 1eb4c3b63..b46c7fa9c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt @@ -5,11 +5,10 @@ import kotlin.math.* public class DoubleAnalyticTensorAlgebra: AnalyticTensorAlgebra, - DoubleOrderedTensorAlgebra() + DoubleTensorAlgebra() { override fun DoubleTensor.exp(): DoubleTensor = this.map(::exp) - // todo log with other base???? override fun DoubleTensor.log(): DoubleTensor = this.map(::ln) override fun DoubleTensor.sqrt(): DoubleTensor = this.map(::sqrt) @@ -42,86 +41,6 @@ public class DoubleAnalyticTensorAlgebra: override fun DoubleTensor.floor(): DoubleTensor = this.map(::floor) - override fun DoubleTensor.clamp(min: Double, max: Double): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.erf(): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.erfinv(): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.erfc(): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.lerp(end: DoubleTensor, weight: DoubleTensor): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.lgamma(): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.logit(eps: Double): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.igamma(other: DoubleTensor): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.igammac(other: DoubleTensor): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.mvlgamma(dimensions: Int): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.polygamma(order: Int): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.pow(exponent: Double): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.round(): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.sigmoid(): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.sinc(): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.heaviside(values: DoubleTensor): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.trapz(xValues: DoubleTensor, dim: Int): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.quantile(q: Double, dim: Int, keepDim: Boolean): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.std(dim: Int, unbiased: Boolean, keepDim: Boolean): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.histc(bins: Int, min: Double, max: Double): DoubleTensor { - TODO("Not yet implemented") - } - } public inline fun DoubleAnalyticTensorAlgebra(block: DoubleAnalyticTensorAlgebra.() -> R): R = diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleOrderedTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleOrderedTensorAlgebra.kt deleted file mode 100644 index a6bea59f4..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleOrderedTensorAlgebra.kt +++ /dev/null @@ -1,43 +0,0 @@ -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.tensors.OrderedTensorAlgebra - -public open class DoubleOrderedTensorAlgebra: - OrderedTensorAlgebra, - DoubleTensorAlgebra() -{ - override fun DoubleTensor.max(dim: Int, keepDim: Boolean): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.cummax(dim: Int): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.min(dim: Int, keepDim: Boolean): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.cummin(dim: Int): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.median(dim: Int, keepDim: Boolean): DoubleTensor { - TODO("Not yet implemented") - } - - override fun maximum(lhs: DoubleTensor, rhs: DoubleTensor) { - TODO("Not yet implemented") - } - - override fun minimum(lhs: DoubleTensor, rhs: DoubleTensor) { - TODO("Not yet implemented") - } - - override fun DoubleTensor.sort(dim: Int, keepDim: Boolean, descending: Boolean): DoubleTensor { - TODO("Not yet implemented") - } -} - -public inline fun DoubleOrderedTensorAlgebra(block: DoubleOrderedTensorAlgebra.() -> R): R = - DoubleOrderedTensorAlgebra().block() \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 0c82ec9c8..0a2e8c86c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -224,26 +224,6 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra, dim: Int): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.flatten(startDim: Int, endDim: Int): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.mean(dim: Int, keepDim: Boolean): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.square(): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.variance(dim: Int, unbiased: Boolean, keepDim: Boolean): DoubleTensor { - TODO("Not yet implemented") - } - - override fun DoubleTensor.squeeze(dim: Int): DoubleTensor { - TODO("Not yet implemented") - } public fun DoubleTensor.map(transform: (Double) -> Double): DoubleTensor { return DoubleTensor( From 22b68e5ca469038e8ee6c2083aafa2f54d51d032 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 26 Mar 2021 20:36:21 +0000 Subject: [PATCH 069/178] BufferedTensor2D & BufferedTensor1D --- kmath-core/api/kmath-core.api | 28 ++++ .../kmath/tensors/core/BufferedTensor.kt | 133 ++++++++++++++++-- .../core/DoubleLinearOpsTensorAlgebra.kt | 11 +- .../core/TestDoubleLinearOpsAlgebra.kt | 1 - .../kmath/tensors/core/TestDoubleTensor.kt | 3 - 5 files changed, 152 insertions(+), 24 deletions(-) diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index a45f00a55..fc0905bd0 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -2745,6 +2745,34 @@ public class space/kscience/kmath/tensors/core/BufferedTensor : space/kscience/k public final fun vectorSequence ()Lkotlin/sequences/Sequence; } +public final class space/kscience/kmath/tensors/core/BufferedTensor1D : space/kscience/kmath/tensors/core/BufferedTensor, space/kscience/kmath/nd/MutableStructure1D { + public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; + public fun get (I)Ljava/lang/Object; + public fun get ([I)Ljava/lang/Object; + public fun getDimension ()I + public fun getSize ()I + public fun iterator ()Ljava/util/Iterator; + public fun set (ILjava/lang/Object;)V + public fun set ([ILjava/lang/Object;)V +} + +public final class space/kscience/kmath/tensors/core/BufferedTensor2D : space/kscience/kmath/tensors/core/BufferedTensor, space/kscience/kmath/nd/MutableStructure2D { + public fun elements ()Lkotlin/sequences/Sequence; + public fun get (II)Ljava/lang/Object; + public fun get ([I)Ljava/lang/Object; + public fun getColNum ()I + public fun getColumns ()Ljava/util/List; + public fun getRowNum ()I + public fun getRows ()Ljava/util/List; + public fun getShape ()[I + public fun set (IILjava/lang/Object;)V +} + +public final class space/kscience/kmath/tensors/core/BufferedTensorKt { + public static final fun as1D (Lspace/kscience/kmath/tensors/core/BufferedTensor;)Lspace/kscience/kmath/tensors/core/BufferedTensor1D; + public static final fun as2D (Lspace/kscience/kmath/tensors/core/BufferedTensor;)Lspace/kscience/kmath/tensors/core/BufferedTensor2D; +} + public final class space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra : space/kscience/kmath/tensors/core/DoubleTensorAlgebra, space/kscience/kmath/tensors/AnalyticTensorAlgebra { public fun ()V public synthetic fun acos (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 160c61260..aa6e58ef6 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -1,23 +1,26 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.nd.* +import space.kscience.kmath.nd.MutableStructure1D +import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.structures.* import space.kscience.kmath.tensors.TensorStructure -import kotlin.math.atanh + public open class BufferedTensor( override val shape: IntArray, public val buffer: MutableBuffer, internal val bufferStart: Int -) : TensorStructure -{ +) : TensorStructure { public val linearStructure: TensorLinearStructure get() = TensorLinearStructure(shape) public val numel: Int get() = linearStructure.size + internal constructor(tensor: BufferedTensor) : + this(tensor.shape, tensor.buffer, tensor.bufferStart) + override fun get(index: IntArray): T = buffer[bufferStart + linearStructure.offset(index)] override fun set(index: IntArray, value: T) { @@ -32,8 +35,8 @@ public open class BufferedTensor( override fun hashCode(): Int = 0 - public fun vectorSequence(): Sequence> = sequence { - check(shape.size >= 1) {"todo"} + public fun vectorSequence(): Sequence> = sequence { + check(shape.size >= 1) { "todo" } val n = shape.size val vectorOffset = shape[n - 1] val vectorShape = intArrayOf(shape.last()) @@ -43,8 +46,8 @@ public open class BufferedTensor( } } - public fun matrixSequence(): Sequence> = sequence { - check(shape.size >= 2) {"todo"} + public fun matrixSequence(): Sequence> = sequence { + check(shape.size >= 2) { "todo" } val n = shape.size val matrixOffset = shape[n - 1] * shape[n - 2] val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) //todo better way? @@ -54,14 +57,14 @@ public open class BufferedTensor( } } - public inline fun forEachVector(vectorAction : (MutableStructure1D) -> Unit): Unit { - for (vector in vectorSequence()){ + public inline fun forEachVector(vectorAction: (BufferedTensor1D) -> Unit): Unit { + for (vector in vectorSequence()) { vectorAction(vector) } } - public inline fun forEachMatrix(matrixAction : (MutableStructure2D) -> Unit): Unit { - for (matrix in matrixSequence()){ + public inline fun forEachMatrix(matrixAction: (BufferedTensor2D) -> Unit): Unit { + for (matrix in matrixSequence()) { matrixAction(matrix) } } @@ -74,21 +77,125 @@ public class IntTensor internal constructor( buffer: IntArray, offset: Int = 0 ) : BufferedTensor(shape, IntBuffer(buffer), offset) +{ + internal constructor(bufferedTensor: BufferedTensor): + this(bufferedTensor.shape, bufferedTensor.buffer.array(), bufferedTensor.bufferStart) +} public class LongTensor internal constructor( shape: IntArray, buffer: LongArray, offset: Int = 0 ) : BufferedTensor(shape, LongBuffer(buffer), offset) +{ + internal constructor(bufferedTensor: BufferedTensor): + this(bufferedTensor.shape, bufferedTensor.buffer.array(), bufferedTensor.bufferStart) +} public class FloatTensor internal constructor( shape: IntArray, buffer: FloatArray, offset: Int = 0 ) : BufferedTensor(shape, FloatBuffer(buffer), offset) +{ + internal constructor(bufferedTensor: BufferedTensor): + this(bufferedTensor.shape, bufferedTensor.buffer.array(), bufferedTensor.bufferStart) +} public class DoubleTensor internal constructor( shape: IntArray, buffer: DoubleArray, offset: Int = 0 -) : BufferedTensor(shape, DoubleBuffer(buffer), offset) \ No newline at end of file +) : BufferedTensor(shape, DoubleBuffer(buffer), offset) +{ + internal constructor(bufferedTensor: BufferedTensor): + this(bufferedTensor.shape, bufferedTensor.buffer.array(), bufferedTensor.bufferStart) +} + + +public class BufferedTensor2D internal constructor( + private val tensor: BufferedTensor, +) : BufferedTensor(tensor), MutableStructure2D { + init { + check(shape.size == 2) { + "Shape ${shape.toList()} not compatible with DoubleTensor2D" + } + } + + override val shape: IntArray + get() = tensor.shape + + override val rowNum: Int + get() = shape[0] + override val colNum: Int + get() = shape[1] + + override fun get(i: Int, j: Int): T = tensor[intArrayOf(i, j)] + + override fun get(index: IntArray): T = tensor[index] + + override fun elements(): Sequence> = tensor.elements() + + override fun set(i: Int, j: Int, value: T) { + tensor[intArrayOf(i, j)] = value + } + + override val rows: List> + get() = List(rowNum) { i -> + BufferedTensor1D( + BufferedTensor( + shape = intArrayOf(colNum), + buffer = VirtualMutableBuffer(colNum) { j -> get(i, j) }, + bufferStart = 0 + ) + ) + } + + override val columns: List> + get() = List(colNum) { j -> + BufferedTensor1D( + BufferedTensor( + shape = intArrayOf(rowNum), + buffer = VirtualMutableBuffer(rowNum) { i -> get(i, j) }, + bufferStart = 0 + ) + ) + } +} + +public class BufferedTensor1D internal constructor( + private val tensor: BufferedTensor +) : BufferedTensor(tensor), MutableStructure1D { + init { + check(shape.size == 1) { + "Shape ${shape.toList()} not compatible with DoubleTensor1D" + } + } + + override fun get(index: IntArray): T = tensor[index] + + override fun set(index: IntArray, value: T) { + tensor[index] = value + } + + override val size: Int + get() = tensor.linearStructure.size + + override fun get(index: Int): T = tensor[intArrayOf(index)] + + override fun set(index: Int, value: T) { + tensor[intArrayOf(index)] = value + } + + override fun copy(): MutableBuffer = tensor.buffer.copy() + +} + +internal fun BufferedTensor.asIntTensor(): IntTensor = IntTensor(this) +internal fun BufferedTensor.asLongTensor(): LongTensor = LongTensor(this) +internal fun BufferedTensor.asFloatTensor(): FloatTensor = FloatTensor(this) +internal fun BufferedTensor.asDoubleTensor(): DoubleTensor = DoubleTensor(this) + + +public fun BufferedTensor.as2D(): BufferedTensor2D = BufferedTensor2D(this) +public fun BufferedTensor.as1D(): BufferedTensor1D = BufferedTensor1D(this) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 0b9d824f0..70fe8a1cc 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -1,8 +1,5 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.nd.MutableStructure2D -import space.kscience.kmath.nd.Structure1D -import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.tensors.LinearOpsTensorAlgebra import kotlin.math.sqrt @@ -153,7 +150,7 @@ public class DoubleLinearOpsTensorAlgebra : TODO("ANDREI") } - private fun luMatrixDet(lu: Structure2D, pivots: Structure1D): Double { + private fun luMatrixDet(lu: BufferedTensor2D, pivots: BufferedTensor1D): Double { val m = lu.shape[0] val sign = if((pivots[m] - m) % 2 == 0) 1.0 else -1.0 return (0 until m).asSequence().map { lu[it, it] }.fold(sign) { left, right -> left * right } @@ -180,9 +177,9 @@ public class DoubleLinearOpsTensorAlgebra : } private fun luMatrixInv( - lu: Structure2D, - pivots: Structure1D, - invMatrix : MutableStructure2D + lu: BufferedTensor2D, + pivots: BufferedTensor1D, + invMatrix : BufferedTensor2D ): Unit { val m = lu.shape[0] diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index d77f33f9d..3a129b03c 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -1,7 +1,6 @@ package space.kscience.kmath.tensors.core import kotlin.math.abs -import kotlin.math.exp import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index b12b08b52..40597f539 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -1,8 +1,5 @@ package space.kscience.kmath.tensors.core - -import space.kscience.kmath.nd.as1D -import space.kscience.kmath.nd.as2D import space.kscience.kmath.structures.toDoubleArray import kotlin.test.Test import kotlin.test.assertEquals From 92710097f06d0ec6161e4f3518a2fd0815ff157a Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Mon, 29 Mar 2021 21:58:56 +0100 Subject: [PATCH 070/178] Fixing 2D and 1D casts --- kmath-core/api/kmath-core.api | 33 --- .../kmath/tensors/core/BufferedTensor.kt | 107 +-------- .../core/DoubleLinearOpsTensorAlgebra.kt | 220 ++++++++++-------- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 53 +++-- .../kscience/kmath/tensors/core/checks.kt | 6 +- .../kmath/tensors/core/TestDoubleTensor.kt | 2 + 6 files changed, 173 insertions(+), 248 deletions(-) diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index fc0905bd0..786b81d19 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -2731,8 +2731,6 @@ public class space/kscience/kmath/tensors/core/BufferedTensor : space/kscience/k public fun ([ILspace/kscience/kmath/structures/MutableBuffer;I)V public fun elements ()Lkotlin/sequences/Sequence; public fun equals (Ljava/lang/Object;)Z - public final fun forEachMatrix (Lkotlin/jvm/functions/Function1;)V - public final fun forEachVector (Lkotlin/jvm/functions/Function1;)V public fun get ([I)Ljava/lang/Object; public final fun getBuffer ()Lspace/kscience/kmath/structures/MutableBuffer; public fun getDimension ()I @@ -2740,37 +2738,7 @@ public class space/kscience/kmath/tensors/core/BufferedTensor : space/kscience/k public final fun getNumel ()I public fun getShape ()[I public fun hashCode ()I - public final fun matrixSequence ()Lkotlin/sequences/Sequence; public fun set ([ILjava/lang/Object;)V - public final fun vectorSequence ()Lkotlin/sequences/Sequence; -} - -public final class space/kscience/kmath/tensors/core/BufferedTensor1D : space/kscience/kmath/tensors/core/BufferedTensor, space/kscience/kmath/nd/MutableStructure1D { - public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun get (I)Ljava/lang/Object; - public fun get ([I)Ljava/lang/Object; - public fun getDimension ()I - public fun getSize ()I - public fun iterator ()Ljava/util/Iterator; - public fun set (ILjava/lang/Object;)V - public fun set ([ILjava/lang/Object;)V -} - -public final class space/kscience/kmath/tensors/core/BufferedTensor2D : space/kscience/kmath/tensors/core/BufferedTensor, space/kscience/kmath/nd/MutableStructure2D { - public fun elements ()Lkotlin/sequences/Sequence; - public fun get (II)Ljava/lang/Object; - public fun get ([I)Ljava/lang/Object; - public fun getColNum ()I - public fun getColumns ()Ljava/util/List; - public fun getRowNum ()I - public fun getRows ()Ljava/util/List; - public fun getShape ()[I - public fun set (IILjava/lang/Object;)V -} - -public final class space/kscience/kmath/tensors/core/BufferedTensorKt { - public static final fun as1D (Lspace/kscience/kmath/tensors/core/BufferedTensor;)Lspace/kscience/kmath/tensors/core/BufferedTensor1D; - public static final fun as2D (Lspace/kscience/kmath/tensors/core/BufferedTensor;)Lspace/kscience/kmath/tensors/core/BufferedTensor2D; } public final class space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra : space/kscience/kmath/tensors/core/DoubleTensorAlgebra, space/kscience/kmath/tensors/AnalyticTensorAlgebra { @@ -2876,7 +2844,6 @@ public class space/kscience/kmath/tensors/core/DoubleTensorAlgebra : space/kscie public synthetic fun eq (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Z public final fun eq (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Z public fun eq (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Z - public final fun eq (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lkotlin/jvm/functions/Function2;)Z public synthetic fun eye (I)Lspace/kscience/kmath/nd/MutableStructureND; public fun eye (I)Lspace/kscience/kmath/tensors/core/DoubleTensor; public final fun fromArray ([I[D)Lspace/kscience/kmath/tensors/core/DoubleTensor; diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index aa6e58ef6..d99c35569 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -35,35 +35,34 @@ public open class BufferedTensor( override fun hashCode(): Int = 0 - public fun vectorSequence(): Sequence> = sequence { - check(shape.size >= 1) { "todo" } + internal fun vectorSequence(): Sequence> = sequence { val n = shape.size val vectorOffset = shape[n - 1] val vectorShape = intArrayOf(shape.last()) for (offset in 0 until numel step vectorOffset) { - val vector = BufferedTensor(vectorShape, buffer, offset).as1D() + val vector = BufferedTensor(vectorShape, buffer, offset) yield(vector) } } - public fun matrixSequence(): Sequence> = sequence { + internal fun matrixSequence(): Sequence> = sequence { check(shape.size >= 2) { "todo" } val n = shape.size val matrixOffset = shape[n - 1] * shape[n - 2] - val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) //todo better way? + val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) for (offset in 0 until numel step matrixOffset) { - val matrix = BufferedTensor(matrixShape, buffer, offset).as2D() + val matrix = BufferedTensor(matrixShape, buffer, offset) yield(matrix) } } - public inline fun forEachVector(vectorAction: (BufferedTensor1D) -> Unit): Unit { + internal inline fun forEachVector(vectorAction: (BufferedTensor) -> Unit): Unit { for (vector in vectorSequence()) { vectorAction(vector) } } - public inline fun forEachMatrix(matrixAction: (BufferedTensor2D) -> Unit): Unit { + internal inline fun forEachMatrix(matrixAction: (BufferedTensor) -> Unit): Unit { for (matrix in matrixSequence()) { matrixAction(matrix) } @@ -71,7 +70,6 @@ public open class BufferedTensor( } - public class IntTensor internal constructor( shape: IntArray, buffer: IntArray, @@ -112,90 +110,7 @@ public class DoubleTensor internal constructor( this(bufferedTensor.shape, bufferedTensor.buffer.array(), bufferedTensor.bufferStart) } - -public class BufferedTensor2D internal constructor( - private val tensor: BufferedTensor, -) : BufferedTensor(tensor), MutableStructure2D { - init { - check(shape.size == 2) { - "Shape ${shape.toList()} not compatible with DoubleTensor2D" - } - } - - override val shape: IntArray - get() = tensor.shape - - override val rowNum: Int - get() = shape[0] - override val colNum: Int - get() = shape[1] - - override fun get(i: Int, j: Int): T = tensor[intArrayOf(i, j)] - - override fun get(index: IntArray): T = tensor[index] - - override fun elements(): Sequence> = tensor.elements() - - override fun set(i: Int, j: Int, value: T) { - tensor[intArrayOf(i, j)] = value - } - - override val rows: List> - get() = List(rowNum) { i -> - BufferedTensor1D( - BufferedTensor( - shape = intArrayOf(colNum), - buffer = VirtualMutableBuffer(colNum) { j -> get(i, j) }, - bufferStart = 0 - ) - ) - } - - override val columns: List> - get() = List(colNum) { j -> - BufferedTensor1D( - BufferedTensor( - shape = intArrayOf(rowNum), - buffer = VirtualMutableBuffer(rowNum) { i -> get(i, j) }, - bufferStart = 0 - ) - ) - } -} - -public class BufferedTensor1D internal constructor( - private val tensor: BufferedTensor -) : BufferedTensor(tensor), MutableStructure1D { - init { - check(shape.size == 1) { - "Shape ${shape.toList()} not compatible with DoubleTensor1D" - } - } - - override fun get(index: IntArray): T = tensor[index] - - override fun set(index: IntArray, value: T) { - tensor[index] = value - } - - override val size: Int - get() = tensor.linearStructure.size - - override fun get(index: Int): T = tensor[intArrayOf(index)] - - override fun set(index: Int, value: T) { - tensor[intArrayOf(index)] = value - } - - override fun copy(): MutableBuffer = tensor.buffer.copy() - -} - -internal fun BufferedTensor.asIntTensor(): IntTensor = IntTensor(this) -internal fun BufferedTensor.asLongTensor(): LongTensor = LongTensor(this) -internal fun BufferedTensor.asFloatTensor(): FloatTensor = FloatTensor(this) -internal fun BufferedTensor.asDoubleTensor(): DoubleTensor = DoubleTensor(this) - - -public fun BufferedTensor.as2D(): BufferedTensor2D = BufferedTensor2D(this) -public fun BufferedTensor.as1D(): BufferedTensor1D = BufferedTensor1D(this) \ No newline at end of file +internal fun BufferedTensor.asTensor(): IntTensor = IntTensor(this) +internal fun BufferedTensor.asTensor(): LongTensor = LongTensor(this) +internal fun BufferedTensor.asTensor(): FloatTensor = FloatTensor(this) +internal fun BufferedTensor.asTensor(): DoubleTensor = DoubleTensor(this) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 70fe8a1cc..0d19fd3f6 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -1,5 +1,9 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.nd.MutableStructure1D +import space.kscience.kmath.nd.MutableStructure2D +import space.kscience.kmath.nd.as1D +import space.kscience.kmath.nd.as2D import space.kscience.kmath.tensors.LinearOpsTensorAlgebra import kotlin.math.sqrt @@ -11,6 +15,48 @@ public class DoubleLinearOpsTensorAlgebra : override fun DoubleTensor.det(): DoubleTensor = detLU() + private inline fun luHelper(lu: MutableStructure2D, pivots: MutableStructure1D, m: Int) { + for (row in 0 until m) pivots[row] = row + + for (i in 0 until m) { + var maxVal = -1.0 + var maxInd = i + + for (k in i until m) { + val absA = kotlin.math.abs(lu[k, i]) + if (absA > maxVal) { + maxVal = absA + maxInd = k + } + } + + //todo check singularity + + if (maxInd != i) { + + val j = pivots[i] + pivots[i] = pivots[maxInd] + pivots[maxInd] = j + + for (k in 0 until m) { + val tmp = lu[i, k] + lu[i, k] = lu[maxInd, k] + lu[maxInd, k] = tmp + } + + pivots[m] += 1 + + } + + for (j in i + 1 until m) { + lu[j, i] /= lu[i, i] + for (k in i + 1 until m) { + lu[j, k] -= lu[j, i] * lu[i, k] + } + } + } + } + override fun DoubleTensor.lu(): Pair { checkSquareMatrix(shape) @@ -27,90 +73,93 @@ public class DoubleLinearOpsTensorAlgebra : IntArray(pivotsShape.reduce(Int::times)) { 0 } ) - for ((lu, pivots) in luTensor.matrixSequence().zip(pivotsTensor.vectorSequence())){ - for (row in 0 until m) pivots[row] = row - - for (i in 0 until m) { - var maxVal = -1.0 - var maxInd = i - - for (k in i until m) { - val absA = kotlin.math.abs(lu[k, i]) - if (absA > maxVal) { - maxVal = absA - maxInd = k - } - } - - //todo check singularity - - if (maxInd != i) { - - val j = pivots[i] - pivots[i] = pivots[maxInd] - pivots[maxInd] = j - - for (k in 0 until m) { - val tmp = lu[i, k] - lu[i, k] = lu[maxInd, k] - lu[maxInd, k] = tmp - } - - pivots[m] += 1 - - } - - for (j in i + 1 until m) { - lu[j, i] /= lu[i, i] - for (k in i + 1 until m) { - lu[j, k] -= lu[j, i] * lu[i, k] - } - } - } - } - + for ((lu, pivots) in luTensor.matrixSequence().zip(pivotsTensor.vectorSequence())) + luHelper(lu.as2D(), pivots.as1D(), m) return Pair(luTensor, pivotsTensor) } - override fun luPivot(luTensor: DoubleTensor, pivotsTensor: IntTensor): Triple { + private inline fun pivInit( + p: MutableStructure2D, + pivot: MutableStructure1D, + n: Int + ) { + for (i in 0 until n) { + p[i, pivot[i]] = 1.0 + } + } + + private inline fun luPivotHelper( + l: MutableStructure2D, + u: MutableStructure2D, + lu: MutableStructure2D, + n: Int + ) { + for (i in 0 until n) { + for (j in 0 until n) { + if (i == j) { + l[i, j] = 1.0 + } + if (j < i) { + l[i, j] = lu[i, j] + } + if (j >= i) { + u[i, j] = lu[i, j] + } + } + } + } + + override fun luPivot( + luTensor: DoubleTensor, + pivotsTensor: IntTensor + ): Triple { //todo checks checkSquareMatrix(luTensor.shape) - check(luTensor.shape.dropLast(1).toIntArray() contentEquals pivotsTensor.shape) { "Bed shapes (("} //todo rewrite + check( + luTensor.shape.dropLast(1).toIntArray() contentEquals pivotsTensor.shape + ) { "Bed shapes ((" } //todo rewrite val n = luTensor.shape.last() val pTensor = luTensor.zeroesLike() - for ((p, pivot) in pTensor.matrixSequence().zip(pivotsTensor.vectorSequence())){ - for (i in 0 until n){ - p[i, pivot[i]] = 1.0 - } - } + for ((p, pivot) in pTensor.matrixSequence().zip(pivotsTensor.vectorSequence())) + pivInit(p.as2D(), pivot.as1D(), n) val lTensor = luTensor.zeroesLike() val uTensor = luTensor.zeroesLike() - for ((pairLU, lu) in lTensor.matrixSequence().zip(uTensor.matrixSequence()).zip(luTensor.matrixSequence())){ + for ((pairLU, lu) in lTensor.matrixSequence().zip(uTensor.matrixSequence()) + .zip(luTensor.matrixSequence())) { val (l, u) = pairLU - for (i in 0 until n) { - for (j in 0 until n) { - if (i == j) { - l[i, j] = 1.0 - } - if (j < i) { - l[i, j] = lu[i, j] - } - if (j >= i) { - u[i, j] = lu[i, j] - } - } - } + luPivotHelper(l.as2D(), u.as2D(), lu.as2D(), n) } return Triple(pTensor, lTensor, uTensor) } + private inline fun choleskyHelper( + a: MutableStructure2D, + l: MutableStructure2D, + n: Int + ) { + for (i in 0 until n) { + for (j in 0 until i) { + var h = a[i, j] + for (k in 0 until j) { + h -= l[i, k] * l[j, k] + } + l[i, j] = h / l[j, j] + } + var h = a[i, i] + for (j in 0 until i) { + h -= l[i, j] * l[i, j] + } + l[i, i] = sqrt(h) + } + } + override fun DoubleTensor.cholesky(): DoubleTensor { // todo checks checkSquareMatrix(shape) @@ -118,22 +167,8 @@ public class DoubleLinearOpsTensorAlgebra : val n = shape.last() val lTensor = zeroesLike() - for ((a, l) in this.matrixSequence().zip(lTensor.matrixSequence())) { - for (i in 0 until n) { - for (j in 0 until i) { - var h = a[i, j] - for (k in 0 until j) { - h -= l[i, k] * l[j, k] - } - l[i, j] = h / l[j, j] - } - var h = a[i, i] - for (j in 0 until i) { - h -= l[i, j] * l[i, j] - } - l[i, i] = sqrt(h) - } - } + for ((a, l) in this.matrixSequence().zip(lTensor.matrixSequence())) + for (i in 0 until n) choleskyHelper(a.as2D(), l.as2D(), n) return lTensor } @@ -150,9 +185,11 @@ public class DoubleLinearOpsTensorAlgebra : TODO("ANDREI") } - private fun luMatrixDet(lu: BufferedTensor2D, pivots: BufferedTensor1D): Double { + private fun luMatrixDet(luTensor: MutableStructure2D, pivotsTensor: MutableStructure1D): Double { + val lu = luTensor.as2D() + val pivots = pivotsTensor.as1D() val m = lu.shape[0] - val sign = if((pivots[m] - m) % 2 == 0) 1.0 else -1.0 + val sign = if ((pivots[m] - m) % 2 == 0) 1.0 else -1.0 return (0 until m).asSequence().map { lu[it, it] }.fold(sign) { left, right -> left * right } } @@ -162,34 +199,34 @@ public class DoubleLinearOpsTensorAlgebra : val detTensorShape = IntArray(n - 1) { i -> shape[i] } detTensorShape[n - 2] = 1 - val resBuffer = DoubleArray(detTensorShape.reduce(Int::times)) { 0.0 } + val resBuffer = DoubleArray(detTensorShape.reduce(Int::times)) { 0.0 } val detTensor = DoubleTensor( detTensorShape, resBuffer ) - luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).forEachIndexed { index, (luMatrix, pivots) -> - resBuffer[index] = luMatrixDet(luMatrix, pivots) + luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).forEachIndexed { index, (lu, pivots) -> + resBuffer[index] = luMatrixDet(lu.as2D(), pivots.as1D()) } return detTensor } private fun luMatrixInv( - lu: BufferedTensor2D, - pivots: BufferedTensor1D, - invMatrix : BufferedTensor2D - ): Unit { + lu: MutableStructure2D, + pivots: MutableStructure1D, + invMatrix: MutableStructure2D + ) { val m = lu.shape[0] for (j in 0 until m) { for (i in 0 until m) { - if (pivots[i] == j){ + if (pivots[i] == j) { invMatrix[i, j] = 1.0 } - for (k in 0 until i){ + for (k in 0 until i) { invMatrix[i, j] -= lu[i, k] * invMatrix[k, j] } } @@ -205,13 +242,12 @@ public class DoubleLinearOpsTensorAlgebra : public fun DoubleTensor.invLU(): DoubleTensor { val (luTensor, pivotsTensor) = lu() - val n = shape.size val invTensor = luTensor.zeroesLike() val seq = luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).zip(invTensor.matrixSequence()) for ((luP, invMatrix) in seq) { val (lu, pivots) = luP - luMatrixInv(lu, pivots, invMatrix) + luMatrixInv(lu.as2D(), pivots.as1D(), invMatrix.as2D()) } return invTensor diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 0a2e8c86c..b25f0164b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -1,8 +1,7 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.linear.Matrix import space.kscience.kmath.nd.MutableStructure2D -import space.kscience.kmath.nd.Structure2D +import space.kscience.kmath.nd.as2D import space.kscience.kmath.tensors.TensorPartialDivisionAlgebra import kotlin.math.abs @@ -224,6 +223,23 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra, + b: MutableStructure2D, + res: MutableStructure2D, + l: Int, m: Int, n: Int + ) { + for (i in 0 until l) { + for (j in 0 until n) { + var curr = 0.0 + for (k in 0 until m) { + curr += a[i, k] * b[k, j] + } + res[i, j] = curr + } + } + } + override fun DoubleTensor.dot(other: DoubleTensor): DoubleTensor { if (this.shape.size == 1 && other.shape.size == 1) { return DoubleTensor(intArrayOf(1), doubleArrayOf(this.times(other).buffer.array().sum())) @@ -240,7 +256,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra Boolean): Boolean { - if (!(this.shape contentEquals other.shape)) { - return false - } - return this.eq(other, eqFunction) - } + public fun DoubleTensor.contentEquals(other: DoubleTensor, eqFunction: (Double, Double) -> Boolean): Boolean = + this.eq(other, eqFunction) - public fun DoubleTensor.eq(other: DoubleTensor, eqFunction: (Double, Double) -> Boolean): Boolean { - // todo broadcasting checking + private fun DoubleTensor.eq(other: DoubleTensor, eqFunction: (Double, Double) -> Boolean): Boolean { + checkShapesCompatible(this, other) val n = this.linearStructure.size if (n != other.linearStructure.size) { return false diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt index c644a295c..247ed3913 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -11,14 +11,14 @@ internal inline fun , "Illegal empty shape provided" } -internal inline fun < TensorType : TensorStructure, +internal inline fun , TorchTensorAlgebraType : TensorAlgebra> TorchTensorAlgebraType.checkEmptyDoubleBuffer(buffer: DoubleArray): Unit = check(buffer.isNotEmpty()) { "Illegal empty buffer provided" } -internal inline fun < TensorType : TensorStructure, +internal inline fun , TorchTensorAlgebraType : TensorAlgebra> TorchTensorAlgebraType.checkBufferShapeConsistency(shape: IntArray, buffer: DoubleArray): Unit = check(buffer.size == shape.reduce(Int::times)) { @@ -56,4 +56,4 @@ internal inline fun , check(shape[n - 1] == shape[n - 2]) { "Tensor must be batches of square matrices, but they are ${shape[n - 1]} by ${shape[n - 1]} matrices" } -} +} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index 40597f539..5e6fdcdc5 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -1,5 +1,7 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.nd.as1D +import space.kscience.kmath.nd.as2D import space.kscience.kmath.structures.toDoubleArray import kotlin.test.Test import kotlin.test.assertEquals From 51eca003af9daeb72a53fc05867d955d1167154c Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Mon, 29 Mar 2021 22:11:34 +0100 Subject: [PATCH 071/178] Moved back value to main algebra context --- kmath-core/api/kmath-core.api | 17 +++-------------- .../kmath/tensors/ReduceOpsTensorAlgebra.kt | 7 ------- .../kscience/kmath/tensors/TensorAlgebra.kt | 2 ++ .../core/DoubleReduceOpsTensorAlgebra.kt | 18 ------------------ .../kmath/tensors/core/DoubleTensorAlgebra.kt | 7 +++++++ .../tensors/core/TestDoubleLinearOpsAlgebra.kt | 9 +++------ .../kmath/tensors/core/TestDoubleTensor.kt | 10 +++++++++- 7 files changed, 24 insertions(+), 46 deletions(-) delete mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ReduceOpsTensorAlgebra.kt delete mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleReduceOpsTensorAlgebra.kt diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index 786b81d19..373920204 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -2654,10 +2654,6 @@ public final class space/kscience/kmath/tensors/LinearOpsTensorAlgebra$DefaultIm public static synthetic fun symEig$default (Lspace/kscience/kmath/tensors/LinearOpsTensorAlgebra;Lspace/kscience/kmath/nd/MutableStructureND;ZILjava/lang/Object;)Lkotlin/Pair; } -public abstract interface class space/kscience/kmath/tensors/ReduceOpsTensorAlgebra : space/kscience/kmath/tensors/TensorAlgebra { - public abstract fun value (Lspace/kscience/kmath/nd/MutableStructureND;)Ljava/lang/Object; -} - public abstract interface class space/kscience/kmath/tensors/TensorAlgebra { public abstract fun copy (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun diagonalEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;III)Lspace/kscience/kmath/nd/MutableStructureND; @@ -2686,6 +2682,7 @@ public abstract interface class space/kscience/kmath/tensors/TensorAlgebra { public abstract fun timesAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V public abstract fun transpose (Lspace/kscience/kmath/nd/MutableStructureND;II)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun unaryMinus (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun value (Lspace/kscience/kmath/nd/MutableStructureND;)Ljava/lang/Object; public abstract fun view (Lspace/kscience/kmath/nd/MutableStructureND;[I)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun viewAs (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun zeroesLike (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; @@ -2809,16 +2806,6 @@ public final class space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebr public static final fun DoubleLinearOpsTensorAlgebra (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; } -public final class space/kscience/kmath/tensors/core/DoubleReduceOpsTensorAlgebra : space/kscience/kmath/tensors/core/DoubleTensorAlgebra, space/kscience/kmath/tensors/ReduceOpsTensorAlgebra { - public fun ()V - public synthetic fun value (Lspace/kscience/kmath/nd/MutableStructureND;)Ljava/lang/Object; - public fun value (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Ljava/lang/Double; -} - -public final class space/kscience/kmath/tensors/core/DoubleReduceOpsTensorAlgebraKt { - public static final fun DoubleReduceOpsTensorAlgebra (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; -} - public final class space/kscience/kmath/tensors/core/DoubleTensor : space/kscience/kmath/tensors/core/BufferedTensor { } @@ -2892,6 +2879,8 @@ public class space/kscience/kmath/tensors/core/DoubleTensorAlgebra : space/kscie public fun transpose (Lspace/kscience/kmath/tensors/core/DoubleTensor;II)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun unaryMinus (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun unaryMinus (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun value (Lspace/kscience/kmath/nd/MutableStructureND;)Ljava/lang/Object; + public fun value (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Ljava/lang/Double; public synthetic fun view (Lspace/kscience/kmath/nd/MutableStructureND;[I)Lspace/kscience/kmath/nd/MutableStructureND; public fun view (Lspace/kscience/kmath/tensors/core/DoubleTensor;[I)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun viewAs (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ReduceOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ReduceOpsTensorAlgebra.kt deleted file mode 100644 index 820b9b25b..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/ReduceOpsTensorAlgebra.kt +++ /dev/null @@ -1,7 +0,0 @@ -package space.kscience.kmath.tensors - -public interface ReduceOpsTensorAlgebra> : - TensorAlgebra { - public fun TensorType.value(): T - -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index b05105ed8..5b7515b20 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -5,6 +5,8 @@ import space.kscience.kmath.tensors.core.DoubleTensor // https://proofwiki.org/wiki/Definition:Algebra_over_Ring public interface TensorAlgebra> { + public fun TensorType.value(): T + //https://pytorch.org/docs/stable/generated/torch.full.html public fun full(value: T, shape: IntArray): TensorType diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleReduceOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleReduceOpsTensorAlgebra.kt deleted file mode 100644 index 9a8aa9ebf..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleReduceOpsTensorAlgebra.kt +++ /dev/null @@ -1,18 +0,0 @@ -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.tensors.ReduceOpsTensorAlgebra - -public class DoubleReduceOpsTensorAlgebra: - DoubleTensorAlgebra(), - ReduceOpsTensorAlgebra { - - override fun DoubleTensor.value(): Double { - check(this.shape contentEquals intArrayOf(1)) { - "Inconsistent value for tensor of shape ${shape.toList()}" - } - return this.buffer.array()[this.bufferStart] - } -} - -public inline fun DoubleReduceOpsTensorAlgebra(block: DoubleReduceOpsTensorAlgebra.() -> R): R = - DoubleReduceOpsTensorAlgebra().block() \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index b25f0164b..b418f3647 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -7,6 +7,13 @@ import kotlin.math.abs public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { + override fun DoubleTensor.value(): Double { + check(this.shape contentEquals intArrayOf(1)) { + "Inconsistent value for tensor of shape ${shape.toList()}" + } + return this.buffer.array()[this.bufferStart] + } + public fun fromArray(shape: IntArray, buffer: DoubleArray): DoubleTensor { checkEmptyShape(shape) checkEmptyDoubleBuffer(buffer) diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 3a129b03c..d2d4ffb67 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -72,11 +72,8 @@ class TestDoubleLinearOpsTensorAlgebra { @Test fun testScalarProduct() = DoubleLinearOpsTensorAlgebra { - val a = fromArray(intArrayOf(3), doubleArrayOf(1.8,2.5, 6.8)) - val b = fromArray(intArrayOf(3), doubleArrayOf(5.5,2.6, 6.4)) - DoubleReduceOpsTensorAlgebra { - assertEquals(a.dot(b).value(), 59.92) - } - + val a = fromArray(intArrayOf(3), doubleArrayOf(1.8, 2.5, 6.8)) + val b = fromArray(intArrayOf(3), doubleArrayOf(5.5, 2.6, 6.4)) + assertEquals(a.dot(b).value(), 59.92) } } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index 5e6fdcdc5..4f4d9bbdf 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -10,7 +10,7 @@ import kotlin.test.assertTrue class TestDoubleTensor { @Test - fun valueTest() = DoubleReduceOpsTensorAlgebra { + fun valueTest() = DoubleTensorAlgebra { val value = 12.5 val tensor = fromArray(intArrayOf(1), doubleArrayOf(value)) assertEquals(tensor.value(), value) @@ -37,5 +37,13 @@ class TestDoubleTensor { vector[0] = 109.56 assertEquals(tensor[intArrayOf(0,1,0)], 109.56) + + tensor.matrixSequence().forEach { + val a = it.asTensor() + val secondRow = a[1].as1D() + val secondColumn = a.transpose(0,1)[1].as1D() + assertEquals(secondColumn[0], 77.89) + assertEquals(secondRow[1], secondColumn[1]) + } } } \ No newline at end of file From d281dfca3ab869fcfb16181f82cc91b57bb4d26d Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 30 Mar 2021 11:22:55 +0100 Subject: [PATCH 072/178] Separate linear algebra utils into dedicated module --- .../kmath/tensors/core/BufferedTensor.kt | 38 ---- .../core/DoubleLinearOpsTensorAlgebra.kt | 134 +------------ .../kmath/tensors/core/DoubleTensorAlgebra.kt | 20 +- .../kscience/kmath/tensors/core/linutils.kt | 188 ++++++++++++++++++ 4 files changed, 190 insertions(+), 190 deletions(-) create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index d99c35569..9a4d13d2c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -1,7 +1,5 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.nd.MutableStructure1D -import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.structures.* import space.kscience.kmath.tensors.TensorStructure @@ -18,9 +16,6 @@ public open class BufferedTensor( public val numel: Int get() = linearStructure.size - internal constructor(tensor: BufferedTensor) : - this(tensor.shape, tensor.buffer, tensor.bufferStart) - override fun get(index: IntArray): T = buffer[bufferStart + linearStructure.offset(index)] override fun set(index: IntArray, value: T) { @@ -35,39 +30,6 @@ public open class BufferedTensor( override fun hashCode(): Int = 0 - internal fun vectorSequence(): Sequence> = sequence { - val n = shape.size - val vectorOffset = shape[n - 1] - val vectorShape = intArrayOf(shape.last()) - for (offset in 0 until numel step vectorOffset) { - val vector = BufferedTensor(vectorShape, buffer, offset) - yield(vector) - } - } - - internal fun matrixSequence(): Sequence> = sequence { - check(shape.size >= 2) { "todo" } - val n = shape.size - val matrixOffset = shape[n - 1] * shape[n - 2] - val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) - for (offset in 0 until numel step matrixOffset) { - val matrix = BufferedTensor(matrixShape, buffer, offset) - yield(matrix) - } - } - - internal inline fun forEachVector(vectorAction: (BufferedTensor) -> Unit): Unit { - for (vector in vectorSequence()) { - vectorAction(vector) - } - } - - internal inline fun forEachMatrix(matrixAction: (BufferedTensor) -> Unit): Unit { - for (matrix in matrixSequence()) { - matrixAction(matrix) - } - } - } public class IntTensor internal constructor( diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 0d19fd3f6..b81cf0364 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -1,11 +1,8 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.nd.MutableStructure1D -import space.kscience.kmath.nd.MutableStructure2D +import space.kscience.kmath.tensors.LinearOpsTensorAlgebra import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D -import space.kscience.kmath.tensors.LinearOpsTensorAlgebra -import kotlin.math.sqrt public class DoubleLinearOpsTensorAlgebra : LinearOpsTensorAlgebra, @@ -15,48 +12,6 @@ public class DoubleLinearOpsTensorAlgebra : override fun DoubleTensor.det(): DoubleTensor = detLU() - private inline fun luHelper(lu: MutableStructure2D, pivots: MutableStructure1D, m: Int) { - for (row in 0 until m) pivots[row] = row - - for (i in 0 until m) { - var maxVal = -1.0 - var maxInd = i - - for (k in i until m) { - val absA = kotlin.math.abs(lu[k, i]) - if (absA > maxVal) { - maxVal = absA - maxInd = k - } - } - - //todo check singularity - - if (maxInd != i) { - - val j = pivots[i] - pivots[i] = pivots[maxInd] - pivots[maxInd] = j - - for (k in 0 until m) { - val tmp = lu[i, k] - lu[i, k] = lu[maxInd, k] - lu[maxInd, k] = tmp - } - - pivots[m] += 1 - - } - - for (j in i + 1 until m) { - lu[j, i] /= lu[i, i] - for (k in i + 1 until m) { - lu[j, k] -= lu[j, i] * lu[i, k] - } - } - } - } - override fun DoubleTensor.lu(): Pair { checkSquareMatrix(shape) @@ -80,37 +35,6 @@ public class DoubleLinearOpsTensorAlgebra : } - private inline fun pivInit( - p: MutableStructure2D, - pivot: MutableStructure1D, - n: Int - ) { - for (i in 0 until n) { - p[i, pivot[i]] = 1.0 - } - } - - private inline fun luPivotHelper( - l: MutableStructure2D, - u: MutableStructure2D, - lu: MutableStructure2D, - n: Int - ) { - for (i in 0 until n) { - for (j in 0 until n) { - if (i == j) { - l[i, j] = 1.0 - } - if (j < i) { - l[i, j] = lu[i, j] - } - if (j >= i) { - u[i, j] = lu[i, j] - } - } - } - } - override fun luPivot( luTensor: DoubleTensor, pivotsTensor: IntTensor @@ -139,27 +63,6 @@ public class DoubleLinearOpsTensorAlgebra : } - private inline fun choleskyHelper( - a: MutableStructure2D, - l: MutableStructure2D, - n: Int - ) { - for (i in 0 until n) { - for (j in 0 until i) { - var h = a[i, j] - for (k in 0 until j) { - h -= l[i, k] * l[j, k] - } - l[i, j] = h / l[j, j] - } - var h = a[i, i] - for (j in 0 until i) { - h -= l[i, j] * l[i, j] - } - l[i, i] = sqrt(h) - } - } - override fun DoubleTensor.cholesky(): DoubleTensor { // todo checks checkSquareMatrix(shape) @@ -185,14 +88,6 @@ public class DoubleLinearOpsTensorAlgebra : TODO("ANDREI") } - private fun luMatrixDet(luTensor: MutableStructure2D, pivotsTensor: MutableStructure1D): Double { - val lu = luTensor.as2D() - val pivots = pivotsTensor.as1D() - val m = lu.shape[0] - val sign = if ((pivots[m] - m) % 2 == 0) 1.0 else -1.0 - return (0 until m).asSequence().map { lu[it, it] }.fold(sign) { left, right -> left * right } - } - public fun DoubleTensor.detLU(): DoubleTensor { val (luTensor, pivotsTensor) = lu() val n = shape.size @@ -213,33 +108,6 @@ public class DoubleLinearOpsTensorAlgebra : return detTensor } - private fun luMatrixInv( - lu: MutableStructure2D, - pivots: MutableStructure1D, - invMatrix: MutableStructure2D - ) { - val m = lu.shape[0] - - for (j in 0 until m) { - for (i in 0 until m) { - if (pivots[i] == j) { - invMatrix[i, j] = 1.0 - } - - for (k in 0 until i) { - invMatrix[i, j] -= lu[i, k] * invMatrix[k, j] - } - } - - for (i in m - 1 downTo 0) { - for (k in i + 1 until m) { - invMatrix[i, j] -= lu[i, k] * invMatrix[k, j] - } - invMatrix[i, j] /= lu[i, i] - } - } - } - public fun DoubleTensor.invLU(): DoubleTensor { val (luTensor, pivotsTensor) = lu() val invTensor = luTensor.zeroesLike() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index b418f3647..c878fc58c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -1,8 +1,7 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.nd.MutableStructure2D -import space.kscience.kmath.nd.as2D import space.kscience.kmath.tensors.TensorPartialDivisionAlgebra +import space.kscience.kmath.nd.as2D import kotlin.math.abs public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { @@ -230,23 +229,6 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra, - b: MutableStructure2D, - res: MutableStructure2D, - l: Int, m: Int, n: Int - ) { - for (i in 0 until l) { - for (j in 0 until n) { - var curr = 0.0 - for (k in 0 until m) { - curr += a[i, k] * b[k, j] - } - res[i, j] = curr - } - } - } - override fun DoubleTensor.dot(other: DoubleTensor): DoubleTensor { if (this.shape.size == 1 && other.shape.size == 1) { return DoubleTensor(intArrayOf(1), doubleArrayOf(this.times(other).buffer.array().sum())) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt new file mode 100644 index 000000000..e78cc33c7 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt @@ -0,0 +1,188 @@ +package space.kscience.kmath.tensors.core + +import space.kscience.kmath.nd.MutableStructure1D +import space.kscience.kmath.nd.MutableStructure2D +import space.kscience.kmath.nd.as1D +import space.kscience.kmath.nd.as2D +import kotlin.math.sqrt + + +internal inline fun BufferedTensor.vectorSequence(): Sequence> = sequence { + val n = shape.size + val vectorOffset = shape[n - 1] + val vectorShape = intArrayOf(shape.last()) + for (offset in 0 until numel step vectorOffset) { + val vector = BufferedTensor(vectorShape, buffer, offset) + yield(vector) + } +} + +internal inline fun BufferedTensor.matrixSequence(): Sequence> = sequence { + check(shape.size >= 2) { "todo" } + val n = shape.size + val matrixOffset = shape[n - 1] * shape[n - 2] + val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) + for (offset in 0 until numel step matrixOffset) { + val matrix = BufferedTensor(matrixShape, buffer, offset) + yield(matrix) + } +} + +internal inline fun BufferedTensor.forEachVector(vectorAction: (BufferedTensor) -> Unit): Unit { + for (vector in vectorSequence()) { + vectorAction(vector) + } +} + +internal inline fun BufferedTensor.forEachMatrix(matrixAction: (BufferedTensor) -> Unit): Unit { + for (matrix in matrixSequence()) { + matrixAction(matrix) + } +} + + +internal inline fun dotHelper( + a: MutableStructure2D, + b: MutableStructure2D, + res: MutableStructure2D, + l: Int, m: Int, n: Int +) { + for (i in 0 until l) { + for (j in 0 until n) { + var curr = 0.0 + for (k in 0 until m) { + curr += a[i, k] * b[k, j] + } + res[i, j] = curr + } + } +} + +internal inline fun luHelper(lu: MutableStructure2D, pivots: MutableStructure1D, m: Int) { + for (row in 0 until m) pivots[row] = row + + for (i in 0 until m) { + var maxVal = -1.0 + var maxInd = i + + for (k in i until m) { + val absA = kotlin.math.abs(lu[k, i]) + if (absA > maxVal) { + maxVal = absA + maxInd = k + } + } + + //todo check singularity + + if (maxInd != i) { + + val j = pivots[i] + pivots[i] = pivots[maxInd] + pivots[maxInd] = j + + for (k in 0 until m) { + val tmp = lu[i, k] + lu[i, k] = lu[maxInd, k] + lu[maxInd, k] = tmp + } + + pivots[m] += 1 + + } + + for (j in i + 1 until m) { + lu[j, i] /= lu[i, i] + for (k in i + 1 until m) { + lu[j, k] -= lu[j, i] * lu[i, k] + } + } + } +} + +internal inline fun pivInit( + p: MutableStructure2D, + pivot: MutableStructure1D, + n: Int +) { + for (i in 0 until n) { + p[i, pivot[i]] = 1.0 + } +} + +internal inline fun luPivotHelper( + l: MutableStructure2D, + u: MutableStructure2D, + lu: MutableStructure2D, + n: Int +) { + for (i in 0 until n) { + for (j in 0 until n) { + if (i == j) { + l[i, j] = 1.0 + } + if (j < i) { + l[i, j] = lu[i, j] + } + if (j >= i) { + u[i, j] = lu[i, j] + } + } + } +} + +internal inline fun choleskyHelper( + a: MutableStructure2D, + l: MutableStructure2D, + n: Int +) { + for (i in 0 until n) { + for (j in 0 until i) { + var h = a[i, j] + for (k in 0 until j) { + h -= l[i, k] * l[j, k] + } + l[i, j] = h / l[j, j] + } + var h = a[i, i] + for (j in 0 until i) { + h -= l[i, j] * l[i, j] + } + l[i, i] = sqrt(h) + } +} + +internal inline fun luMatrixDet(luTensor: MutableStructure2D, pivotsTensor: MutableStructure1D): Double { + val lu = luTensor.as2D() + val pivots = pivotsTensor.as1D() + val m = lu.shape[0] + val sign = if ((pivots[m] - m) % 2 == 0) 1.0 else -1.0 + return (0 until m).asSequence().map { lu[it, it] }.fold(sign) { left, right -> left * right } +} + +internal inline fun luMatrixInv( + lu: MutableStructure2D, + pivots: MutableStructure1D, + invMatrix: MutableStructure2D +) { + val m = lu.shape[0] + + for (j in 0 until m) { + for (i in 0 until m) { + if (pivots[i] == j) { + invMatrix[i, j] = 1.0 + } + + for (k in 0 until i) { + invMatrix[i, j] -= lu[i, k] * invMatrix[k, j] + } + } + + for (i in m - 1 downTo 0) { + for (k in i + 1 until m) { + invMatrix[i, j] -= lu[i, k] * invMatrix[k, j] + } + invMatrix[i, j] /= lu[i, i] + } + } +} From 2503d35ba8629055aaffc03f6b2e12e2030d7dd3 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Tue, 30 Mar 2021 14:53:19 +0300 Subject: [PATCH 073/178] complete qr + test qr and lu --- .../core/DoubleLinearOpsTensorAlgebra.kt | 51 +++++++++++++++++-- .../core/TestDoubleLinearOpsAlgebra.kt | 46 +++++++++++++++++ 2 files changed, 92 insertions(+), 5 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 1558e6af9..59ec944f2 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -118,7 +118,8 @@ public class DoubleLinearOpsTensorAlgebra : //todo checks checkSquareMatrix(luTensor.shape) check( - luTensor.shape.dropLast(1).toIntArray() contentEquals pivotsTensor.shape + luTensor.shape.dropLast(2).toIntArray() contentEquals pivotsTensor.shape.dropLast(1).toIntArray() || + luTensor.shape.last() == pivotsTensor.shape.last() - 1 ) { "Bed shapes ((" } //todo rewrite val n = luTensor.shape.last() @@ -173,16 +174,56 @@ public class DoubleLinearOpsTensorAlgebra : return lTensor } - private fun matrixQR( - matrix: Structure2D, + private fun MutableStructure1D.dot(other: MutableStructure1D): Double { + var res = 0.0 + for (i in 0 until size) { + res += this[i] * other[i] + } + return res + } + + private fun MutableStructure1D.l2Norm(): Double { + var squareSum = 0.0 + for (i in 0 until size) { + squareSum += this[i] * this[i] + } + return sqrt(squareSum) + } + + fun qrHelper( + matrix: MutableStructure2D, q: MutableStructure2D, r: MutableStructure2D ) { - + //todo check square + val n = matrix.colNum + for (j in 0 until n) { + val v = matrix.columns[j] + if (j > 0) { + for (i in 0 until j) { + r[i, j] = q.columns[i].dot(matrix.columns[j]) + for (k in 0 until n) { + v[k] = v[k] - r[i, j] * q.columns[i][k] + } + } + } + r[j, j] = v.l2Norm() + for (i in 0 until n) { + q[i, j] = v[i] / r[j, j] + } + } } override fun DoubleTensor.qr(): Pair { - TODO("ANDREI") + checkSquareMatrix(shape) + val qTensor = zeroesLike() + val rTensor = zeroesLike() + val seq = matrixSequence().zip((qTensor.matrixSequence().zip(rTensor.matrixSequence()))) + for ((matrix, qr) in seq) { + val (q, r) = qr + qrHelper(matrix.as2D(), q.as2D(), r.as2D()) + } + return Pair(qTensor, rTensor) } override fun DoubleTensor.svd(): Triple { diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index d2d4ffb67..b79c54dd1 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -76,4 +76,50 @@ class TestDoubleLinearOpsTensorAlgebra { val b = fromArray(intArrayOf(3), doubleArrayOf(5.5, 2.6, 6.4)) assertEquals(a.dot(b).value(), 59.92) } + + @Test + fun testQR() = DoubleLinearOpsTensorAlgebra { + val shape = intArrayOf(2, 2, 2) + val buffer = doubleArrayOf( + 1.0, 3.0, + 1.0, 2.0, + 1.5, 1.0, + 10.0, 2.0 + ) + + val tensor = fromArray(shape, buffer) + + val (q, r) = tensor.qr() + + assertTrue { q.shape contentEquals shape } + assertTrue { r.shape contentEquals shape } + + assertTrue { q.dot(r).buffer.array().epsEqual(buffer) } + + //todo check orthogonality/upper triang. + } + + @Test + fun testLU() = DoubleLinearOpsTensorAlgebra { + val shape = intArrayOf(2, 2, 2) + val buffer = doubleArrayOf( + 1.0, 3.0, + 1.0, 2.0, + 1.5, 1.0, + 10.0, 2.0 + ) + val tensor = fromArray(shape, buffer) + + val (lu, pivots) = tensor.lu() + + // todo check lu + + val (p, l, u) = luPivot(lu, pivots) + + assertTrue { p.shape contentEquals shape } + assertTrue { l.shape contentEquals shape } + assertTrue { u.shape contentEquals shape } + + assertTrue { p.dot(tensor).buffer.array().epsEqual(l.dot(u).buffer.array()) } + } } From 139534fdb343b984c94f5bc089df34b9e1d5946b Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Tue, 30 Mar 2021 15:13:45 +0300 Subject: [PATCH 074/178] fix --- .../kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 59ec944f2..6be50e710 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -183,11 +183,7 @@ public class DoubleLinearOpsTensorAlgebra : } private fun MutableStructure1D.l2Norm(): Double { - var squareSum = 0.0 - for (i in 0 until size) { - squareSum += this[i] * this[i] - } - return sqrt(squareSum) + return sqrt((0 until size).sumOf { this[it] * this[it] }) } fun qrHelper( @@ -223,7 +219,7 @@ public class DoubleLinearOpsTensorAlgebra : val (q, r) = qr qrHelper(matrix.as2D(), q.as2D(), r.as2D()) } - return Pair(qTensor, rTensor) + return qTensor to rTensor } override fun DoubleTensor.svd(): Triple { From 370bab462cae6d883677d0ed5cda7e0b885caa96 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 30 Mar 2021 13:14:09 +0100 Subject: [PATCH 075/178] merged pull request --- .../core/DoubleLinearOpsTensorAlgebra.kt | 40 ------------------- .../kscience/kmath/tensors/core/linutils.kt | 40 +++++++++++++++++++ 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 46ab5f80f..13fb18c01 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -77,46 +77,6 @@ public class DoubleLinearOpsTensorAlgebra : return lTensor } - private fun MutableStructure1D.dot(other: MutableStructure1D): Double { - var res = 0.0 - for (i in 0 until size) { - res += this[i] * other[i] - } - return res - } - - private fun MutableStructure1D.l2Norm(): Double { - var squareSum = 0.0 - for (i in 0 until size) { - squareSum += this[i] * this[i] - } - return sqrt(squareSum) - } - - fun qrHelper( - matrix: MutableStructure2D, - q: MutableStructure2D, - r: MutableStructure2D - ) { - //todo check square - val n = matrix.colNum - for (j in 0 until n) { - val v = matrix.columns[j] - if (j > 0) { - for (i in 0 until j) { - r[i, j] = q.columns[i].dot(matrix.columns[j]) - for (k in 0 until n) { - v[k] = v[k] - r[i, j] * q.columns[i][k] - } - } - } - r[j, j] = v.l2Norm() - for (i in 0 until n) { - q[i, j] = v[i] / r[j, j] - } - } - } - override fun DoubleTensor.qr(): Pair { checkSquareMatrix(shape) val qTensor = zeroesLike() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt index e78cc33c7..49a4384c2 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt @@ -186,3 +186,43 @@ internal inline fun luMatrixInv( } } } + +internal inline fun MutableStructure1D.dot(other: MutableStructure1D): Double { + var res = 0.0 + for (i in 0 until size) { + res += this[i] * other[i] + } + return res +} + +internal inline fun MutableStructure1D.l2Norm(): Double { + var squareSum = 0.0 + for (i in 0 until size) { + squareSum += this[i] * this[i] + } + return sqrt(squareSum) +} + +internal inline fun qrHelper( + matrix: MutableStructure2D, + q: MutableStructure2D, + r: MutableStructure2D +) { + //todo check square + val n = matrix.colNum + for (j in 0 until n) { + val v = matrix.columns[j] + if (j > 0) { + for (i in 0 until j) { + r[i, j] = q.columns[i].dot(matrix.columns[j]) + for (k in 0 until n) { + v[k] = v[k] - r[i, j] * q.columns[i][k] + } + } + } + r[j, j] = v.l2Norm() + for (i in 0 until n) { + q[i, j] = v[i] / r[j, j] + } + } +} From 581c13c573179dd9b2b67e65a4a2c84047ed9171 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 30 Mar 2021 14:14:05 +0100 Subject: [PATCH 076/178] drop code duplication --- kmath-core/api/kmath-core.api | 6 +-- .../core/DoubleLinearOpsTensorAlgebra.kt | 2 +- .../kscience/kmath/tensors/core/linutils.kt | 42 +++++++------------ 3 files changed, 20 insertions(+), 30 deletions(-) diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index 373920204..634f38bed 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -2645,7 +2645,7 @@ public abstract interface class space/kscience/kmath/tensors/LinearOpsTensorAlge public abstract fun inv (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun lu (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Pair; public abstract fun luPivot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; - public abstract fun qr (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; + public abstract fun qr (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Pair; public abstract fun svd (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; public abstract fun symEig (Lspace/kscience/kmath/nd/MutableStructureND;Z)Lkotlin/Pair; } @@ -2794,8 +2794,8 @@ public final class space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebr public fun lu (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lkotlin/Pair; public synthetic fun luPivot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; public fun luPivot (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/IntTensor;)Lkotlin/Triple; - public synthetic fun qr (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun qr (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public synthetic fun qr (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Pair; + public fun qr (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lkotlin/Pair; public synthetic fun svd (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; public fun svd (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lkotlin/Triple; public synthetic fun symEig (Lspace/kscience/kmath/nd/MutableStructureND;Z)Lkotlin/Pair; diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 13fb18c01..3d2d21e0c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -84,7 +84,7 @@ public class DoubleLinearOpsTensorAlgebra : val seq = matrixSequence().zip((qTensor.matrixSequence().zip(rTensor.matrixSequence()))) for ((matrix, qr) in seq) { val (q, r) = qr - qrHelper(matrix.as2D(), q.as2D(), r.as2D()) + qrHelper(matrix.asTensor(), q.asTensor(), r.as2D()) } return Pair(qTensor, rTensor) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt index 49a4384c2..4067de5f4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt @@ -187,42 +187,32 @@ internal inline fun luMatrixInv( } } -internal inline fun MutableStructure1D.dot(other: MutableStructure1D): Double { - var res = 0.0 - for (i in 0 until size) { - res += this[i] * other[i] - } - return res -} - -internal inline fun MutableStructure1D.l2Norm(): Double { - var squareSum = 0.0 - for (i in 0 until size) { - squareSum += this[i] * this[i] - } - return sqrt(squareSum) -} - -internal inline fun qrHelper( - matrix: MutableStructure2D, - q: MutableStructure2D, +internal inline fun DoubleLinearOpsTensorAlgebra.qrHelper( + matrix: DoubleTensor, + q: DoubleTensor, r: MutableStructure2D ) { - //todo check square - val n = matrix.colNum + checkSquareMatrix(matrix.shape) + val n = matrix.shape[0] + val qM = q.as2D() + val matrixT = matrix.transpose(0,1) + val qT = q.transpose(0,1) + for (j in 0 until n) { - val v = matrix.columns[j] + val v = matrixT[j] + val vv = v.as1D() if (j > 0) { for (i in 0 until j) { - r[i, j] = q.columns[i].dot(matrix.columns[j]) + r[i, j] = qT[i].dot(matrixT[j]).value() for (k in 0 until n) { - v[k] = v[k] - r[i, j] * q.columns[i][k] + val qTi = qT[i].as1D() + vv[k] = vv[k] - r[i, j] * qTi[k] } } } - r[j, j] = v.l2Norm() + r[j, j] = DoubleAnalyticTensorAlgebra { v.dot(v).sqrt().value() } for (i in 0 until n) { - q[i, j] = v[i] / r[j, j] + qM[i, j] = vv[i] / r[j, j] } } } From 03455a3bebc617e09392e6da7ac361040babf67a Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 30 Mar 2021 14:36:59 +0100 Subject: [PATCH 077/178] infix dot forgotten --- .../space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt | 2 +- .../kotlin/space/kscience/kmath/tensors/core/linutils.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index c878fc58c..965aef1ea 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -229,7 +229,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra 0) { for (i in 0 until j) { - r[i, j] = qT[i].dot(matrixT[j]).value() + r[i, j] = (qT[i] dot matrixT[j]).value() for (k in 0 until n) { val qTi = qT[i].as1D() vv[k] = vv[k] - r[i, j] * qTi[k] } } } - r[j, j] = DoubleAnalyticTensorAlgebra { v.dot(v).sqrt().value() } + r[j, j] = DoubleAnalyticTensorAlgebra { (v dot v).sqrt().value() } for (i in 0 until n) { qM[i, j] = vv[i] / r[j, j] } From b5d3ca76db28552aa534f04813234047b2b6a9ae Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 30 Mar 2021 19:20:20 +0100 Subject: [PATCH 078/178] Dropping creation methods from interface --- .../kscience/kmath/tensors/TensorAlgebra.kt | 21 ------------------- .../tensors/TensorPartialDivisionAlgebra.kt | 2 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 18 ++++++++-------- .../kscience/kmath/tensors/core/utils.kt | 8 ++++++- 4 files changed, 17 insertions(+), 32 deletions(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index 5b7515b20..d7c6eaefd 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -1,29 +1,10 @@ package space.kscience.kmath.tensors -import space.kscience.kmath.tensors.core.DoubleTensor - // https://proofwiki.org/wiki/Definition:Algebra_over_Ring public interface TensorAlgebra> { public fun TensorType.value(): T - //https://pytorch.org/docs/stable/generated/torch.full.html - public fun full(value: T, shape: IntArray): TensorType - - public fun ones(shape: IntArray): TensorType - public fun zeros(shape: IntArray): TensorType - - //https://pytorch.org/docs/stable/generated/torch.full_like.html#torch.full_like - public fun TensorType.fullLike(value: T): TensorType - - public fun TensorType.zeroesLike(): TensorType - public fun TensorType.onesLike(): TensorType - - //https://pytorch.org/docs/stable/generated/torch.eye.html - public fun eye(n: Int): TensorType - - public fun TensorType.copy(): TensorType - public operator fun T.plus(other: TensorType): TensorType public operator fun TensorType.plus(value: T): TensorType public operator fun TensorType.plus(other: TensorType): TensorType @@ -53,8 +34,6 @@ public interface TensorAlgebra> { public fun TensorType.view(shape: IntArray): TensorType public fun TensorType.viewAs(other: TensorType): TensorType - public fun TensorType.eq(other: TensorType, delta: T): Boolean - //https://pytorch.org/docs/stable/generated/torch.matmul.html public infix fun TensorType.dot(other: TensorType): TensorType diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt index 67b9c9d73..0b9079967 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt @@ -2,7 +2,7 @@ package space.kscience.kmath.tensors // https://proofwiki.org/wiki/Definition:Division_Algebra public interface TensorPartialDivisionAlgebra> : - TensorAlgebra { + TensorAlgebra { public operator fun TensorType.div(value: T): TensorType public operator fun TensorType.div(other: TensorType): TensorType public operator fun TensorType.divAssign(value: T) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 965aef1ea..323ade45d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -27,27 +27,27 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra abs(x - y) < delta } } - override fun DoubleTensor.eq(other: DoubleTensor, delta: Double): Boolean { + public fun DoubleTensor.eq(other: DoubleTensor, delta: Double): Boolean { return this.eq(other) { x, y -> abs(x - y) < delta } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index 591ebb89c..33e78db33 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -1,7 +1,8 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.structures.* - +import kotlin.random.Random +import kotlin.math.* /** * Returns a reference to [IntArray] containing all of the elements of this [Buffer]. @@ -34,3 +35,8 @@ internal fun Buffer.array(): DoubleArray = when (this) { is DoubleBuffer -> array else -> throw RuntimeException("Failed to cast Buffer to DoubleArray") } + +internal inline fun getRandomNormals(n: Int, seed: Long): DoubleArray { + val u = Random(seed) + return (0 until n).map { sqrt(-2.0 * u.nextDouble()) * cos(2.0 * PI * u.nextDouble()) }.toDoubleArray() +} From 07b6f988c296592cc28c93de12009fced255f43d Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 30 Mar 2021 19:31:42 +0100 Subject: [PATCH 079/178] forgot ln --- .../kotlin/space/kscience/kmath/tensors/core/utils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index 33e78db33..d8a073d64 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -38,5 +38,5 @@ internal fun Buffer.array(): DoubleArray = when (this) { internal inline fun getRandomNormals(n: Int, seed: Long): DoubleArray { val u = Random(seed) - return (0 until n).map { sqrt(-2.0 * u.nextDouble()) * cos(2.0 * PI * u.nextDouble()) }.toDoubleArray() + return (0 until n).map { sqrt(-2.0 * ln(u.nextDouble())) * cos(2.0 * PI * u.nextDouble()) }.toDoubleArray() } From 6305acea68a8b34e9ddd01b7daf1711f17829151 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 31 Mar 2021 08:32:53 +0100 Subject: [PATCH 080/178] API dump --- kmath-core/api/kmath-core.api | 36 +++++++++-------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index 634f38bed..f0e749d2b 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -2655,21 +2655,14 @@ public final class space/kscience/kmath/tensors/LinearOpsTensorAlgebra$DefaultIm } public abstract interface class space/kscience/kmath/tensors/TensorAlgebra { - public abstract fun copy (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun diagonalEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;III)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun dot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun eq (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Z - public abstract fun eye (I)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun full (Ljava/lang/Object;[I)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun fullLike (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun get (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun minus (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun minus (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V public abstract fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public abstract fun ones ([I)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun onesLike (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun plus (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun plus (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun plus (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; @@ -2685,8 +2678,6 @@ public abstract interface class space/kscience/kmath/tensors/TensorAlgebra { public abstract fun value (Lspace/kscience/kmath/nd/MutableStructureND;)Ljava/lang/Object; public abstract fun view (Lspace/kscience/kmath/nd/MutableStructureND;[I)Lspace/kscience/kmath/nd/MutableStructureND; public abstract fun viewAs (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun zeroesLike (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun zeros ([I)Lspace/kscience/kmath/nd/MutableStructureND; } public final class space/kscience/kmath/tensors/TensorAlgebra$DefaultImpls { @@ -2814,8 +2805,7 @@ public class space/kscience/kmath/tensors/core/DoubleTensorAlgebra : space/kscie public final fun contentEquals (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Z public final fun contentEquals (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lkotlin/jvm/functions/Function2;)Z public static synthetic fun contentEquals$default (Lspace/kscience/kmath/tensors/core/DoubleTensorAlgebra;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;DILjava/lang/Object;)Z - public synthetic fun copy (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun copy (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public final fun copy (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun diagonalEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;III)Lspace/kscience/kmath/nd/MutableStructureND; public fun diagonalEmbedding (Lspace/kscience/kmath/tensors/core/DoubleTensor;III)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun div (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; @@ -2828,16 +2818,12 @@ public class space/kscience/kmath/tensors/core/DoubleTensorAlgebra : space/kscie public fun divAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V public synthetic fun dot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun dot (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun eq (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Z public final fun eq (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Z - public fun eq (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Z - public synthetic fun eye (I)Lspace/kscience/kmath/nd/MutableStructureND; - public fun eye (I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public final fun eq (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Z + public final fun eye (I)Lspace/kscience/kmath/tensors/core/DoubleTensor; public final fun fromArray ([I[D)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public fun full (D[I)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun full (Ljava/lang/Object;[I)Lspace/kscience/kmath/nd/MutableStructureND; - public synthetic fun fullLike (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun fullLike (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public final fun full (D[I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public final fun fullLike (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun get (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; public fun get (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; public final fun map (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/tensors/core/DoubleTensor; @@ -2851,10 +2837,8 @@ public class space/kscience/kmath/tensors/core/DoubleTensorAlgebra : space/kscie public synthetic fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V public fun minusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)V public fun minusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V - public synthetic fun ones ([I)Lspace/kscience/kmath/nd/MutableStructureND; - public fun ones ([I)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun onesLike (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun onesLike (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public final fun ones ([I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public final fun onesLike (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public fun plus (DLspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun plus (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public synthetic fun plus (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; @@ -2885,10 +2869,8 @@ public class space/kscience/kmath/tensors/core/DoubleTensorAlgebra : space/kscie public fun view (Lspace/kscience/kmath/tensors/core/DoubleTensor;[I)Lspace/kscience/kmath/tensors/core/DoubleTensor; public synthetic fun viewAs (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; public fun viewAs (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun zeroesLike (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun zeroesLike (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun zeros ([I)Lspace/kscience/kmath/nd/MutableStructureND; - public fun zeros ([I)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public final fun zeroesLike (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; + public final fun zeros ([I)Lspace/kscience/kmath/tensors/core/DoubleTensor; } public final class space/kscience/kmath/tensors/core/DoubleTensorAlgebraKt { From 5abd63cde28fcf63e72809799b10211647adb73b Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 31 Mar 2021 09:07:45 +0100 Subject: [PATCH 081/178] moving to kmath-tensors module --- kmath-core/api/kmath-core.api | 278 ------------------ kmath-tensors/build.gradle.kts | 16 + .../kmath/tensors/AnalyticTensorAlgebra.kt | 0 .../kmath/tensors/LinearOpsTensorAlgebra.kt | 0 .../kscience/kmath/tensors/TensorAlgebra.kt | 0 .../tensors/TensorPartialDivisionAlgebra.kt | 0 .../kscience/kmath/tensors/TensorStructure.kt | 0 .../core/BroadcastDoubleTensorAlgebra.kt | 0 .../kmath/tensors/core/BufferedTensor.kt | 0 .../core/DoubleAnalyticTensorAlgebra.kt | 0 .../core/DoubleLinearOpsTensorAlgebra.kt | 0 .../kmath/tensors/core/DoubleTensorAlgebra.kt | 0 .../tensors/core/TensorLinearStructure.kt | 0 .../kscience/kmath/tensors/core/checks.kt | 0 .../kscience/kmath/tensors/core/linutils.kt | 0 .../kscience/kmath/tensors/core/utils.kt | 0 .../kmath/tensors/core/TestBroadcasting.kt | 0 .../core/TestDoubleAnalyticTensorAlgebra.kt | 0 .../core/TestDoubleLinearOpsAlgebra.kt | 0 .../kmath/tensors/core/TestDoubleTensor.kt | 0 .../tensors/core/TestDoubleTensorAlgebra.kt | 0 settings.gradle.kts | 1 + 22 files changed, 17 insertions(+), 278 deletions(-) create mode 100644 kmath-tensors/build.gradle.kts rename {kmath-core => kmath-tensors}/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt (100%) rename {kmath-core => kmath-tensors}/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt (100%) rename {kmath-core => kmath-tensors}/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt (100%) rename {kmath-core => kmath-tensors}/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt (100%) rename {kmath-core => kmath-tensors}/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt (100%) rename {kmath-core => kmath-tensors}/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt (100%) rename {kmath-core => kmath-tensors}/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt (100%) rename {kmath-core => kmath-tensors}/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt (100%) rename {kmath-core => kmath-tensors}/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt (100%) rename {kmath-core => kmath-tensors}/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt (100%) rename {kmath-core => kmath-tensors}/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt (100%) rename {kmath-core => kmath-tensors}/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt (100%) rename {kmath-core => kmath-tensors}/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt (100%) rename {kmath-core => kmath-tensors}/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt (100%) rename {kmath-core => kmath-tensors}/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt (100%) rename {kmath-core => kmath-tensors}/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt (100%) rename {kmath-core => kmath-tensors}/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt (100%) rename {kmath-core => kmath-tensors}/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt (100%) rename {kmath-core => kmath-tensors}/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt (100%) diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index cc6c93c20..fee874b12 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -2602,281 +2602,3 @@ public final class space/kscience/kmath/structures/VirtualMutableBuffer : space/ public fun set (ILjava/lang/Object;)V } -public abstract interface class space/kscience/kmath/tensors/AnalyticTensorAlgebra : space/kscience/kmath/tensors/TensorPartialDivisionAlgebra { - public abstract fun acos (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun acosh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun asin (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun asinh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun atan (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun atanh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun ceil (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun cos (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun cosh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun exp (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun floor (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun log (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun sin (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun sinh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun sqrt (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun tan (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun tanh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; -} - -public abstract interface class space/kscience/kmath/tensors/LinearOpsTensorAlgebra : space/kscience/kmath/tensors/TensorPartialDivisionAlgebra { - public abstract fun cholesky (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun det (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun inv (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun lu (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Pair; - public abstract fun luPivot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; - public abstract fun qr (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Pair; - public abstract fun svd (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; - public abstract fun symEig (Lspace/kscience/kmath/nd/MutableStructureND;Z)Lkotlin/Pair; -} - -public final class space/kscience/kmath/tensors/LinearOpsTensorAlgebra$DefaultImpls { - public static synthetic fun symEig$default (Lspace/kscience/kmath/tensors/LinearOpsTensorAlgebra;Lspace/kscience/kmath/nd/MutableStructureND;ZILjava/lang/Object;)Lkotlin/Pair; -} - -public abstract interface class space/kscience/kmath/tensors/TensorAlgebra { - public abstract fun diagonalEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;III)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun dot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun get (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun minus (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun minus (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V - public abstract fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public abstract fun plus (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun plus (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun plus (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V - public abstract fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public abstract fun times (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun times (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun times (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun timesAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V - public abstract fun timesAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public abstract fun transpose (Lspace/kscience/kmath/nd/MutableStructureND;II)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun unaryMinus (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun value (Lspace/kscience/kmath/nd/MutableStructureND;)Ljava/lang/Object; - public abstract fun view (Lspace/kscience/kmath/nd/MutableStructureND;[I)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun viewAs (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; -} - -public final class space/kscience/kmath/tensors/TensorAlgebra$DefaultImpls { - public static synthetic fun diagonalEmbedding$default (Lspace/kscience/kmath/tensors/TensorAlgebra;Lspace/kscience/kmath/nd/MutableStructureND;IIIILjava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; -} - -public abstract interface class space/kscience/kmath/tensors/TensorPartialDivisionAlgebra : space/kscience/kmath/tensors/TensorAlgebra { - public abstract fun div (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun div (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public abstract fun divAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V - public abstract fun divAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V -} - -public final class space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra : space/kscience/kmath/tensors/core/DoubleTensorAlgebra { - public fun ()V - public synthetic fun div (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun div (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun divAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public fun divAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V - public synthetic fun minus (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun minus (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public fun minusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V - public synthetic fun plus (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun plus (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public fun plusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V - public synthetic fun times (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun times (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun timesAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public fun timesAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V -} - -public final class space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebraKt { - public static final fun BroadcastDoubleTensorAlgebra (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; -} - -public class space/kscience/kmath/tensors/core/BufferedTensor : space/kscience/kmath/nd/MutableStructureND { - public fun ([ILspace/kscience/kmath/structures/MutableBuffer;I)V - public fun elements ()Lkotlin/sequences/Sequence; - public fun equals (Ljava/lang/Object;)Z - public fun get ([I)Ljava/lang/Object; - public final fun getBuffer ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun getDimension ()I - public final fun getLinearStructure ()Lspace/kscience/kmath/tensors/core/TensorLinearStructure; - public final fun getNumel ()I - public fun getShape ()[I - public fun hashCode ()I - public fun set ([ILjava/lang/Object;)V -} - -public final class space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra : space/kscience/kmath/tensors/core/DoubleTensorAlgebra, space/kscience/kmath/tensors/AnalyticTensorAlgebra { - public fun ()V - public synthetic fun acos (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun acos (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun acosh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun acosh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun asin (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun asin (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun asinh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun asinh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun atan (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun atan (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun atanh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun atanh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun ceil (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun ceil (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun cos (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun cos (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun cosh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun cosh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun exp (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun exp (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun floor (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun floor (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun log (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun log (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun sin (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun sin (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun sinh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun sinh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun sqrt (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun sqrt (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun tan (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun tan (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun tanh (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun tanh (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; -} - -public final class space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebraKt { - public static final fun DoubleAnalyticTensorAlgebra (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra : space/kscience/kmath/tensors/core/DoubleTensorAlgebra, space/kscience/kmath/tensors/LinearOpsTensorAlgebra { - public fun ()V - public synthetic fun cholesky (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun cholesky (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun det (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun det (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public final fun detLU (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun inv (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun inv (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public final fun invLU (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun lu (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Pair; - public fun lu (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lkotlin/Pair; - public synthetic fun luPivot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; - public fun luPivot (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/IntTensor;)Lkotlin/Triple; - public synthetic fun qr (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Pair; - public fun qr (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lkotlin/Pair; - public synthetic fun svd (Lspace/kscience/kmath/nd/MutableStructureND;)Lkotlin/Triple; - public fun svd (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lkotlin/Triple; - public synthetic fun symEig (Lspace/kscience/kmath/nd/MutableStructureND;Z)Lkotlin/Pair; - public fun symEig (Lspace/kscience/kmath/tensors/core/DoubleTensor;Z)Lkotlin/Pair; -} - -public final class space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebraKt { - public static final fun DoubleLinearOpsTensorAlgebra (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/tensors/core/DoubleTensor : space/kscience/kmath/tensors/core/BufferedTensor { -} - -public class space/kscience/kmath/tensors/core/DoubleTensorAlgebra : space/kscience/kmath/tensors/TensorPartialDivisionAlgebra { - public fun ()V - public final fun contentEquals (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Z - public final fun contentEquals (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lkotlin/jvm/functions/Function2;)Z - public static synthetic fun contentEquals$default (Lspace/kscience/kmath/tensors/core/DoubleTensorAlgebra;Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;DILjava/lang/Object;)Z - public final fun copy (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun diagonalEmbedding (Lspace/kscience/kmath/nd/MutableStructureND;III)Lspace/kscience/kmath/nd/MutableStructureND; - public fun diagonalEmbedding (Lspace/kscience/kmath/tensors/core/DoubleTensor;III)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun div (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public synthetic fun div (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun div (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public fun div (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun divAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V - public synthetic fun divAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public fun divAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)V - public fun divAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V - public synthetic fun dot (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun dot (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public final fun eq (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Z - public final fun eq (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Z - public final fun eye (I)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public final fun fromArray ([I[D)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public final fun full (D[I)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public final fun fullLike (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun get (Lspace/kscience/kmath/nd/MutableStructureND;I)Lspace/kscience/kmath/nd/MutableStructureND; - public fun get (Lspace/kscience/kmath/tensors/core/DoubleTensor;I)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public final fun map (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public fun minus (DLspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public synthetic fun minus (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public synthetic fun minus (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun minus (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public fun minus (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V - public synthetic fun minusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public fun minusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)V - public fun minusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V - public final fun ones ([I)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public final fun onesLike (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public fun plus (DLspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun plus (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public synthetic fun plus (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public synthetic fun plus (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun plus (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public fun plus (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V - public synthetic fun plusAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public fun plusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)V - public fun plusAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V - public fun times (DLspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun times (Ljava/lang/Object;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public synthetic fun times (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/MutableStructureND; - public synthetic fun times (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun times (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public fun times (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun timesAssign (Lspace/kscience/kmath/nd/MutableStructureND;Ljava/lang/Object;)V - public synthetic fun timesAssign (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)V - public fun timesAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;D)V - public fun timesAssign (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)V - public synthetic fun transpose (Lspace/kscience/kmath/nd/MutableStructureND;II)Lspace/kscience/kmath/nd/MutableStructureND; - public fun transpose (Lspace/kscience/kmath/tensors/core/DoubleTensor;II)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun unaryMinus (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun unaryMinus (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun value (Lspace/kscience/kmath/nd/MutableStructureND;)Ljava/lang/Object; - public fun value (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Ljava/lang/Double; - public synthetic fun view (Lspace/kscience/kmath/nd/MutableStructureND;[I)Lspace/kscience/kmath/nd/MutableStructureND; - public fun view (Lspace/kscience/kmath/tensors/core/DoubleTensor;[I)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public synthetic fun viewAs (Lspace/kscience/kmath/nd/MutableStructureND;Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructureND; - public fun viewAs (Lspace/kscience/kmath/tensors/core/DoubleTensor;Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public final fun zeroesLike (Lspace/kscience/kmath/tensors/core/DoubleTensor;)Lspace/kscience/kmath/tensors/core/DoubleTensor; - public final fun zeros ([I)Lspace/kscience/kmath/tensors/core/DoubleTensor; -} - -public final class space/kscience/kmath/tensors/core/DoubleTensorAlgebraKt { - public static final fun DoubleTensorAlgebra (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/tensors/core/FloatTensor : space/kscience/kmath/tensors/core/BufferedTensor { -} - -public final class space/kscience/kmath/tensors/core/IntTensor : space/kscience/kmath/tensors/core/BufferedTensor { -} - -public final class space/kscience/kmath/tensors/core/LongTensor : space/kscience/kmath/tensors/core/BufferedTensor { -} - -public final class space/kscience/kmath/tensors/core/TensorLinearStructure { - public fun ([I)V - public final fun getShape ()[I - public final fun getSize ()I - public final fun getStrides ()[I - public final fun index (I)[I - public final fun indices ()Lkotlin/sequences/Sequence; - public final fun offset ([I)I - public final fun stepIndex ([I)[I -} - diff --git a/kmath-tensors/build.gradle.kts b/kmath-tensors/build.gradle.kts new file mode 100644 index 000000000..8e823416b --- /dev/null +++ b/kmath-tensors/build.gradle.kts @@ -0,0 +1,16 @@ +plugins { + id("ru.mipt.npm.gradle.mpp") +} + +kotlin.sourceSets { + commonMain { + dependencies { + api(project(":kmath-core")) + api(project(":kmath-stat")) + } + } +} + +readme { + maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt similarity index 100% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt similarity index 100% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt similarity index 100% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt similarity index 100% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt similarity index 100% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt similarity index 100% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt similarity index 100% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt similarity index 100% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt similarity index 100% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt similarity index 100% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt similarity index 100% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt similarity index 100% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt similarity index 100% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt similarity index 100% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt similarity index 100% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt rename to kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt similarity index 100% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt rename to kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt similarity index 100% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt rename to kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt similarity index 100% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt rename to kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt similarity index 100% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt rename to kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index 4467d5ed6..ffc93d576 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -40,5 +40,6 @@ include( ":kmath-ast", ":kmath-ejml", ":kmath-kotlingrad", + ":kmath-tensors", ":examples" ) From 706a44fd3300f050115e4b40042fe32046b181e0 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 31 Mar 2021 09:15:55 +0100 Subject: [PATCH 082/178] get normals TBD --- .../space/kscience/kmath/tensors/core/utils.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index d8a073d64..e46d39cf2 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -1,5 +1,7 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.stat.RandomGenerator +import space.kscience.kmath.stat.samplers.BoxMullerNormalizedGaussianSampler import space.kscience.kmath.structures.* import kotlin.random.Random import kotlin.math.* @@ -35,8 +37,10 @@ internal fun Buffer.array(): DoubleArray = when (this) { is DoubleBuffer -> array else -> throw RuntimeException("Failed to cast Buffer to DoubleArray") } - -internal inline fun getRandomNormals(n: Int, seed: Long): DoubleArray { - val u = Random(seed) - return (0 until n).map { sqrt(-2.0 * ln(u.nextDouble())) * cos(2.0 * PI * u.nextDouble()) }.toDoubleArray() +/* +internal inline fun getRandomNormals(n: Int,): DoubleArray { + val sampler = BoxMullerNormalizedGaussianSampler.of() + val chain = sampler.sample(RandomGenerator.default) + return (0 until n).map { chain.next() }.toDoubleArray() } +*/ \ No newline at end of file From b36281fa39d810ae1e60d2e7a9e042be754b8687 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 31 Mar 2021 09:23:41 +0100 Subject: [PATCH 083/178] roll back --- .../space/kscience/kmath/tensors/core/utils.kt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index e46d39cf2..fc0ebe7fa 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -37,10 +37,8 @@ internal fun Buffer.array(): DoubleArray = when (this) { is DoubleBuffer -> array else -> throw RuntimeException("Failed to cast Buffer to DoubleArray") } -/* -internal inline fun getRandomNormals(n: Int,): DoubleArray { - val sampler = BoxMullerNormalizedGaussianSampler.of() - val chain = sampler.sample(RandomGenerator.default) - return (0 until n).map { chain.next() }.toDoubleArray() -} -*/ \ No newline at end of file + +internal inline fun getRandomNormals(n: Int, seed: Long): DoubleArray { + val u = Random(seed) + return (0 until n).map { sqrt(-2.0 * ln(u.nextDouble())) * cos(2.0 * PI * u.nextDouble()) }.toDoubleArray() +} \ No newline at end of file From 3e98240b94b99170ffd8525d9b307ac6c715ebd6 Mon Sep 17 00:00:00 2001 From: AlyaNovikova Date: Thu, 1 Apr 2021 20:21:14 +0300 Subject: [PATCH 084/178] add function diagonalEmbedding with tests --- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 42 ++++++++++++++++++- .../tensors/core/TestDoubleTensorAlgebra.kt | 33 +++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 323ade45d..ab692c0f9 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -283,7 +283,47 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra n || dim2 > n) { + throw RuntimeException("Dimension out of range") + } + + var lessDim = dim1 + var greaterDim = dim2 + var realOffset = offset + if (lessDim > greaterDim) { + realOffset *= -1 + lessDim = greaterDim.also {greaterDim = lessDim} + } + + val resShape = diagonalEntries.shape.slice(0 until lessDim).toIntArray() + + intArrayOf(diagonalEntries.shape[n - 1] + abs(realOffset)) + + diagonalEntries.shape.slice(lessDim until greaterDim - 1).toIntArray() + + intArrayOf(diagonalEntries.shape[n - 1] + abs(realOffset)) + + diagonalEntries.shape.slice(greaterDim - 1 until n - 1).toIntArray() + val resTensor = zeros(resShape) + + for (i in 0 until diagonalEntries.linearStructure.size) { + val multiIndex = diagonalEntries.linearStructure.index(i) + + var offset1 = 0 + var offset2 = abs(realOffset) + if (realOffset < 0) { + offset1 = offset2.also {offset2 = offset1} + } + val diagonalMultiIndex = multiIndex.slice(0 until lessDim).toIntArray() + + intArrayOf(multiIndex[n - 1] + offset1) + + multiIndex.slice(lessDim until greaterDim - 1).toIntArray() + + intArrayOf(multiIndex[n - 1] + offset2) + + multiIndex.slice(greaterDim - 1 until n - 1).toIntArray() + + resTensor[diagonalMultiIndex] = diagonalEntries[multiIndex] + } + + return resTensor } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index 168d80a9d..692db69af 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -115,6 +115,39 @@ class TestDoubleTensorAlgebra { assertTrue(tensor4.dot(tensor5).shape contentEquals intArrayOf(5, 4, 2, 8, 3, 8, 5)) } + @Test + fun diagonalEmbedding() = DoubleTensorAlgebra { + 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 tensor3 = zeros(intArrayOf(2, 3, 4, 5)) + + assertTrue(diagonalEmbedding(tensor3, 0, 3, 4).shape contentEquals + intArrayOf(2, 3, 4, 5, 5)) + assertTrue(diagonalEmbedding(tensor3, 1, 3, 4).shape contentEquals + intArrayOf(2, 3, 4, 6, 6)) + assertTrue(diagonalEmbedding(tensor3, 2, 0, 3).shape contentEquals + intArrayOf(7, 2, 3, 7, 4)) + + val diagonal1 = diagonalEmbedding(tensor1, 0, 1, 0) + assertTrue(diagonal1.shape contentEquals intArrayOf(3, 3)) + assertTrue(diagonal1.buffer.array() contentEquals + doubleArrayOf(10.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 30.0)) + + val diagonal1_offset = diagonalEmbedding(tensor1, 1, 1, 0) + assertTrue(diagonal1_offset.shape contentEquals intArrayOf(4, 4)) + assertTrue(diagonal1_offset.buffer.array() contentEquals + doubleArrayOf(0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 30.0, 0.0)) + + val diagonal2 = diagonalEmbedding(tensor2, 1, 0, 2) + assertTrue(diagonal2.shape contentEquals intArrayOf(4, 2, 4)) + assertTrue(diagonal2.buffer.array() contentEquals + doubleArrayOf( + 0.0, 1.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, + 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 5.0, 0.0, + 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 6.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)) + } + @Test fun testContentEqual() = DoubleTensorAlgebra { //TODO() From 814eab8cde1dff4b94b49efbb8d93c6b0bc06002 Mon Sep 17 00:00:00 2001 From: AlyaNovikova Date: Tue, 6 Apr 2021 00:06:14 +0300 Subject: [PATCH 085/178] implement svd function and tests for it --- .../core/DoubleLinearOpsTensorAlgebra.kt | 77 ++++++++++++++++++- .../core/TestDoubleLinearOpsAlgebra.kt | 32 ++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index c571fe446..fbd9da18e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -3,6 +3,8 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.tensors.LinearOpsTensorAlgebra import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D +import kotlin.math.abs +import kotlin.math.min public class DoubleLinearOpsTensorAlgebra : LinearOpsTensorAlgebra, @@ -89,8 +91,81 @@ public class DoubleLinearOpsTensorAlgebra : return qTensor to rTensor } + internal fun svd1d(a: DoubleTensor, epsilon: Double = 1e-10): DoubleTensor { + val (n, m) = a.shape + var v: DoubleTensor + val b: DoubleTensor + if (n > m) { + b = a.transpose(0, 1).dot(a) + v = DoubleTensor(intArrayOf(m), getRandomNormals(m, 0)) + } else { + b = a.dot(a.transpose(0, 1)) + v = DoubleTensor(intArrayOf(n), getRandomNormals(n, 0)) + } + + var lastV: DoubleTensor + while (true) { + lastV = v + v = b.dot(lastV) + val norm = DoubleAnalyticTensorAlgebra { (v dot v).sqrt().value() } + v = v.times(1.0 / norm) + if (abs(v.dot(lastV).value()) > 1 - epsilon) { + return v + } + } + } + override fun DoubleTensor.svd(): Triple { - TODO("ALYA") + val size = this.shape.size + val commonShape = this.shape.sliceArray(0 until size - 2) + val (n, m) = this.shape.sliceArray(size - 2 until size) + val resU = zeros(commonShape + intArrayOf(n, min(n, m))) + val resS = zeros(commonShape + intArrayOf(min(n, m))) + val resV = zeros(commonShape + intArrayOf(min(n, m), m)) + + for ((matrix, USV) in this.matrixSequence() + .zip(resU.matrixSequence().zip(resS.vectorSequence().zip(resV.matrixSequence())))) { + val res = ArrayList>(0) + val (matrixU, SV) = USV + val (matrixS, matrixV) = SV + + for (k in 0 until min(n, m)) { + var a = matrix.asTensor().copy() + for ((singularValue, u, v) in res.slice(0 until k)) { + val outerProduct = DoubleArray(u.shape[0] * v.shape[0]) + for (i in 0 until u.shape[0]) { + for (j in 0 until v.shape[0]) { + outerProduct[i * v.shape[0] + j] = u[i].value() * v[j].value() + } + } + a = a - singularValue.times(DoubleTensor(intArrayOf(u.shape[0], v.shape[0]), outerProduct)) + } + var v: DoubleTensor + var u: DoubleTensor + var norm: Double + if (n > m) { + v = svd1d(a) + u = matrix.asTensor().dot(v) + norm = DoubleAnalyticTensorAlgebra { (u dot u).sqrt().value() } + u = u.times(1.0 / norm) + } else { + u = svd1d(a) + v = matrix.asTensor().transpose(0, 1).dot(u) + norm = DoubleAnalyticTensorAlgebra { (v dot v).sqrt().value() } + v = v.times(1.0 / norm) + } + + res.add(Triple(norm, u, v)) + } + + val s = res.map { it.first }.toDoubleArray() + val uBuffer = res.map { it.second }.flatMap { it.buffer.array().toList() }.toDoubleArray() + val vBuffer = res.map { it.third }.flatMap { it.buffer.array().toList() }.toDoubleArray() + uBuffer.copyInto(matrixU.buffer.array()) + s.copyInto(matrixS.buffer.array()) + vBuffer.copyInto(matrixV.buffer.array()) + } + return Triple(resU, resS, resV.transpose(size - 2, size - 1)) } override fun DoubleTensor.symEig(eigenvectors: Boolean): Pair { diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index b79c54dd1..843707153 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -122,4 +122,36 @@ class TestDoubleLinearOpsTensorAlgebra { assertTrue { p.dot(tensor).buffer.array().epsEqual(l.dot(u).buffer.array()) } } + + @Test + fun svd1d() = DoubleLinearOpsTensorAlgebra { + val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + + val res = svd1d(tensor2) + + assertTrue(res.shape contentEquals intArrayOf(2)) + assertTrue { abs(abs(res.buffer.array()[res.bufferStart]) - 0.386) < 0.01} + assertTrue { abs(abs(res.buffer.array()[res.bufferStart + 1]) - 0.922) < 0.01} + } + + @Test + fun svd() = DoubleLinearOpsTensorAlgebra { + val epsilon = 1e-10 + fun test_tensor(tensor: DoubleTensor) { + val svd = tensor.svd() + + val tensorSVD = svd.first + .dot( + diagonalEmbedding(svd.second, 0, 0, 1) + .dot(svd.third.transpose(0, 1)) + ) + + for ((x1, x2) in tensor.buffer.array() zip tensorSVD.buffer.array()) { + assertTrue { abs(x1 - x2) < epsilon } + } + } + test_tensor(fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))) + test_tensor(fromArray(intArrayOf(2, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0))) + + } } From 4336788a6ba846af6a63be1352d1bec1c1f39b56 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 6 Apr 2021 09:00:13 +0100 Subject: [PATCH 086/178] Moving Alya's SVD implementation to linutils --- .../core/DoubleLinearOpsTensorAlgebra.kt | 66 +--------------- .../kscience/kmath/tensors/core/linutils.kt | 76 ++++++++++++++++++- .../core/TestDoubleLinearOpsAlgebra.kt | 4 +- 3 files changed, 78 insertions(+), 68 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index fbd9da18e..7db812d9d 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -91,29 +91,6 @@ public class DoubleLinearOpsTensorAlgebra : return qTensor to rTensor } - internal fun svd1d(a: DoubleTensor, epsilon: Double = 1e-10): DoubleTensor { - val (n, m) = a.shape - var v: DoubleTensor - val b: DoubleTensor - if (n > m) { - b = a.transpose(0, 1).dot(a) - v = DoubleTensor(intArrayOf(m), getRandomNormals(m, 0)) - } else { - b = a.dot(a.transpose(0, 1)) - v = DoubleTensor(intArrayOf(n), getRandomNormals(n, 0)) - } - - var lastV: DoubleTensor - while (true) { - lastV = v - v = b.dot(lastV) - val norm = DoubleAnalyticTensorAlgebra { (v dot v).sqrt().value() } - v = v.times(1.0 / norm) - if (abs(v.dot(lastV).value()) > 1 - epsilon) { - return v - } - } - } override fun DoubleTensor.svd(): Triple { val size = this.shape.size @@ -124,47 +101,8 @@ public class DoubleLinearOpsTensorAlgebra : val resV = zeros(commonShape + intArrayOf(min(n, m), m)) for ((matrix, USV) in this.matrixSequence() - .zip(resU.matrixSequence().zip(resS.vectorSequence().zip(resV.matrixSequence())))) { - val res = ArrayList>(0) - val (matrixU, SV) = USV - val (matrixS, matrixV) = SV - - for (k in 0 until min(n, m)) { - var a = matrix.asTensor().copy() - for ((singularValue, u, v) in res.slice(0 until k)) { - val outerProduct = DoubleArray(u.shape[0] * v.shape[0]) - for (i in 0 until u.shape[0]) { - for (j in 0 until v.shape[0]) { - outerProduct[i * v.shape[0] + j] = u[i].value() * v[j].value() - } - } - a = a - singularValue.times(DoubleTensor(intArrayOf(u.shape[0], v.shape[0]), outerProduct)) - } - var v: DoubleTensor - var u: DoubleTensor - var norm: Double - if (n > m) { - v = svd1d(a) - u = matrix.asTensor().dot(v) - norm = DoubleAnalyticTensorAlgebra { (u dot u).sqrt().value() } - u = u.times(1.0 / norm) - } else { - u = svd1d(a) - v = matrix.asTensor().transpose(0, 1).dot(u) - norm = DoubleAnalyticTensorAlgebra { (v dot v).sqrt().value() } - v = v.times(1.0 / norm) - } - - res.add(Triple(norm, u, v)) - } - - val s = res.map { it.first }.toDoubleArray() - val uBuffer = res.map { it.second }.flatMap { it.buffer.array().toList() }.toDoubleArray() - val vBuffer = res.map { it.third }.flatMap { it.buffer.array().toList() }.toDoubleArray() - uBuffer.copyInto(matrixU.buffer.array()) - s.copyInto(matrixS.buffer.array()) - vBuffer.copyInto(matrixV.buffer.array()) - } + .zip(resU.matrixSequence().zip(resS.vectorSequence().zip(resV.matrixSequence())))) + svdHelper(matrix.asTensor(), USV, m, n) return Triple(resU, resS, resV.transpose(size - 2, size - 1)) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt index f6cf71b07..e1d5c1819 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt @@ -4,6 +4,8 @@ import space.kscience.kmath.nd.MutableStructure1D import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D +import kotlin.math.abs +import kotlin.math.min import kotlin.math.sqrt @@ -195,8 +197,8 @@ internal inline fun DoubleLinearOpsTensorAlgebra.qrHelper( checkSquareMatrix(matrix.shape) val n = matrix.shape[0] val qM = q.as2D() - val matrixT = matrix.transpose(0,1) - val qT = q.transpose(0,1) + val matrixT = matrix.transpose(0, 1) + val qT = q.transpose(0, 1) for (j in 0 until n) { val v = matrixT[j] @@ -216,3 +218,73 @@ internal inline fun DoubleLinearOpsTensorAlgebra.qrHelper( } } } + +internal inline fun DoubleLinearOpsTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10): DoubleTensor { + val (n, m) = a.shape + var v: DoubleTensor + val b: DoubleTensor + if (n > m) { + b = a.transpose(0, 1).dot(a) + v = DoubleTensor(intArrayOf(m), getRandomNormals(m, 0)) + } else { + b = a.dot(a.transpose(0, 1)) + v = DoubleTensor(intArrayOf(n), getRandomNormals(n, 0)) + } + + var lastV: DoubleTensor + while (true) { + lastV = v + v = b.dot(lastV) + val norm = DoubleAnalyticTensorAlgebra { (v dot v).sqrt().value() } + v = v.times(1.0 / norm) + if (abs(v.dot(lastV).value()) > 1 - epsilon) { + return v + } + } +} + +internal inline fun DoubleLinearOpsTensorAlgebra.svdHelper( + matrix: DoubleTensor, + USV: Pair, Pair, BufferedTensor>>, + m: Int, n: Int +): Unit { + val res = ArrayList>(0) + val (matrixU, SV) = USV + val (matrixS, matrixV) = SV + + for (k in 0 until min(n, m)) { + var a = matrix.copy() + for ((singularValue, u, v) in res.slice(0 until k)) { + val outerProduct = DoubleArray(u.shape[0] * v.shape[0]) + for (i in 0 until u.shape[0]) { + for (j in 0 until v.shape[0]) { + outerProduct[i * v.shape[0] + j] = u[i].value() * v[j].value() + } + } + a = a - singularValue.times(DoubleTensor(intArrayOf(u.shape[0], v.shape[0]), outerProduct)) + } + var v: DoubleTensor + var u: DoubleTensor + var norm: Double + if (n > m) { + v = svd1d(a) + u = matrix.dot(v) + norm = DoubleAnalyticTensorAlgebra { (u dot u).sqrt().value() } + u = u.times(1.0 / norm) + } else { + u = svd1d(a) + v = matrix.transpose(0, 1).dot(u) + norm = DoubleAnalyticTensorAlgebra { (v dot v).sqrt().value() } + v = v.times(1.0 / norm) + } + + res.add(Triple(norm, u, v)) + } + + val s = res.map { it.first }.toDoubleArray() + val uBuffer = res.map { it.second }.flatMap { it.buffer.array().toList() }.toDoubleArray() + val vBuffer = res.map { it.third }.flatMap { it.buffer.array().toList() }.toDoubleArray() + uBuffer.copyInto(matrixU.buffer.array()) + s.copyInto(matrixS.buffer.array()) + vBuffer.copyInto(matrixV.buffer.array()) +} diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 843707153..60f7f4a97 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -124,7 +124,7 @@ class TestDoubleLinearOpsTensorAlgebra { } @Test - fun svd1d() = DoubleLinearOpsTensorAlgebra { + fun testSVD1D() = DoubleLinearOpsTensorAlgebra { val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val res = svd1d(tensor2) @@ -135,7 +135,7 @@ class TestDoubleLinearOpsTensorAlgebra { } @Test - fun svd() = DoubleLinearOpsTensorAlgebra { + fun testSVD() = DoubleLinearOpsTensorAlgebra { val epsilon = 1e-10 fun test_tensor(tensor: DoubleTensor) { val svd = tensor.svd() From dcdc22dd9dddf8d3157fb51f1ee7b6bf226b3b8c Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 6 Apr 2021 11:04:00 +0100 Subject: [PATCH 087/178] SVD test to be fixed --- .../kscience/kmath/tensors/TensorAlgebra.kt | 2 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 6 ++ .../kscience/kmath/tensors/core/utils.kt | 2 - .../core/TestDoubleLinearOpsAlgebra.kt | 65 +++++++++++-------- 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index d7c6eaefd..966806de1 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -40,7 +40,7 @@ public interface TensorAlgebra> { //https://pytorch.org/docs/stable/generated/torch.diag_embed.html public fun diagonalEmbedding( diagonalEntries: TensorType, - offset: Int = 0, dim1: Int = -2, dim2: Int = -1 + offset: Int = 0, dim1: Int = 0, dim2: Int = 1 ): TensorType } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index ab692c0f9..53063a066 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -362,6 +362,12 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra eps) { - return false - } - } - return true - } - @Test fun testDetLU() = DoubleLinearOpsTensorAlgebra { val tensor = fromArray( @@ -136,22 +121,46 @@ class TestDoubleLinearOpsTensorAlgebra { @Test fun testSVD() = DoubleLinearOpsTensorAlgebra { - val epsilon = 1e-10 - fun test_tensor(tensor: DoubleTensor) { - val svd = tensor.svd() + 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))) + } - val tensorSVD = svd.first - .dot( - diagonalEmbedding(svd.second, 0, 0, 1) - .dot(svd.third.transpose(0, 1)) - ) + @Test + fun testBatchedSVD() = DoubleLinearOpsTensorAlgebra { + val tensor = randNormal(intArrayOf(7, 5, 3), 0) + val (tensorU, tensorS, tensorV) = tensor.svd() + val tensorSVD = tensorU dot (diagonalEmbedding(tensorS,0,1,2) dot tensorV) + println(tensor.eq(tensorSVD)) + } - for ((x1, x2) in tensor.buffer.array() zip tensorSVD.buffer.array()) { - assertTrue { abs(x1 - x2) < epsilon } - } + +} + +private inline fun Double.epsEqual(other: Double, eps: Double = 1e-5): Boolean { + return abs(this - other) < eps +} + +private inline fun DoubleArray.epsEqual(other: DoubleArray, eps: Double = 1e-5): Boolean { + for ((elem1, elem2) in this.asSequence().zip(other.asSequence())) { + if (abs(elem1 - elem2) > eps) { + return false } - test_tensor(fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))) - test_tensor(fromArray(intArrayOf(2, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0))) + } + return true +} +private inline fun DoubleLinearOpsTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double = 1e-10): Unit { + val svd = tensor.svd() + + val tensorSVD = svd.first + .dot( + diagonalEmbedding(svd.second, 0, 0, 1) + .dot(svd.third.transpose(0, 1)) + ) + + for ((x1, x2) in tensor.buffer.array() zip tensorSVD.buffer.array()) { + assertTrue { abs(x1 - x2) < epsilon } } } + + From 2bbe10e41c83e5ce44a920ad0a4c071b7d25f252 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 6 Apr 2021 11:41:41 +0100 Subject: [PATCH 088/178] SymEig test --- .../tensors/core/TestDoubleLinearOpsAlgebra.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 0bd0ff5bd..29632e771 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -1,6 +1,7 @@ package space.kscience.kmath.tensors.core import kotlin.math.abs +import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -125,12 +126,21 @@ class TestDoubleLinearOpsTensorAlgebra { testSVDFor(fromArray(intArrayOf(2, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0))) } - @Test + @Test @Ignore fun testBatchedSVD() = DoubleLinearOpsTensorAlgebra { val tensor = randNormal(intArrayOf(7, 5, 3), 0) val (tensorU, tensorS, tensorV) = tensor.svd() val tensorSVD = tensorU dot (diagonalEmbedding(tensorS,0,1,2) dot tensorV) - println(tensor.eq(tensorSVD)) + assertTrue(tensor.eq(tensorSVD)) + } + + @Test @Ignore + fun testBatchedSymEig() = DoubleLinearOpsTensorAlgebra { + val tensor = randNormal(shape = intArrayOf(5, 2, 2), 0) + val tensorSigma = tensor + tensor.transpose(1, 2) + val (tensorS, tensorV) = tensorSigma.symEig() + val tensorSigmaCalc = tensorV dot (diagonalEmbedding(tensorS, 0,1,2) dot tensorV.transpose(1, 2)) + assertTrue(tensorSigma.eq(tensorSigmaCalc)) } From 174f6566e116b43e70622785c58291532b170369 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 6 Apr 2021 12:07:39 +0100 Subject: [PATCH 089/178] Negative indices --- .../kscience/kmath/tensors/TensorAlgebra.kt | 4 ++-- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 20 +++++++++++-------- .../tensors/core/TensorLinearStructure.kt | 3 +++ .../kscience/kmath/tensors/core/utils.kt | 12 ++++++++++- .../core/TestDoubleLinearOpsAlgebra.kt | 4 ++-- .../tensors/core/TestDoubleTensorAlgebra.kt | 4 ++-- 6 files changed, 32 insertions(+), 15 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index 966806de1..8fd1cf2ed 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -28,7 +28,7 @@ public interface TensorAlgebra> { public operator fun TensorType.get(i: Int): TensorType //https://pytorch.org/docs/stable/generated/torch.transpose.html - public fun TensorType.transpose(i: Int, j: Int): TensorType + public fun TensorType.transpose(i: Int = -2, j: Int = -1): TensorType //https://pytorch.org/docs/stable/tensor_view.html public fun TensorType.view(shape: IntArray): TensorType @@ -40,7 +40,7 @@ public interface TensorAlgebra> { //https://pytorch.org/docs/stable/generated/torch.diag_embed.html public fun diagonalEmbedding( diagonalEntries: TensorType, - offset: Int = 0, dim1: Int = 0, dim2: Int = 1 + offset: Int = 0, dim1: Int = -2, dim2: Int = -1 ): TensorType } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 53063a066..870dbe8a7 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -198,19 +198,21 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra n || dim2 > n) { + if (d1 > n || d2 > n) { throw RuntimeException("Dimension out of range") } - var lessDim = dim1 - var greaterDim = dim2 + var lessDim = d1 + var greaterDim = d2 var realOffset = offset if (lessDim > greaterDim) { realOffset *= -1 diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt index 97ce29657..47745c2be 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt @@ -73,6 +73,9 @@ public class TensorLinearStructure(public val shape: IntArray) public val size: Int get() = shape.reduce(Int::times) + public val dim: Int + get() = shape.size + public fun indices(): Sequence = (0 until size).asSequence().map { index(it) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index 5fd3cfd28..785b59ede 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -39,4 +39,14 @@ internal fun Buffer.array(): DoubleArray = when (this) { internal inline fun getRandomNormals(n: Int, seed: Long): DoubleArray { val u = Random(seed) return (0 until n).map { sqrt(-2.0 * ln(u.nextDouble())) * cos(2.0 * PI * u.nextDouble()) }.toDoubleArray() -} \ No newline at end of file +} + +internal inline fun minusIndexFrom(n: Int, i: Int) : Int = if (i >= 0) i else { + val ii = n + i + check(ii >= 0) { + "Out of bound index $i for tensor of dim $n" + } + ii +} + +internal inline fun BufferedTensor.minusIndex(i: Int): Int = minusIndexFrom(this.linearStructure.dim, i) \ No newline at end of file diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 29632e771..56f9332f6 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -130,7 +130,7 @@ class TestDoubleLinearOpsTensorAlgebra { fun testBatchedSVD() = DoubleLinearOpsTensorAlgebra { val tensor = randNormal(intArrayOf(7, 5, 3), 0) val (tensorU, tensorS, tensorV) = tensor.svd() - val tensorSVD = tensorU dot (diagonalEmbedding(tensorS,0,1,2) dot tensorV) + val tensorSVD = tensorU dot (diagonalEmbedding(tensorS) dot tensorV) assertTrue(tensor.eq(tensorSVD)) } @@ -139,7 +139,7 @@ class TestDoubleLinearOpsTensorAlgebra { val tensor = randNormal(shape = intArrayOf(5, 2, 2), 0) val tensorSigma = tensor + tensor.transpose(1, 2) val (tensorS, tensorV) = tensorSigma.symEig() - val tensorSigmaCalc = tensorV dot (diagonalEmbedding(tensorS, 0,1,2) dot tensorV.transpose(1, 2)) + val tensorSigmaCalc = tensorV dot (diagonalEmbedding(tensorS) dot tensorV.transpose(1, 2)) assertTrue(tensorSigma.eq(tensorSigmaCalc)) } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index 692db69af..fa7a8fd32 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -35,8 +35,8 @@ class TestDoubleTensorAlgebra { fun transpose1x2x3() = DoubleTensorAlgebra { 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 res02 = tensor.transpose(0, 2) - val res12 = tensor.transpose(1, 2) + val res02 = tensor.transpose(-3, 2) + val res12 = tensor.transpose() assertTrue(res01.shape contentEquals intArrayOf(2, 1, 3)) assertTrue(res02.shape contentEquals intArrayOf(3, 2, 1)) From 74dfca4e2e265a17bcba9b4d968a56ddd5d07ad9 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 7 Apr 2021 15:11:00 +0100 Subject: [PATCH 090/178] Using kmath-stat for random normals --- .../kotlin/space/kscience/kmath/tensors/core/utils.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index 785b59ede..c99f9d156 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -1,8 +1,8 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.samplers.GaussianSampler +import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.structures.* -import kotlin.random.Random -import kotlin.math.* /** * Returns a reference to [IntArray] containing all of the elements of this [Buffer]. @@ -37,8 +37,9 @@ internal fun Buffer.array(): DoubleArray = when (this) { } internal inline fun getRandomNormals(n: Int, seed: Long): DoubleArray { - val u = Random(seed) - return (0 until n).map { sqrt(-2.0 * ln(u.nextDouble())) * cos(2.0 * PI * u.nextDouble()) }.toDoubleArray() + val distribution = GaussianSampler(0.0, 1.0) + val generator = RandomGenerator.default(seed) + return distribution.sample(generator).nextBufferBlocking(n).toDoubleArray() } internal inline fun minusIndexFrom(n: Int, i: Int) : Int = if (i >= 0) i else { From ea4d6618b4c2c7ecc22f82c4376b2b06904ff7c2 Mon Sep 17 00:00:00 2001 From: AlyaNovikova Date: Thu, 8 Apr 2021 23:58:44 +0300 Subject: [PATCH 091/178] fix bugs in svd --- .../tensors/core/DoubleLinearOpsTensorAlgebra.kt | 14 ++++++++++---- .../kscience/kmath/tensors/core/linutils.kt | 16 +++++++++++----- .../space/kscience/kmath/tensors/core/utils.kt | 7 +++++++ .../tensors/core/TestDoubleLinearOpsAlgebra.kt | 4 ++-- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 7db812d9d..83a41b80d 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -96,14 +96,20 @@ public class DoubleLinearOpsTensorAlgebra : val size = this.shape.size val commonShape = this.shape.sliceArray(0 until size - 2) val (n, m) = this.shape.sliceArray(size - 2 until size) - val resU = zeros(commonShape + intArrayOf(n, min(n, m))) + val resU = zeros(commonShape + intArrayOf(min(n, m), n)) val resS = zeros(commonShape + intArrayOf(min(n, m))) val resV = zeros(commonShape + intArrayOf(min(n, m), m)) for ((matrix, USV) in this.matrixSequence() - .zip(resU.matrixSequence().zip(resS.vectorSequence().zip(resV.matrixSequence())))) - svdHelper(matrix.asTensor(), USV, m, n) - return Triple(resU, resS, resV.transpose(size - 2, size - 1)) + .zip(resU.matrixSequence().zip(resS.vectorSequence().zip(resV.matrixSequence())))) { + val size = matrix.shape.reduce { acc, i -> acc * i } + val curMatrix = DoubleTensor( + matrix.shape, + matrix.buffer.array().slice(matrix.bufferStart until matrix.bufferStart + size).toDoubleArray() + ) + svdHelper(curMatrix, USV, m, n) + } + return Triple(resU.transpose(size - 2, size - 1), resS, resV) } override fun DoubleTensor.symEig(eigenvectors: Boolean): Pair { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt index e1d5c1819..1bdfee2d5 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt @@ -225,10 +225,10 @@ internal inline fun DoubleLinearOpsTensorAlgebra.svd1d(a: DoubleTensor, epsilon: val b: DoubleTensor if (n > m) { b = a.transpose(0, 1).dot(a) - v = DoubleTensor(intArrayOf(m), getRandomNormals(m, 0)) + v = DoubleTensor(intArrayOf(m), getRandomUnitVector(m, 0)) } else { b = a.dot(a.transpose(0, 1)) - v = DoubleTensor(intArrayOf(n), getRandomNormals(n, 0)) + v = DoubleTensor(intArrayOf(n), getRandomUnitVector(n, 0)) } var lastV: DoubleTensor @@ -284,7 +284,13 @@ internal inline fun DoubleLinearOpsTensorAlgebra.svdHelper( val s = res.map { it.first }.toDoubleArray() val uBuffer = res.map { it.second }.flatMap { it.buffer.array().toList() }.toDoubleArray() val vBuffer = res.map { it.third }.flatMap { it.buffer.array().toList() }.toDoubleArray() - uBuffer.copyInto(matrixU.buffer.array()) - s.copyInto(matrixS.buffer.array()) - vBuffer.copyInto(matrixV.buffer.array()) + for (i in uBuffer.indices) { + matrixU.buffer.array()[matrixU.bufferStart + i] = uBuffer[i] + } + for (i in s.indices) { + matrixS.buffer.array()[matrixS.bufferStart + i] = s[i] + } + for (i in vBuffer.indices) { + matrixV.buffer.array()[matrixV.bufferStart + i] = vBuffer[i] + } } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index c99f9d156..392abd1c2 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -3,6 +3,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.samplers.GaussianSampler import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.structures.* +import kotlin.math.sqrt /** * Returns a reference to [IntArray] containing all of the elements of this [Buffer]. @@ -42,6 +43,12 @@ internal inline fun getRandomNormals(n: Int, seed: Long): DoubleArray { return distribution.sample(generator).nextBufferBlocking(n).toDoubleArray() } +internal inline fun getRandomUnitVector(n: Int, seed: Long): DoubleArray { + val unnorm = getRandomNormals(n, seed) + val norm = sqrt(unnorm.map { it * it }.sum()) + return unnorm.map { it / norm }.toDoubleArray() +} + internal inline fun minusIndexFrom(n: Int, i: Int) : Int = if (i >= 0) i else { val ii = n + i check(ii >= 0) { diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 56f9332f6..35390968e 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -126,9 +126,9 @@ class TestDoubleLinearOpsTensorAlgebra { testSVDFor(fromArray(intArrayOf(2, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0))) } - @Test @Ignore + @Test fun testBatchedSVD() = DoubleLinearOpsTensorAlgebra { - val tensor = randNormal(intArrayOf(7, 5, 3), 0) + val tensor = randNormal(intArrayOf(1, 15, 4, 7, 5, 3), 0) val (tensorU, tensorS, tensorV) = tensor.svd() val tensorSVD = tensorU dot (diagonalEmbedding(tensorS) dot tensorV) assertTrue(tensor.eq(tensorSVD)) From a09a1c7adc73615d46b4fa5d1611c3a694b8d5a8 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 9 Apr 2021 07:33:25 +0100 Subject: [PATCH 092/178] Fixed tests --- .../core/DoubleLinearOpsTensorAlgebra.kt | 6 +- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 7 --- .../kscience/kmath/tensors/core/checks.kt | 3 +- .../core/TestDoubleLinearOpsAlgebra.kt | 63 ++++++++----------- 4 files changed, 31 insertions(+), 48 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 83a41b80d..916361abe 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -93,7 +93,7 @@ public class DoubleLinearOpsTensorAlgebra : override fun DoubleTensor.svd(): Triple { - val size = this.shape.size + val size = this.linearStructure.dim val commonShape = this.shape.sliceArray(0 until size - 2) val (n, m) = this.shape.sliceArray(size - 2 until size) val resU = zeros(commonShape + intArrayOf(min(n, m), n)) @@ -109,11 +109,11 @@ public class DoubleLinearOpsTensorAlgebra : ) svdHelper(curMatrix, USV, m, n) } - return Triple(resU.transpose(size - 2, size - 1), resS, resV) + return Triple(resU.transpose(), resS, resV.transpose()) } override fun DoubleTensor.symEig(eigenvectors: Boolean): Pair { - TODO("ANDREI") + TODO() } public fun DoubleTensor.detLU(): DoubleTensor { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 870dbe8a7..8f355dd3d 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -339,19 +339,12 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra abs(x - y) < delta } - } - public fun DoubleTensor.eq(other: DoubleTensor, delta: Double): Boolean { return this.eq(other) { x, y -> abs(x - y) < delta } } public fun DoubleTensor.eq(other: DoubleTensor): Boolean = this.eq(other, 1e-5) - public fun DoubleTensor.contentEquals(other: DoubleTensor, eqFunction: (Double, Double) -> Boolean): Boolean = - this.eq(other, eqFunction) - private fun DoubleTensor.eq(other: DoubleTensor, eqFunction: (Double, Double) -> Boolean): Boolean { checkShapesCompatible(this, other) val n = this.linearStructure.size diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt index 247ed3913..f994324ff 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -56,4 +56,5 @@ internal inline fun , check(shape[n - 1] == shape[n - 2]) { "Tensor must be batches of square matrices, but they are ${shape[n - 1]} by ${shape[n - 1]} matrices" } -} \ No newline at end of file +} + diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 35390968e..df896bace 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -20,15 +20,17 @@ class TestDoubleLinearOpsTensorAlgebra { ) ) - val expectedShape = intArrayOf(2, 1) - val expectedBuffer = doubleArrayOf( - -1.0, - -7.0 + val expectedTensor = fromArray( + intArrayOf(2, 1), + doubleArrayOf( + -1.0, + -7.0 + ) ) val detTensor = tensor.detLU() - assertTrue { detTensor.shape contentEquals expectedShape } - assertTrue { detTensor.buffer.array().epsEqual(expectedBuffer) } + assertTrue(detTensor.eq(expectedTensor)) + } @Test @@ -43,17 +45,17 @@ class TestDoubleLinearOpsTensorAlgebra { ) ) - val expectedShape = intArrayOf(2, 2, 2) - val expectedBuffer = doubleArrayOf( - 1.0, 0.0, - 0.0, 0.5, - 0.0, 1.0, - 1.0, -1.0 + val expectedTensor = fromArray( + intArrayOf(2, 2, 2), doubleArrayOf( + 1.0, 0.0, + 0.0, 0.5, + 0.0, 1.0, + 1.0, -1.0 + ) ) val invTensor = tensor.invLU() - assertTrue { invTensor.shape contentEquals expectedShape } - assertTrue { invTensor.buffer.array().epsEqual(expectedBuffer) } + assertTrue(invTensor.eq(expectedTensor)) } @Test @@ -80,7 +82,7 @@ class TestDoubleLinearOpsTensorAlgebra { assertTrue { q.shape contentEquals shape } assertTrue { r.shape contentEquals shape } - assertTrue { q.dot(r).buffer.array().epsEqual(buffer) } + assertTrue((q dot r).eq(tensor)) //todo check orthogonality/upper triang. } @@ -106,7 +108,7 @@ class TestDoubleLinearOpsTensorAlgebra { assertTrue { l.shape contentEquals shape } assertTrue { u.shape contentEquals shape } - assertTrue { p.dot(tensor).buffer.array().epsEqual(l.dot(u).buffer.array()) } + assertTrue((p dot tensor).eq(l dot u)) } @Test @@ -116,8 +118,8 @@ class TestDoubleLinearOpsTensorAlgebra { val res = svd1d(tensor2) assertTrue(res.shape contentEquals intArrayOf(2)) - assertTrue { abs(abs(res.buffer.array()[res.bufferStart]) - 0.386) < 0.01} - assertTrue { abs(abs(res.buffer.array()[res.bufferStart + 1]) - 0.922) < 0.01} + assertTrue { abs(abs(res.buffer.array()[res.bufferStart]) - 0.386) < 0.01 } + assertTrue { abs(abs(res.buffer.array()[res.bufferStart + 1]) - 0.922) < 0.01 } } @Test @@ -130,11 +132,12 @@ class TestDoubleLinearOpsTensorAlgebra { fun testBatchedSVD() = DoubleLinearOpsTensorAlgebra { val tensor = randNormal(intArrayOf(1, 15, 4, 7, 5, 3), 0) val (tensorU, tensorS, tensorV) = tensor.svd() - val tensorSVD = tensorU dot (diagonalEmbedding(tensorS) dot tensorV) + val tensorSVD = tensorU dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) assertTrue(tensor.eq(tensorSVD)) } - @Test @Ignore + @Test + @Ignore fun testBatchedSymEig() = DoubleLinearOpsTensorAlgebra { val tensor = randNormal(shape = intArrayOf(5, 2, 2), 0) val tensorSigma = tensor + tensor.transpose(1, 2) @@ -146,31 +149,17 @@ class TestDoubleLinearOpsTensorAlgebra { } -private inline fun Double.epsEqual(other: Double, eps: Double = 1e-5): Boolean { - return abs(this - other) < eps -} - -private inline fun DoubleArray.epsEqual(other: DoubleArray, eps: Double = 1e-5): Boolean { - for ((elem1, elem2) in this.asSequence().zip(other.asSequence())) { - if (abs(elem1 - elem2) > eps) { - return false - } - } - return true -} private inline fun DoubleLinearOpsTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double = 1e-10): Unit { val svd = tensor.svd() val tensorSVD = svd.first .dot( - diagonalEmbedding(svd.second, 0, 0, 1) - .dot(svd.third.transpose(0, 1)) + diagonalEmbedding(svd.second) + .dot(svd.third.transpose()) ) - for ((x1, x2) in tensor.buffer.array() zip tensorSVD.buffer.array()) { - assertTrue { abs(x1 - x2) < epsilon } - } + assertTrue(tensor.eq(tensorSVD, epsilon)) } From 8c1131dd5818f75b1b0eb9e0b3ef23f12f6a7c07 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 9 Apr 2021 08:03:47 +0100 Subject: [PATCH 093/178] Approaching SymEig through SVD --- .../kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt | 6 ++++-- .../kotlin/space/kscience/kmath/tensors/core/checks.kt | 4 ++++ .../kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 916361abe..43502e79a 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -67,7 +67,7 @@ public class DoubleLinearOpsTensorAlgebra : } override fun DoubleTensor.cholesky(): DoubleTensor { - // todo checks + checkSymmetric(this) checkSquareMatrix(shape) val n = shape.last() @@ -113,7 +113,9 @@ public class DoubleLinearOpsTensorAlgebra : } override fun DoubleTensor.symEig(eigenvectors: Boolean): Pair { - TODO() + checkSymmetric(this) + val svd = this.svd() + TODO("U might have some columns negative to V") } public fun DoubleTensor.detLU(): DoubleTensor { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt index f994324ff..1f70eb300 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -58,3 +58,7 @@ internal inline fun , } } +internal inline fun DoubleTensorAlgebra.checkSymmetric(tensor: DoubleTensor): Unit = + check(tensor.eq(tensor.transpose())){ + "Tensor is not symmetric about the last 2 dimensions" + } \ No newline at end of file diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index df896bace..cc127b5a7 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -140,9 +140,9 @@ class TestDoubleLinearOpsTensorAlgebra { @Ignore fun testBatchedSymEig() = DoubleLinearOpsTensorAlgebra { val tensor = randNormal(shape = intArrayOf(5, 2, 2), 0) - val tensorSigma = tensor + tensor.transpose(1, 2) + val tensorSigma = tensor + tensor.transpose() val (tensorS, tensorV) = tensorSigma.symEig() - val tensorSigmaCalc = tensorV dot (diagonalEmbedding(tensorS) dot tensorV.transpose(1, 2)) + val tensorSigmaCalc = tensorV dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) assertTrue(tensorSigma.eq(tensorSigmaCalc)) } From 5d8b42da906fec8c5450a4babf461a4873a8aee9 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 9 Apr 2021 08:29:08 +0100 Subject: [PATCH 094/178] minor corrections to linear stuff --- .../kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 43502e79a..4e67e1d16 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -67,6 +67,7 @@ public class DoubleLinearOpsTensorAlgebra : } override fun DoubleTensor.cholesky(): DoubleTensor { + //positive definite check checkSymmetric(this) checkSquareMatrix(shape) @@ -114,8 +115,7 @@ public class DoubleLinearOpsTensorAlgebra : override fun DoubleTensor.symEig(eigenvectors: Boolean): Pair { checkSymmetric(this) - val svd = this.svd() - TODO("U might have some columns negative to V") + TODO("maybe use SVD") } public fun DoubleTensor.detLU(): DoubleTensor { From e4dbabc30f5a740deae2055c33c982637463d85e Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 9 Apr 2021 08:32:03 +0100 Subject: [PATCH 095/178] more infor --- .../kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 4e67e1d16..7d99b7b51 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -115,6 +115,8 @@ public class DoubleLinearOpsTensorAlgebra : override fun DoubleTensor.symEig(eigenvectors: Boolean): Pair { checkSymmetric(this) + //http://hua-zhou.github.io/teaching/biostatm280-2017spring/slides/16-eigsvd/eigsvd.html + //see the last point TODO("maybe use SVD") } From 3f0dff3ce9f830f6c04ac72346eb6053c61ae0bf Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 9 Apr 2021 09:18:00 +0100 Subject: [PATCH 096/178] Approximate spectral decomposition for symmetric matrices based on SVD --- .../tensors/core/DoubleLinearOpsTensorAlgebra.kt | 11 ++++++++--- .../kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt | 6 +++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 7d99b7b51..268f2fe55 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -3,8 +3,10 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.tensors.LinearOpsTensorAlgebra import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D +import space.kscience.kmath.structures.toList import kotlin.math.abs import kotlin.math.min +import kotlin.math.sign public class DoubleLinearOpsTensorAlgebra : LinearOpsTensorAlgebra, @@ -113,11 +115,14 @@ public class DoubleLinearOpsTensorAlgebra : return Triple(resU.transpose(), resS, resV.transpose()) } + //http://hua-zhou.github.io/teaching/biostatm280-2017spring/slides/16-eigsvd/eigsvd.html override fun DoubleTensor.symEig(eigenvectors: Boolean): Pair { checkSymmetric(this) - //http://hua-zhou.github.io/teaching/biostatm280-2017spring/slides/16-eigsvd/eigsvd.html - //see the last point - TODO("maybe use SVD") + val (u, s, v) = this.svd() + val shp = s.shape + intArrayOf(1) + val utv = (u.transpose() dot v).map { if (abs(it) < 0.99) 0.0 else sign(it) } + val eig = (utv dot s.view(shp)).view(s.shape) + return Pair(eig, v) } public fun DoubleTensor.detLU(): DoubleTensor { diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index cc127b5a7..c96fcb1c0 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -1,5 +1,6 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.structures.toList import kotlin.math.abs import kotlin.test.Ignore import kotlin.test.Test @@ -137,13 +138,12 @@ class TestDoubleLinearOpsTensorAlgebra { } @Test - @Ignore fun testBatchedSymEig() = DoubleLinearOpsTensorAlgebra { - val tensor = randNormal(shape = intArrayOf(5, 2, 2), 0) + val tensor = randNormal(shape = intArrayOf(5, 3, 3), 0) val tensorSigma = tensor + tensor.transpose() val (tensorS, tensorV) = tensorSigma.symEig() val tensorSigmaCalc = tensorV dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) - assertTrue(tensorSigma.eq(tensorSigmaCalc)) + assertTrue(tensorSigma.eq(tensorSigmaCalc, 0.01)) } From fe8579180d8ebe92b8ba2a41a74d5932d90694a9 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 9 Apr 2021 09:56:37 +0100 Subject: [PATCH 097/178] Open epsilon to client to control numerical precision for power methods --- .../kmath/tensors/LinearOpsTensorAlgebra.kt | 4 ++-- .../core/DoubleLinearOpsTensorAlgebra.kt | 17 +++++++++++------ .../space/kscience/kmath/tensors/core/checks.kt | 6 +++--- .../kscience/kmath/tensors/core/linutils.kt | 6 +++--- .../tensors/core/TestDoubleLinearOpsAlgebra.kt | 2 +- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt index d980c510f..87c459f35 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt @@ -1,7 +1,7 @@ package space.kscience.kmath.tensors -public interface LinearOpsTensorAlgebra, IndexTensorType: TensorStructure> : +public interface LinearOpsTensorAlgebra, IndexTensorType : TensorStructure> : TensorPartialDivisionAlgebra { //https://pytorch.org/docs/stable/linalg.html#torch.linalg.det @@ -26,6 +26,6 @@ public interface LinearOpsTensorAlgebra, Inde public fun TensorType.svd(): Triple //https://pytorch.org/docs/stable/generated/torch.symeig.html - public fun TensorType.symEig(eigenvectors: Boolean = true): Pair + public fun TensorType.symEig(): Pair } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 268f2fe55..95b668917 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -94,8 +94,10 @@ public class DoubleLinearOpsTensorAlgebra : return qTensor to rTensor } + override fun DoubleTensor.svd(): Triple = + svd(epsilon = 1e-10) - override fun DoubleTensor.svd(): Triple { + public fun DoubleTensor.svd(epsilon: Double): Triple { val size = this.linearStructure.dim val commonShape = this.shape.sliceArray(0 until size - 2) val (n, m) = this.shape.sliceArray(size - 2 until size) @@ -110,17 +112,20 @@ public class DoubleLinearOpsTensorAlgebra : matrix.shape, matrix.buffer.array().slice(matrix.bufferStart until matrix.bufferStart + size).toDoubleArray() ) - svdHelper(curMatrix, USV, m, n) + svdHelper(curMatrix, USV, m, n, epsilon) } return Triple(resU.transpose(), resS, resV.transpose()) } + override fun DoubleTensor.symEig(): Pair = + symEig(epsilon = 1e-15) + //http://hua-zhou.github.io/teaching/biostatm280-2017spring/slides/16-eigsvd/eigsvd.html - override fun DoubleTensor.symEig(eigenvectors: Boolean): Pair { - checkSymmetric(this) - val (u, s, v) = this.svd() + public fun DoubleTensor.symEig(epsilon: Double): Pair { + checkSymmetric(this, epsilon) + val (u, s, v) = this.svd(epsilon) val shp = s.shape + intArrayOf(1) - val utv = (u.transpose() dot v).map { if (abs(it) < 0.99) 0.0 else sign(it) } + val utv = (u.transpose() dot v).map { if (abs(it) < 0.9) 0.0 else sign(it) } val eig = (utv dot s.view(shp)).view(s.shape) return Pair(eig, v) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt index 1f70eb300..1dde2ea56 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -58,7 +58,7 @@ internal inline fun , } } -internal inline fun DoubleTensorAlgebra.checkSymmetric(tensor: DoubleTensor): Unit = - check(tensor.eq(tensor.transpose())){ - "Tensor is not symmetric about the last 2 dimensions" +internal inline fun DoubleTensorAlgebra.checkSymmetric(tensor: DoubleTensor, epsilon: Double = 1e-6): Unit = + check(tensor.eq(tensor.transpose(), epsilon)) { + "Tensor is not symmetric about the last 2 dimensions at precision $epsilon" } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt index 1bdfee2d5..685c16a1b 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt @@ -246,7 +246,7 @@ internal inline fun DoubleLinearOpsTensorAlgebra.svd1d(a: DoubleTensor, epsilon: internal inline fun DoubleLinearOpsTensorAlgebra.svdHelper( matrix: DoubleTensor, USV: Pair, Pair, BufferedTensor>>, - m: Int, n: Int + m: Int, n: Int, epsilon: Double ): Unit { val res = ArrayList>(0) val (matrixU, SV) = USV @@ -267,12 +267,12 @@ internal inline fun DoubleLinearOpsTensorAlgebra.svdHelper( var u: DoubleTensor var norm: Double if (n > m) { - v = svd1d(a) + v = svd1d(a, epsilon) u = matrix.dot(v) norm = DoubleAnalyticTensorAlgebra { (u dot u).sqrt().value() } u = u.times(1.0 / norm) } else { - u = svd1d(a) + u = svd1d(a, epsilon) v = matrix.transpose(0, 1).dot(u) norm = DoubleAnalyticTensorAlgebra { (v dot v).sqrt().value() } v = v.times(1.0 / norm) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index c96fcb1c0..0997a9b86 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -143,7 +143,7 @@ class TestDoubleLinearOpsTensorAlgebra { val tensorSigma = tensor + tensor.transpose() val (tensorS, tensorV) = tensorSigma.symEig() val tensorSigmaCalc = tensorV dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) - assertTrue(tensorSigma.eq(tensorSigmaCalc, 0.01)) + assertTrue(tensorSigma.eq(tensorSigmaCalc)) } From a692412cff00241031258e37e1f7c2ad151518f4 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 9 Apr 2021 10:08:55 +0100 Subject: [PATCH 098/178] Safer cleaner for symeig --- .../tensors/core/DoubleLinearOpsTensorAlgebra.kt | 10 ++++++---- .../space/kscience/kmath/tensors/core/linutils.kt | 12 ++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 95b668917..c26046e37 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -3,10 +3,8 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.tensors.LinearOpsTensorAlgebra import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D -import space.kscience.kmath.structures.toList -import kotlin.math.abs import kotlin.math.min -import kotlin.math.sign + public class DoubleLinearOpsTensorAlgebra : LinearOpsTensorAlgebra, @@ -125,7 +123,11 @@ public class DoubleLinearOpsTensorAlgebra : checkSymmetric(this, epsilon) val (u, s, v) = this.svd(epsilon) val shp = s.shape + intArrayOf(1) - val utv = (u.transpose() dot v).map { if (abs(it) < 0.9) 0.0 else sign(it) } + val utv = u.transpose() dot v + val n = s.shape.last() + for( matrix in utv.matrixSequence()) + cleanSymHelper(matrix.as2D(),n) + val eig = (utv dot s.view(shp)).view(s.shape) return Pair(eig, v) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt index 685c16a1b..b3cfc1092 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt @@ -6,6 +6,7 @@ import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D import kotlin.math.abs import kotlin.math.min +import kotlin.math.sign import kotlin.math.sqrt @@ -294,3 +295,14 @@ internal inline fun DoubleLinearOpsTensorAlgebra.svdHelper( matrixV.buffer.array()[matrixV.bufferStart + i] = vBuffer[i] } } + +internal inline fun cleanSymHelper(matrix: MutableStructure2D, n: Int): Unit { + for (i in 0 until n) + for (j in 0 until n) { + if (i == j) { + matrix[i, j] = sign(matrix[i, j]) + } else { + matrix[i, j] = 0.0 + } + } +} From 1e8da7a87bcc00830338d66f8d68fb2dfda7698b Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 9 Apr 2021 10:53:36 +0100 Subject: [PATCH 099/178] Cholesky decomp tests and checks - det to be fixed --- .../tensors/core/DoubleLinearOpsTensorAlgebra.kt | 3 ++- .../space/kscience/kmath/tensors/core/checks.kt | 9 ++++++++- .../tensors/core/TestDoubleLinearOpsAlgebra.kt | 13 +++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index c26046e37..4d6d14764 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -67,9 +67,10 @@ public class DoubleLinearOpsTensorAlgebra : } override fun DoubleTensor.cholesky(): DoubleTensor { - //positive definite check checkSymmetric(this) checkSquareMatrix(shape) + //TODO("Andrei the det routine has bugs") + //checkPositiveDefinite(this) val n = shape.last() val lTensor = zeroesLike() diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt index 1dde2ea56..8dbf9eb81 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -61,4 +61,11 @@ internal inline fun , internal inline fun DoubleTensorAlgebra.checkSymmetric(tensor: DoubleTensor, epsilon: Double = 1e-6): Unit = check(tensor.eq(tensor.transpose(), epsilon)) { "Tensor is not symmetric about the last 2 dimensions at precision $epsilon" - } \ No newline at end of file + } + +internal inline fun DoubleLinearOpsTensorAlgebra.checkPositiveDefinite(tensor: DoubleTensor): Unit { + for( mat in tensor.matrixSequence()) + check(mat.asTensor().detLU().value() > 0.0){ + "Tensor contains matrices which are not positive definite ${mat.asTensor().detLU().value()}" + } +} \ No newline at end of file diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 0997a9b86..2914b216b 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -112,6 +112,19 @@ class TestDoubleLinearOpsTensorAlgebra { assertTrue((p dot tensor).eq(l dot u)) } + @Test + fun testCholesky() = DoubleLinearOpsTensorAlgebra { + val tensor = randNormal(intArrayOf(2, 5, 5), 0) + val sigma = (tensor dot tensor.transpose()) + diagonalEmbedding( + fromArray(intArrayOf(2, 5), DoubleArray(10) { 0.1 }) + ) + //checkPositiveDefinite(sigma) sigma must be positive definite + val low = sigma.cholesky() + val sigmChol = low dot low.transpose() + assertTrue(sigma.eq(sigmChol)) + + } + @Test fun testSVD1D() = DoubleLinearOpsTensorAlgebra { val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) From b51427d2abb401d1402eebd7bf61e93bca47f3a2 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 9 Apr 2021 12:26:03 +0100 Subject: [PATCH 100/178] test to fix determinant --- .../tensors/core/TestDoubleLinearOpsAlgebra.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 2914b216b..37caf88fe 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -34,6 +34,19 @@ class TestDoubleLinearOpsTensorAlgebra { } + @Test + fun testDet() = DoubleLinearOpsTensorAlgebra { + val m = fromArray( + intArrayOf(3, 3), doubleArrayOf( + 2.1843, 1.4391, -0.4845, + 1.4391, 1.7772, 0.4055, + -0.4845, 0.4055, 0.7519 + ) + ) + println(m.det().value()) + println(0.0197) //expected value + } + @Test fun testInvLU() = DoubleLinearOpsTensorAlgebra { val tensor = fromArray( From 75783bcb038d1649f5587a15e906d9450fce5c8c Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 9 Apr 2021 14:06:44 +0100 Subject: [PATCH 101/178] some todos --- .../kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 4d6d14764..82f63dd40 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -154,6 +154,7 @@ public class DoubleLinearOpsTensorAlgebra : } public fun DoubleTensor.invLU(): DoubleTensor { + //TODO("Andrei the det is non-zero") val (luTensor, pivotsTensor) = lu() val invTensor = luTensor.zeroesLike() From a2d41d5e73e8eef1413a4f1671d0717b8b97aa9b Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 14 Apr 2021 20:30:42 +0100 Subject: [PATCH 102/178] Cholesky with precision in client API --- .../kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt | 7 ++++--- .../kotlin/space/kscience/kmath/tensors/core/checks.kt | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 82f63dd40..e0ec49333 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -66,11 +66,10 @@ public class DoubleLinearOpsTensorAlgebra : } - override fun DoubleTensor.cholesky(): DoubleTensor { - checkSymmetric(this) + public fun DoubleTensor.cholesky(epsilon: Double): DoubleTensor { checkSquareMatrix(shape) //TODO("Andrei the det routine has bugs") - //checkPositiveDefinite(this) + //checkPositiveDefinite(this, epsilon) val n = shape.last() val lTensor = zeroesLike() @@ -81,6 +80,8 @@ public class DoubleLinearOpsTensorAlgebra : return lTensor } + override fun DoubleTensor.cholesky(): DoubleTensor = cholesky(1e-6) + override fun DoubleTensor.qr(): Pair { checkSquareMatrix(shape) val qTensor = zeroesLike() diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt index 8dbf9eb81..730b6ed9a 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -63,7 +63,9 @@ internal inline fun DoubleTensorAlgebra.checkSymmetric(tensor: DoubleTensor, eps "Tensor is not symmetric about the last 2 dimensions at precision $epsilon" } -internal inline fun DoubleLinearOpsTensorAlgebra.checkPositiveDefinite(tensor: DoubleTensor): Unit { +internal inline fun DoubleLinearOpsTensorAlgebra.checkPositiveDefinite( + tensor: DoubleTensor, epsilon: Double = 1e-6): Unit { + checkSymmetric(tensor, epsilon) for( mat in tensor.matrixSequence()) check(mat.asTensor().detLU().value() > 0.0){ "Tensor contains matrices which are not positive definite ${mat.asTensor().detLU().value()}" From c7669d4fba20ccd856918504d4836d2619961927 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Wed, 14 Apr 2021 23:05:54 +0300 Subject: [PATCH 103/178] fix det --- .../core/DoubleLinearOpsTensorAlgebra.kt | 22 +++++++++---- .../kscience/kmath/tensors/core/checks.kt | 10 ++++++ .../kscience/kmath/tensors/core/linutils.kt | 11 +++++-- .../core/TestDoubleLinearOpsAlgebra.kt | 17 ++++++++-- kmath-tensors/src/jvmMain/kotlin/andMain.kt | 32 +++++++++++++++++++ 5 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 kmath-tensors/src/jvmMain/kotlin/andMain.kt diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 82f63dd40..59678947a 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -14,8 +14,7 @@ public class DoubleLinearOpsTensorAlgebra : override fun DoubleTensor.det(): DoubleTensor = detLU() - override fun DoubleTensor.lu(): Pair { - + internal fun DoubleTensor.luForDet(forDet: Boolean = false): Pair { checkSquareMatrix(shape) val luTensor = copy() @@ -31,10 +30,22 @@ public class DoubleLinearOpsTensorAlgebra : ) for ((lu, pivots) in luTensor.matrixSequence().zip(pivotsTensor.vectorSequence())) - luHelper(lu.as2D(), pivots.as1D(), m) + try { + luHelper(lu.as2D(), pivots.as1D(), m) + } catch (e: RuntimeException) { + if (forDet) { + lu.as2D()[intArrayOf(0, 0)] = 0.0 + } else { + throw IllegalStateException("LUP decomposition can't be performed") + } + } + return Pair(luTensor, pivotsTensor) + } + override fun DoubleTensor.lu(): Pair { + return luForDet(false) } override fun luPivot( @@ -69,8 +80,7 @@ public class DoubleLinearOpsTensorAlgebra : override fun DoubleTensor.cholesky(): DoubleTensor { checkSymmetric(this) checkSquareMatrix(shape) - //TODO("Andrei the det routine has bugs") - //checkPositiveDefinite(this) + checkPositiveDefinite(this) val n = shape.last() val lTensor = zeroesLike() @@ -134,7 +144,7 @@ public class DoubleLinearOpsTensorAlgebra : } public fun DoubleTensor.detLU(): DoubleTensor { - val (luTensor, pivotsTensor) = lu() + val (luTensor, pivotsTensor) = luForDet(forDet = true) val n = shape.size val detTensorShape = IntArray(n - 1) { i -> shape[i] } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt index 8dbf9eb81..c61759da2 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -2,6 +2,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.tensors.TensorAlgebra import space.kscience.kmath.tensors.TensorStructure +import kotlin.math.abs internal inline fun , @@ -68,4 +69,13 @@ internal inline fun DoubleLinearOpsTensorAlgebra.checkPositiveDefinite(tensor: D check(mat.asTensor().detLU().value() > 0.0){ "Tensor contains matrices which are not positive definite ${mat.asTensor().detLU().value()}" } +} + +internal inline fun DoubleLinearOpsTensorAlgebra.checkNonSingularMatrix(tensor: DoubleTensor): Unit { + for( mat in tensor.matrixSequence()) { + val detTensor = mat.asTensor().detLU() + check(!(detTensor.eq(detTensor.zeroesLike()))){ + "Tensor contains matrices which are singular" + } + } } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt index b3cfc1092..f2c9d8c76 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt @@ -62,10 +62,10 @@ internal inline fun dotHelper( } internal inline fun luHelper(lu: MutableStructure2D, pivots: MutableStructure1D, m: Int) { - for (row in 0 until m) pivots[row] = row + for (row in 0..m) pivots[row] = row for (i in 0 until m) { - var maxVal = -1.0 + var maxVal = 0.0 var maxInd = i for (k in i until m) { @@ -76,7 +76,9 @@ internal inline fun luHelper(lu: MutableStructure2D, pivots: MutableStru } } - //todo check singularity + if (abs(maxVal) < 1e-9) { + throw RuntimeException() + } if (maxInd != i) { @@ -158,6 +160,9 @@ internal inline fun choleskyHelper( internal inline fun luMatrixDet(luTensor: MutableStructure2D, pivotsTensor: MutableStructure1D): Double { val lu = luTensor.as2D() val pivots = pivotsTensor.as1D() + if (lu[0, 0] == 0.0) { + return 0.0 + } val m = lu.shape[0] val sign = if ((pivots[m] - m) % 2 == 0) 1.0 else -1.0 return (0 until m).asSequence().map { lu[it, it] }.fold(sign) { left, right -> left * right } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 37caf88fe..75ff12355 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -36,6 +36,7 @@ class TestDoubleLinearOpsTensorAlgebra { @Test fun testDet() = DoubleLinearOpsTensorAlgebra { + val expectedValue = 0.019827417 val m = fromArray( intArrayOf(3, 3), doubleArrayOf( 2.1843, 1.4391, -0.4845, @@ -43,8 +44,20 @@ class TestDoubleLinearOpsTensorAlgebra { -0.4845, 0.4055, 0.7519 ) ) - println(m.det().value()) - println(0.0197) //expected value + + assertTrue { abs(m.det().value() - expectedValue) < 1e-5} + } + + @Test + fun testDetSingle() = DoubleLinearOpsTensorAlgebra { + val expectedValue = 48.151623 + val m = fromArray( + intArrayOf(1, 1), doubleArrayOf( + expectedValue + ) + ) + + assertTrue { abs(m.det().value() - expectedValue) < 1e-5} } @Test diff --git a/kmath-tensors/src/jvmMain/kotlin/andMain.kt b/kmath-tensors/src/jvmMain/kotlin/andMain.kt new file mode 100644 index 000000000..68facf467 --- /dev/null +++ b/kmath-tensors/src/jvmMain/kotlin/andMain.kt @@ -0,0 +1,32 @@ +import space.kscience.kmath.nd.* +import space.kscience.kmath.tensors.core.DoubleLinearOpsTensorAlgebra +import space.kscience.kmath.tensors.core.DoubleTensorAlgebra +import space.kscience.kmath.tensors.core.array +import kotlin.math.abs +import kotlin.math.sqrt + + +fun main() { + + DoubleTensorAlgebra { + val tensor = fromArray( + intArrayOf(2, 2, 2), + doubleArrayOf( + 1.0, 3.0, + 1.0, 2.0, + 1.5, 1.0, + 10.0, 2.0 + ) + ) + val tensor2 = fromArray( + intArrayOf(2, 2), + doubleArrayOf( + 0.0, 0.0, + 0.0, 0.0 + ) + ) + DoubleLinearOpsTensorAlgebra { + println(tensor2.det().value()) + } + } +} From aeb71b5d270f7e40f8c5b8c2416c163e6baec206 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Wed, 14 Apr 2021 23:10:42 +0300 Subject: [PATCH 104/178] fix det --- .../core/DoubleLinearOpsTensorAlgebra.kt | 28 +++++++++++++------ .../kscience/kmath/tensors/core/checks.kt | 14 +++++++++- .../kscience/kmath/tensors/core/linutils.kt | 11 ++++++-- .../core/TestDoubleLinearOpsAlgebra.kt | 17 +++++++++-- 4 files changed, 56 insertions(+), 14 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index 82f63dd40..027fcf5d0 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -14,8 +14,7 @@ public class DoubleLinearOpsTensorAlgebra : override fun DoubleTensor.det(): DoubleTensor = detLU() - override fun DoubleTensor.lu(): Pair { - + internal fun DoubleTensor.luForDet(forDet: Boolean = false): Pair { checkSquareMatrix(shape) val luTensor = copy() @@ -31,10 +30,22 @@ public class DoubleLinearOpsTensorAlgebra : ) for ((lu, pivots) in luTensor.matrixSequence().zip(pivotsTensor.vectorSequence())) - luHelper(lu.as2D(), pivots.as1D(), m) + try { + luHelper(lu.as2D(), pivots.as1D(), m) + } catch (e: RuntimeException) { + if (forDet) { + lu.as2D()[intArrayOf(0, 0)] = 0.0 + } else { + throw IllegalStateException("LUP decomposition can't be performed") + } + } + return Pair(luTensor, pivotsTensor) + } + override fun DoubleTensor.lu(): Pair { + return luForDet(false) } override fun luPivot( @@ -66,11 +77,10 @@ public class DoubleLinearOpsTensorAlgebra : } - override fun DoubleTensor.cholesky(): DoubleTensor { - checkSymmetric(this) + public fun DoubleTensor.cholesky(epsilon: Double): DoubleTensor { checkSquareMatrix(shape) - //TODO("Andrei the det routine has bugs") - //checkPositiveDefinite(this) + checkPositiveDefinite(this) + //checkPositiveDefinite(this, epsilon) val n = shape.last() val lTensor = zeroesLike() @@ -81,6 +91,8 @@ public class DoubleLinearOpsTensorAlgebra : return lTensor } + override fun DoubleTensor.cholesky(): DoubleTensor = cholesky(1e-6) + override fun DoubleTensor.qr(): Pair { checkSquareMatrix(shape) val qTensor = zeroesLike() @@ -134,7 +146,7 @@ public class DoubleLinearOpsTensorAlgebra : } public fun DoubleTensor.detLU(): DoubleTensor { - val (luTensor, pivotsTensor) = lu() + val (luTensor, pivotsTensor) = luForDet(forDet = true) val n = shape.size val detTensorShape = IntArray(n - 1) { i -> shape[i] } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt index 8dbf9eb81..45a71d1bc 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -2,6 +2,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.tensors.TensorAlgebra import space.kscience.kmath.tensors.TensorStructure +import kotlin.math.abs internal inline fun , @@ -63,9 +64,20 @@ internal inline fun DoubleTensorAlgebra.checkSymmetric(tensor: DoubleTensor, eps "Tensor is not symmetric about the last 2 dimensions at precision $epsilon" } -internal inline fun DoubleLinearOpsTensorAlgebra.checkPositiveDefinite(tensor: DoubleTensor): Unit { +internal inline fun DoubleLinearOpsTensorAlgebra.checkPositiveDefinite( + tensor: DoubleTensor, epsilon: Double = 1e-6): Unit { + checkSymmetric(tensor, epsilon) for( mat in tensor.matrixSequence()) check(mat.asTensor().detLU().value() > 0.0){ "Tensor contains matrices which are not positive definite ${mat.asTensor().detLU().value()}" } +} + +internal inline fun DoubleLinearOpsTensorAlgebra.checkNonSingularMatrix(tensor: DoubleTensor): Unit { + for( mat in tensor.matrixSequence()) { + val detTensor = mat.asTensor().detLU() + check(!(detTensor.eq(detTensor.zeroesLike()))){ + "Tensor contains matrices which are singular" + } + } } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt index b3cfc1092..f2c9d8c76 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt @@ -62,10 +62,10 @@ internal inline fun dotHelper( } internal inline fun luHelper(lu: MutableStructure2D, pivots: MutableStructure1D, m: Int) { - for (row in 0 until m) pivots[row] = row + for (row in 0..m) pivots[row] = row for (i in 0 until m) { - var maxVal = -1.0 + var maxVal = 0.0 var maxInd = i for (k in i until m) { @@ -76,7 +76,9 @@ internal inline fun luHelper(lu: MutableStructure2D, pivots: MutableStru } } - //todo check singularity + if (abs(maxVal) < 1e-9) { + throw RuntimeException() + } if (maxInd != i) { @@ -158,6 +160,9 @@ internal inline fun choleskyHelper( internal inline fun luMatrixDet(luTensor: MutableStructure2D, pivotsTensor: MutableStructure1D): Double { val lu = luTensor.as2D() val pivots = pivotsTensor.as1D() + if (lu[0, 0] == 0.0) { + return 0.0 + } val m = lu.shape[0] val sign = if ((pivots[m] - m) % 2 == 0) 1.0 else -1.0 return (0 until m).asSequence().map { lu[it, it] }.fold(sign) { left, right -> left * right } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 37caf88fe..75ff12355 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -36,6 +36,7 @@ class TestDoubleLinearOpsTensorAlgebra { @Test fun testDet() = DoubleLinearOpsTensorAlgebra { + val expectedValue = 0.019827417 val m = fromArray( intArrayOf(3, 3), doubleArrayOf( 2.1843, 1.4391, -0.4845, @@ -43,8 +44,20 @@ class TestDoubleLinearOpsTensorAlgebra { -0.4845, 0.4055, 0.7519 ) ) - println(m.det().value()) - println(0.0197) //expected value + + assertTrue { abs(m.det().value() - expectedValue) < 1e-5} + } + + @Test + fun testDetSingle() = DoubleLinearOpsTensorAlgebra { + val expectedValue = 48.151623 + val m = fromArray( + intArrayOf(1, 1), doubleArrayOf( + expectedValue + ) + ) + + assertTrue { abs(m.det().value() - expectedValue) < 1e-5} } @Test From b46e8c5fe23bb64fa6868363848e2e13e0c1edfb Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 14 Apr 2021 22:13:54 +0100 Subject: [PATCH 105/178] LU and det refactored --- .../core/DoubleLinearOpsTensorAlgebra.kt | 64 ++++++------------- .../kscience/kmath/tensors/core/linutils.kt | 43 +++++++++++-- .../core/TestDoubleLinearOpsAlgebra.kt | 8 +-- 3 files changed, 59 insertions(+), 56 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index a6bd5d5f7..e72948c84 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -10,43 +10,15 @@ public class DoubleLinearOpsTensorAlgebra : LinearOpsTensorAlgebra, DoubleTensorAlgebra() { - override fun DoubleTensor.inv(): DoubleTensor = invLU() + override fun DoubleTensor.inv(): DoubleTensor = invLU(1e-9) - override fun DoubleTensor.det(): DoubleTensor = detLU() + override fun DoubleTensor.det(): DoubleTensor = detLU(1e-9) - internal fun DoubleTensor.luForDet(forDet: Boolean = false): Pair { - checkSquareMatrix(shape) + public fun DoubleTensor.lu(epsilon: Double): Pair = + computeLU(this, epsilon) ?: + throw RuntimeException("Tensor contains matrices which are singular at precision $epsilon") - val luTensor = copy() - - val n = shape.size - val m = shape.last() - val pivotsShape = IntArray(n - 1) { i -> shape[i] } - pivotsShape[n - 2] = m + 1 - - val pivotsTensor = IntTensor( - pivotsShape, - IntArray(pivotsShape.reduce(Int::times)) { 0 } - ) - - for ((lu, pivots) in luTensor.matrixSequence().zip(pivotsTensor.vectorSequence())) - try { - luHelper(lu.as2D(), pivots.as1D(), m) - } catch (e: RuntimeException) { - if (forDet) { - lu.as2D()[intArrayOf(0, 0)] = 0.0 - } else { - throw IllegalStateException("LUP decomposition can't be performed") - } - } - - - return Pair(luTensor, pivotsTensor) - } - - override fun DoubleTensor.lu(): Pair { - return luForDet(false) - } + override fun DoubleTensor.lu(): Pair = lu(1e-9) override fun luPivot( luTensor: DoubleTensor, @@ -79,9 +51,7 @@ public class DoubleLinearOpsTensorAlgebra : public fun DoubleTensor.cholesky(epsilon: Double): DoubleTensor { checkSquareMatrix(shape) - checkPositiveDefinite(this) - //checkPositiveDefinite(this, epsilon) - + checkPositiveDefinite(this, epsilon) val n = shape.last() val lTensor = zeroesLike() @@ -139,15 +109,19 @@ public class DoubleLinearOpsTensorAlgebra : val shp = s.shape + intArrayOf(1) val utv = u.transpose() dot v val n = s.shape.last() - for( matrix in utv.matrixSequence()) - cleanSymHelper(matrix.as2D(),n) + for (matrix in utv.matrixSequence()) + cleanSymHelper(matrix.as2D(), n) val eig = (utv dot s.view(shp)).view(s.shape) return Pair(eig, v) } - public fun DoubleTensor.detLU(): DoubleTensor { - val (luTensor, pivotsTensor) = luForDet(forDet = true) + public fun DoubleTensor.detLU(epsilon: Double = 1e-9): DoubleTensor { + + checkSquareMatrix(this.shape) + val luTensor = this.copy() + val pivotsTensor = this.setUpPivots() + val n = shape.size val detTensorShape = IntArray(n - 1) { i -> shape[i] } @@ -160,15 +134,15 @@ public class DoubleLinearOpsTensorAlgebra : ) luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).forEachIndexed { index, (lu, pivots) -> - resBuffer[index] = luMatrixDet(lu.as2D(), pivots.as1D()) + resBuffer[index] = if (luHelper(lu.as2D(), pivots.as1D(), epsilon)) + 0.0 else luMatrixDet(lu.as2D(), pivots.as1D()) } return detTensor } - public fun DoubleTensor.invLU(): DoubleTensor { - //TODO("Andrei the det is non-zero") - val (luTensor, pivotsTensor) = lu() + public fun DoubleTensor.invLU(epsilon: Double = 1e-9): DoubleTensor { + val (luTensor, pivotsTensor) = lu(epsilon) val invTensor = luTensor.zeroesLike() val seq = luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).zip(invTensor.matrixSequence()) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt index f2c9d8c76..ee159b614 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt @@ -61,7 +61,13 @@ internal inline fun dotHelper( } } -internal inline fun luHelper(lu: MutableStructure2D, pivots: MutableStructure1D, m: Int) { +internal inline fun luHelper( + lu: MutableStructure2D, + pivots: MutableStructure1D, + epsilon: Double): Boolean { + + val m = lu.rowNum + for (row in 0..m) pivots[row] = row for (i in 0 until m) { @@ -69,16 +75,15 @@ internal inline fun luHelper(lu: MutableStructure2D, pivots: MutableStru var maxInd = i for (k in i until m) { - val absA = kotlin.math.abs(lu[k, i]) + val absA = abs(lu[k, i]) if (absA > maxVal) { maxVal = absA maxInd = k } } - if (abs(maxVal) < 1e-9) { - throw RuntimeException() - } + if (abs(maxVal) < epsilon) + return true // matrix is singular if (maxInd != i) { @@ -103,6 +108,34 @@ internal inline fun luHelper(lu: MutableStructure2D, pivots: MutableStru } } } + return false +} + +internal inline fun BufferedTensor.setUpPivots(): IntTensor { + val n = this.shape.size + val m = this.shape.last() + val pivotsShape = IntArray(n - 1) { i -> this.shape[i] } + pivotsShape[n - 2] = m + 1 + + return IntTensor( + pivotsShape, + IntArray(pivotsShape.reduce(Int::times)) { 0 } + ) +} + +internal inline fun DoubleLinearOpsTensorAlgebra.computeLU( + tensor: DoubleTensor, + epsilon: Double): Pair? { + + checkSquareMatrix(tensor.shape) + val luTensor = tensor.copy() + val pivotsTensor = tensor.setUpPivots() + + for ((lu, pivots) in luTensor.matrixSequence().zip(pivotsTensor.vectorSequence())) + if(luHelper(lu.as2D(), pivots.as1D(), epsilon)) + return null + + return Pair(luTensor, pivotsTensor) } internal inline fun pivInit( diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 75ff12355..d19d0b6f6 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -1,8 +1,6 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.structures.toList import kotlin.math.abs -import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -45,7 +43,7 @@ class TestDoubleLinearOpsTensorAlgebra { ) ) - assertTrue { abs(m.det().value() - expectedValue) < 1e-5} + assertTrue { abs(m.det().value() - expectedValue) < 1e-5 } } @Test @@ -57,7 +55,7 @@ class TestDoubleLinearOpsTensorAlgebra { ) ) - assertTrue { abs(m.det().value() - expectedValue) < 1e-5} + assertTrue { abs(m.det().value() - expectedValue) < 1e-5 } } @Test @@ -144,11 +142,9 @@ class TestDoubleLinearOpsTensorAlgebra { val sigma = (tensor dot tensor.transpose()) + diagonalEmbedding( fromArray(intArrayOf(2, 5), DoubleArray(10) { 0.1 }) ) - //checkPositiveDefinite(sigma) sigma must be positive definite val low = sigma.cholesky() val sigmChol = low dot low.transpose() assertTrue(sigma.eq(sigmChol)) - } @Test From 0fa73e1e9e4cca8cf4377d580bbfbcceb394d8c0 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 14 Apr 2021 22:21:18 +0100 Subject: [PATCH 106/178] Drop unused code --- .../kotlin/space/kscience/kmath/tensors/core/checks.kt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt index 45a71d1bc..730b6ed9a 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -2,7 +2,6 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.tensors.TensorAlgebra import space.kscience.kmath.tensors.TensorStructure -import kotlin.math.abs internal inline fun , @@ -71,13 +70,4 @@ internal inline fun DoubleLinearOpsTensorAlgebra.checkPositiveDefinite( check(mat.asTensor().detLU().value() > 0.0){ "Tensor contains matrices which are not positive definite ${mat.asTensor().detLU().value()}" } -} - -internal inline fun DoubleLinearOpsTensorAlgebra.checkNonSingularMatrix(tensor: DoubleTensor): Unit { - for( mat in tensor.matrixSequence()) { - val detTensor = mat.asTensor().detLU() - check(!(detTensor.eq(detTensor.zeroesLike()))){ - "Tensor contains matrices which are singular" - } - } } \ No newline at end of file From b7da52edb196769ac5afb42ae5dbdca6bedd58f5 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Thu, 15 Apr 2021 23:10:15 +0300 Subject: [PATCH 107/178] pretty printer --- .../kscience/kmath/tensors/core/utils.kt | 48 +++++++++++++- .../src/jvmMain/kotlin/tensorPrettyPrinter.kt | 64 +++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 kmath-tensors/src/jvmMain/kotlin/tensorPrettyPrinter.kt diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index 392abd1c2..e67591c9e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -1,5 +1,7 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.nd.as1D +import space.kscience.kmath.nd.as2D import space.kscience.kmath.samplers.GaussianSampler import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.structures.* @@ -57,4 +59,48 @@ internal inline fun minusIndexFrom(n: Int, i: Int) : Int = if (i >= 0) i else { ii } -internal inline fun BufferedTensor.minusIndex(i: Int): Int = minusIndexFrom(this.linearStructure.dim, i) \ No newline at end of file +internal inline fun BufferedTensor.minusIndex(i: Int): Int = minusIndexFrom(this.linearStructure.dim, i) + +public fun DoubleTensor.toPrettyString(): String = buildString { + var offset = 0 + val shape = this@toPrettyString.shape + val linearStructure = this@toPrettyString.linearStructure + var vectorSize = shape.last() + val initString = "DoubleTensor(\n" + append(initString) + var charOffset = 3 + for (vector in vectorSequence()) { + append(" ".repeat(charOffset)) + val index = linearStructure.index(offset) + for (ind in index.reversed()) { + if (ind != 0) { + break + } + append("[") + charOffset += 1 + } + // todo refactor + val values = mutableListOf() + for (i in 0 until vectorSize) { + values.add(vector[intArrayOf(i)]) + } + // todo apply exp formatting + append(values.joinToString(", ")) + append("]") + charOffset -= 1 + for ((ind, maxInd) in index.reversed().zip(shape.reversed()).drop(1)){ + if (ind != maxInd - 1) { + break + } + append("]") + charOffset -=1 + } + offset += vectorSize + // todo refactor + if (this@toPrettyString.numel == offset) { + break + } + append(",\n") + } + append("\n)") +} diff --git a/kmath-tensors/src/jvmMain/kotlin/tensorPrettyPrinter.kt b/kmath-tensors/src/jvmMain/kotlin/tensorPrettyPrinter.kt new file mode 100644 index 000000000..669a5494b --- /dev/null +++ b/kmath-tensors/src/jvmMain/kotlin/tensorPrettyPrinter.kt @@ -0,0 +1,64 @@ + +import space.kscience.kmath.tensors.core.DoubleTensor +import space.kscience.kmath.tensors.core.vectorSequence +import java.lang.StringBuilder + +internal fun format(value: Double, digits: Int = 4): String { + val res = "%.${digits}e".format(value).replace(',', '.') + if (value < 0.0) { + return res + } + return StringBuilder().append(" ").append(res).toString() +} + +public fun DoubleTensor.toPrettyString(): String { + val builder = StringBuilder() + with(builder) { + var offset = 0 + val shape = this@toPrettyString.shape + val linearStructure = this@toPrettyString.linearStructure + var vectorSize = shape.last() + val initString = "DoubleTensor(\n" + append(initString) + var charOffset = 3 + for (vector in vectorSequence()) { + append(" ".repeat(charOffset)) + val index = linearStructure.index(offset) + for (ind in index.reversed()) { + if (ind != 0) { + break + } + append("[") + charOffset += 1 + } + // todo refactor + val values = mutableListOf() + for (i in 0 until vectorSize) { + values.add(vector[intArrayOf(i)]) + } + append(values.map { format(it) }.joinToString(", ")) + append("]") + charOffset -= 1 + for (i in shape.size - 2 downTo 0){ + val ind = index[i] + val maxInd = shape[i] + if (ind != maxInd - 1) { + break + } + append("]") + charOffset -=1 + } + offset += vectorSize + // todo refactor + if (this@toPrettyString.numel == offset) { + break + } + append(",\n") + } + append("\n)") + } + return builder.toString() +} + + + From 41ac72b4fbf5527a9a37296da90ff412e66cf542 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 16 Apr 2021 07:45:31 +0100 Subject: [PATCH 108/178] MPP toString for DoubleTensor --- .../kmath/tensors/core/BufferedTensor.kt | 4 ++- .../kscience/kmath/tensors/core/linutils.kt | 4 +-- .../kscience/kmath/tensors/core/utils.kt | 33 ++++++++++++++----- .../src/jvmMain/kotlin/tensorPrettyPrinter.kt | 4 +-- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 9a4d13d2c..9e393f1a8 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -4,7 +4,6 @@ import space.kscience.kmath.structures.* import space.kscience.kmath.tensors.TensorStructure - public open class BufferedTensor( override val shape: IntArray, public val buffer: MutableBuffer, @@ -70,6 +69,9 @@ public class DoubleTensor internal constructor( { internal constructor(bufferedTensor: BufferedTensor): this(bufferedTensor.shape, bufferedTensor.buffer.array(), bufferedTensor.bufferStart) + + override fun toString(): String = toPrettyString() + } internal fun BufferedTensor.asTensor(): IntTensor = IntTensor(this) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt index ee159b614..ba5e0caaf 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt @@ -190,9 +190,7 @@ internal inline fun choleskyHelper( } } -internal inline fun luMatrixDet(luTensor: MutableStructure2D, pivotsTensor: MutableStructure1D): Double { - val lu = luTensor.as2D() - val pivots = pivotsTensor.as1D() +internal inline fun luMatrixDet(lu: MutableStructure2D, pivots: MutableStructure1D): Double { if (lu[0, 0] == 0.0) { return 0.0 } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index e67591c9e..daab79016 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -1,11 +1,11 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.as1D -import space.kscience.kmath.nd.as2D import space.kscience.kmath.samplers.GaussianSampler import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.structures.* -import kotlin.math.sqrt +import kotlin.math.* /** * Returns a reference to [IntArray] containing all of the elements of this [Buffer]. @@ -61,7 +61,25 @@ internal inline fun minusIndexFrom(n: Int, i: Int) : Int = if (i >= 0) i else { internal inline fun BufferedTensor.minusIndex(i: Int): Int = minusIndexFrom(this.linearStructure.dim, i) -public fun DoubleTensor.toPrettyString(): String = buildString { +internal inline fun format(value: Double, digits: Int = 4): String { + val ten = 10.0 + val approxOrder = ceil(log10(abs(value))).toInt() + val order = if( + ((value % ten) == 0.0) or + (value == 1.0) or + ((1/value) % ten == 0.0)) approxOrder else approxOrder - 1 + + val lead = value / ten.pow(order) + val leadDisplay = round(lead*ten.pow(digits)) / ten.pow(digits) + val orderDisplay = if(order >= 0) "+$order" else "$order" + val valueDisplay = "${leadDisplay}E$orderDisplay" + val res = if(value < 0.0) valueDisplay else " $valueDisplay" + val fLength = digits + 6 + val endSpace = " ".repeat(fLength - res.length) + return "$res$endSpace" +} + +internal inline fun DoubleTensor.toPrettyString(): String = buildString { var offset = 0 val shape = this@toPrettyString.shape val linearStructure = this@toPrettyString.linearStructure @@ -79,12 +97,9 @@ public fun DoubleTensor.toPrettyString(): String = buildString { append("[") charOffset += 1 } - // todo refactor - val values = mutableListOf() - for (i in 0 until vectorSize) { - values.add(vector[intArrayOf(i)]) - } - // todo apply exp formatting + + val values = vector.as1D().toMutableList().map(::format) + append(values.joinToString(", ")) append("]") charOffset -= 1 diff --git a/kmath-tensors/src/jvmMain/kotlin/tensorPrettyPrinter.kt b/kmath-tensors/src/jvmMain/kotlin/tensorPrettyPrinter.kt index 669a5494b..d3ce5933e 100644 --- a/kmath-tensors/src/jvmMain/kotlin/tensorPrettyPrinter.kt +++ b/kmath-tensors/src/jvmMain/kotlin/tensorPrettyPrinter.kt @@ -2,7 +2,7 @@ import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.vectorSequence import java.lang.StringBuilder - +/* internal fun format(value: Double, digits: Int = 4): String { val res = "%.${digits}e".format(value).replace(',', '.') if (value < 0.0) { @@ -59,6 +59,6 @@ public fun DoubleTensor.toPrettyString(): String { } return builder.toString() } - +*/ From baa303171eb9a6a99b3f5e83cae87a1e0a1abb5f Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 16 Apr 2021 07:47:06 +0100 Subject: [PATCH 109/178] No jvm specifics please --- .../src/jvmMain/kotlin/tensorPrettyPrinter.kt | 64 ------------------- 1 file changed, 64 deletions(-) delete mode 100644 kmath-tensors/src/jvmMain/kotlin/tensorPrettyPrinter.kt diff --git a/kmath-tensors/src/jvmMain/kotlin/tensorPrettyPrinter.kt b/kmath-tensors/src/jvmMain/kotlin/tensorPrettyPrinter.kt deleted file mode 100644 index d3ce5933e..000000000 --- a/kmath-tensors/src/jvmMain/kotlin/tensorPrettyPrinter.kt +++ /dev/null @@ -1,64 +0,0 @@ - -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.vectorSequence -import java.lang.StringBuilder -/* -internal fun format(value: Double, digits: Int = 4): String { - val res = "%.${digits}e".format(value).replace(',', '.') - if (value < 0.0) { - return res - } - return StringBuilder().append(" ").append(res).toString() -} - -public fun DoubleTensor.toPrettyString(): String { - val builder = StringBuilder() - with(builder) { - var offset = 0 - val shape = this@toPrettyString.shape - val linearStructure = this@toPrettyString.linearStructure - var vectorSize = shape.last() - val initString = "DoubleTensor(\n" - append(initString) - var charOffset = 3 - for (vector in vectorSequence()) { - append(" ".repeat(charOffset)) - val index = linearStructure.index(offset) - for (ind in index.reversed()) { - if (ind != 0) { - break - } - append("[") - charOffset += 1 - } - // todo refactor - val values = mutableListOf() - for (i in 0 until vectorSize) { - values.add(vector[intArrayOf(i)]) - } - append(values.map { format(it) }.joinToString(", ")) - append("]") - charOffset -= 1 - for (i in shape.size - 2 downTo 0){ - val ind = index[i] - val maxInd = shape[i] - if (ind != maxInd - 1) { - break - } - append("]") - charOffset -=1 - } - offset += vectorSize - // todo refactor - if (this@toPrettyString.numel == offset) { - break - } - append(",\n") - } - append("\n)") - } - return builder.toString() -} -*/ - - From 1e7cf39150be8393acd0f24572d0a1a93ef87e15 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 16 Apr 2021 11:58:42 +0100 Subject: [PATCH 110/178] Don't print 0 order --- .../kotlin/space/kscience/kmath/tensors/core/utils.kt | 6 +++--- .../space/kscience/kmath/tensors/core/TestDoubleTensor.kt | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index daab79016..40d40b593 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -71,8 +71,8 @@ internal inline fun format(value: Double, digits: Int = 4): String { val lead = value / ten.pow(order) val leadDisplay = round(lead*ten.pow(digits)) / ten.pow(digits) - val orderDisplay = if(order >= 0) "+$order" else "$order" - val valueDisplay = "${leadDisplay}E$orderDisplay" + val orderDisplay = if(order == 0) "" else if(order > 0) "E+$order" else "E$order" + val valueDisplay = "${leadDisplay}$orderDisplay" val res = if(value < 0.0) valueDisplay else " $valueDisplay" val fLength = digits + 6 val endSpace = " ".repeat(fLength - res.length) @@ -83,7 +83,7 @@ internal inline fun DoubleTensor.toPrettyString(): String = buildString { var offset = 0 val shape = this@toPrettyString.shape val linearStructure = this@toPrettyString.linearStructure - var vectorSize = shape.last() + val vectorSize = shape.last() val initString = "DoubleTensor(\n" append(initString) var charOffset = 3 diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index 4f4d9bbdf..ddcf0369c 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -46,4 +46,10 @@ class TestDoubleTensor { assertEquals(secondRow[1], secondColumn[1]) } } + + @Test + fun toStringTest() = DoubleTensorAlgebra { + val tensor = randNormal(intArrayOf(2,3)) + println(tensor) + } } \ No newline at end of file From 4f8ab4dd78ea1a9a8925fce8898c33313e6be9ec Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 16 Apr 2021 12:03:27 +0100 Subject: [PATCH 111/178] Ignore print test --- .../kotlin/space/kscience/kmath/tensors/core/utils.kt | 3 +-- .../space/kscience/kmath/tensors/core/TestDoubleTensor.kt | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index 40d40b593..0b2b5c0df 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -1,6 +1,5 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.as1D import space.kscience.kmath.samplers.GaussianSampler import space.kscience.kmath.stat.RandomGenerator @@ -72,7 +71,7 @@ internal inline fun format(value: Double, digits: Int = 4): String { val lead = value / ten.pow(order) val leadDisplay = round(lead*ten.pow(digits)) / ten.pow(digits) val orderDisplay = if(order == 0) "" else if(order > 0) "E+$order" else "E$order" - val valueDisplay = "${leadDisplay}$orderDisplay" + val valueDisplay = "$leadDisplay$orderDisplay" val res = if(value < 0.0) valueDisplay else " $valueDisplay" val fLength = digits + 6 val endSpace = " ".repeat(fLength - res.length) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index ddcf0369c..f950dfce3 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -1,8 +1,10 @@ package space.kscience.kmath.tensors.core +import kotlinx.coroutines.InternalCoroutinesApi import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D import space.kscience.kmath.structures.toDoubleArray +import kotlin.test.Ignore import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -47,7 +49,7 @@ class TestDoubleTensor { } } - @Test + @Test @Ignore fun toStringTest() = DoubleTensorAlgebra { val tensor = randNormal(intArrayOf(2,3)) println(tensor) From 82d8394a9fd19461e90a331157e5ac4eee705aab Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 16 Apr 2021 12:05:18 +0100 Subject: [PATCH 112/178] remove kolinx import --- .../kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index f950dfce3..fd75f77fe 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -1,6 +1,5 @@ package space.kscience.kmath.tensors.core -import kotlinx.coroutines.InternalCoroutinesApi import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D import space.kscience.kmath.structures.toDoubleArray From cc11df617489c6d3d8105b72cf5a472af1c90c01 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 21 Apr 2021 19:51:34 +0100 Subject: [PATCH 113/178] Casting receiver --- .../kmath/tensors/AnalyticTensorAlgebra.kt | 38 +-- .../kmath/tensors/LinearOpsTensorAlgebra.kt | 21 +- .../kscience/kmath/tensors/TensorAlgebra.kt | 50 ++-- .../tensors/TensorPartialDivisionAlgebra.kt | 12 +- .../core/BroadcastDoubleTensorAlgebra.kt | 57 ++-- .../kmath/tensors/core/BufferedTensor.kt | 48 ++- .../core/DoubleAnalyticTensorAlgebra.kt | 37 +-- .../core/DoubleLinearOpsTensorAlgebra.kt | 65 ++-- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 279 +++++++++--------- .../kscience/kmath/tensors/core/checks.kt | 41 +-- .../kscience/kmath/tensors/core/linutils.kt | 4 +- .../kscience/kmath/tensors/core/utils.kt | 4 +- 12 files changed, 326 insertions(+), 330 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt index fa1de81fa..2a8b228f4 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt @@ -1,58 +1,58 @@ package space.kscience.kmath.tensors -public interface AnalyticTensorAlgebra> : - TensorPartialDivisionAlgebra { +public interface AnalyticTensorAlgebra : + TensorPartialDivisionAlgebra { //https://pytorch.org/docs/stable/generated/torch.exp.html - public fun TensorType.exp(): TensorType + public fun TensorStructure.exp(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.log.html - public fun TensorType.log(): TensorType + public fun TensorStructure.log(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.sqrt.html - public fun TensorType.sqrt(): TensorType + public fun TensorStructure.sqrt(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.acos.html#torch.cos - public fun TensorType.cos(): TensorType + public fun TensorStructure.cos(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.acos.html#torch.acos - public fun TensorType.acos(): TensorType + public fun TensorStructure.acos(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.cosh - public fun TensorType.cosh(): TensorType + public fun TensorStructure.cosh(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.acosh - public fun TensorType.acosh(): TensorType + public fun TensorStructure.acosh(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sin - public fun TensorType.sin(): TensorType + public fun TensorStructure.sin(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asin - public fun TensorType.asin(): TensorType + public fun TensorStructure.asin(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sinh - public fun TensorType.sinh(): TensorType + public fun TensorStructure.sinh(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asinh - public fun TensorType.asinh(): TensorType + public fun TensorStructure.asinh(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.atan.html#torch.tan - public fun TensorType.tan(): TensorType + public fun TensorStructure.tan(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.atan.html#torch.atan - public fun TensorType.atan(): TensorType + public fun TensorStructure.atan(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.tanh - public fun TensorType.tanh(): TensorType + public fun TensorStructure.tanh(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.atanh - public fun TensorType.atanh(): TensorType + public fun TensorStructure.atanh(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.ceil.html#torch.ceil - public fun TensorType.ceil(): TensorType + public fun TensorStructure.ceil(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.floor.html#torch.floor - public fun TensorType.floor(): TensorType + public fun TensorStructure.floor(): TensorStructure } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt index 87c459f35..8ca8945a5 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt @@ -1,31 +1,32 @@ package space.kscience.kmath.tensors -public interface LinearOpsTensorAlgebra, IndexTensorType : TensorStructure> : - TensorPartialDivisionAlgebra { +public interface LinearOpsTensorAlgebra : + TensorPartialDivisionAlgebra { //https://pytorch.org/docs/stable/linalg.html#torch.linalg.det - public fun TensorType.det(): TensorType + public fun TensorStructure.det(): TensorStructure //https://pytorch.org/docs/stable/linalg.html#torch.linalg.inv - public fun TensorType.inv(): TensorType + public fun TensorStructure.inv(): TensorStructure //https://pytorch.org/docs/stable/linalg.html#torch.linalg.cholesky - public fun TensorType.cholesky(): TensorType + public fun TensorStructure.cholesky(): TensorStructure //https://pytorch.org/docs/stable/linalg.html#torch.linalg.qr - public fun TensorType.qr(): Pair + public fun TensorStructure.qr(): Pair, TensorStructure> //https://pytorch.org/docs/stable/generated/torch.lu.html - public fun TensorType.lu(): Pair + public fun TensorStructure.lu(): Pair, TensorStructure> //https://pytorch.org/docs/stable/generated/torch.lu_unpack.html - public fun luPivot(luTensor: TensorType, pivotsTensor: IndexTensorType): Triple + public fun luPivot(luTensor: TensorStructure, pivotsTensor: TensorStructure): + Triple, TensorStructure, TensorStructure> //https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd - public fun TensorType.svd(): Triple + public fun TensorStructure.svd(): Triple, TensorStructure, TensorStructure> //https://pytorch.org/docs/stable/generated/torch.symeig.html - public fun TensorType.symEig(): Pair + public fun TensorStructure.symEig(): Pair, TensorStructure> } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt index 8fd1cf2ed..f64d49dd8 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt @@ -1,46 +1,46 @@ package space.kscience.kmath.tensors // https://proofwiki.org/wiki/Definition:Algebra_over_Ring -public interface TensorAlgebra> { +public interface TensorAlgebra { - public fun TensorType.value(): T + public fun TensorStructure.value(): T - public operator fun T.plus(other: TensorType): TensorType - public operator fun TensorType.plus(value: T): TensorType - public operator fun TensorType.plus(other: TensorType): TensorType - public operator fun TensorType.plusAssign(value: T): Unit - public operator fun TensorType.plusAssign(other: TensorType): Unit + public operator fun T.plus(other: TensorStructure): TensorStructure + public operator fun TensorStructure.plus(value: T): TensorStructure + public operator fun TensorStructure.plus(other: TensorStructure): TensorStructure + public operator fun TensorStructure.plusAssign(value: T): Unit + public operator fun TensorStructure.plusAssign(other: TensorStructure): Unit - public operator fun T.minus(other: TensorType): TensorType - public operator fun TensorType.minus(value: T): TensorType - public operator fun TensorType.minus(other: TensorType): TensorType - public operator fun TensorType.minusAssign(value: T): Unit - public operator fun TensorType.minusAssign(other: TensorType): Unit + public operator fun T.minus(other: TensorStructure): TensorStructure + public operator fun TensorStructure.minus(value: T): TensorStructure + public operator fun TensorStructure.minus(other: TensorStructure): TensorStructure + public operator fun TensorStructure.minusAssign(value: T): Unit + public operator fun TensorStructure.minusAssign(other: TensorStructure): Unit - public operator fun T.times(other: TensorType): TensorType - public operator fun TensorType.times(value: T): TensorType - public operator fun TensorType.times(other: TensorType): TensorType - public operator fun TensorType.timesAssign(value: T): Unit - public operator fun TensorType.timesAssign(other: TensorType): Unit - public operator fun TensorType.unaryMinus(): TensorType + public operator fun T.times(other: TensorStructure): TensorStructure + public operator fun TensorStructure.times(value: T): TensorStructure + public operator fun TensorStructure.times(other: TensorStructure): TensorStructure + public operator fun TensorStructure.timesAssign(value: T): Unit + public operator fun TensorStructure.timesAssign(other: TensorStructure): Unit + public operator fun TensorStructure.unaryMinus(): TensorStructure //https://pytorch.org/cppdocs/notes/tensor_indexing.html - public operator fun TensorType.get(i: Int): TensorType + public operator fun TensorStructure.get(i: Int): TensorStructure //https://pytorch.org/docs/stable/generated/torch.transpose.html - public fun TensorType.transpose(i: Int = -2, j: Int = -1): TensorType + public fun TensorStructure.transpose(i: Int = -2, j: Int = -1): TensorStructure //https://pytorch.org/docs/stable/tensor_view.html - public fun TensorType.view(shape: IntArray): TensorType - public fun TensorType.viewAs(other: TensorType): TensorType + public fun TensorStructure.view(shape: IntArray): TensorStructure + public fun TensorStructure.viewAs(other: TensorStructure): TensorStructure //https://pytorch.org/docs/stable/generated/torch.matmul.html - public infix fun TensorType.dot(other: TensorType): TensorType + public infix fun TensorStructure.dot(other: TensorStructure): TensorStructure //https://pytorch.org/docs/stable/generated/torch.diag_embed.html public fun diagonalEmbedding( - diagonalEntries: TensorType, + diagonalEntries: TensorStructure, offset: Int = 0, dim1: Int = -2, dim2: Int = -1 - ): TensorType + ): TensorStructure } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt index 0b9079967..b37ac6b6e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt @@ -1,10 +1,10 @@ package space.kscience.kmath.tensors // https://proofwiki.org/wiki/Definition:Division_Algebra -public interface TensorPartialDivisionAlgebra> : - TensorAlgebra { - public operator fun TensorType.div(value: T): TensorType - public operator fun TensorType.div(other: TensorType): TensorType - public operator fun TensorType.divAssign(value: T) - public operator fun TensorType.divAssign(other: TensorType) +public interface TensorPartialDivisionAlgebra : + TensorAlgebra { + public operator fun TensorStructure.div(value: T): TensorStructure + public operator fun TensorStructure.div(other: TensorStructure): TensorStructure + public operator fun TensorStructure.divAssign(value: T) + public operator fun TensorStructure.divAssign(other: TensorStructure) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt index f315f6b51..53c385197 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt @@ -1,11 +1,12 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.tensors.TensorStructure import kotlin.math.max public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { - override fun DoubleTensor.plus(other: DoubleTensor): DoubleTensor { - val broadcast = broadcastTensors(this, other) + override fun TensorStructure.plus(other: TensorStructure): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> @@ -14,16 +15,16 @@ public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun DoubleTensor.plusAssign(other: DoubleTensor) { - val newOther = broadcastTo(other, this.shape) - for (i in 0 until this.linearStructure.size) { - this.buffer.array()[this.bufferStart + i] += - newOther.buffer.array()[this.bufferStart + i] + override fun TensorStructure.plusAssign(other: TensorStructure) { + val newOther = broadcastTo(other.tensor, tensor.shape) + for (i in 0 until tensor.linearStructure.size) { + tensor.buffer.array()[tensor.bufferStart + i] += + newOther.buffer.array()[tensor.bufferStart + i] } } - override fun DoubleTensor.minus(other: DoubleTensor): DoubleTensor { - val broadcast = broadcastTensors(this, other) + override fun TensorStructure.minus(other: TensorStructure): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> @@ -32,16 +33,16 @@ public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun DoubleTensor.minusAssign(other: DoubleTensor) { - val newOther = broadcastTo(other, this.shape) - for (i in 0 until this.linearStructure.size) { - this.buffer.array()[this.bufferStart + i] -= - newOther.buffer.array()[this.bufferStart + i] + override fun TensorStructure.minusAssign(other: TensorStructure) { + val newOther = broadcastTo(other.tensor, tensor.shape) + for (i in 0 until tensor.linearStructure.size) { + tensor.buffer.array()[tensor.bufferStart + i] -= + newOther.buffer.array()[tensor.bufferStart + i] } } - override fun DoubleTensor.times(other: DoubleTensor): DoubleTensor { - val broadcast = broadcastTensors(this, other) + override fun TensorStructure.times(other: TensorStructure): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> @@ -51,16 +52,16 @@ public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun DoubleTensor.timesAssign(other: DoubleTensor) { - val newOther = broadcastTo(other, this.shape) - for (i in 0 until this.linearStructure.size) { - this.buffer.array()[this.bufferStart + i] *= - newOther.buffer.array()[this.bufferStart + i] + override fun TensorStructure.timesAssign(other: TensorStructure) { + val newOther = broadcastTo(other.tensor, tensor.shape) + for (i in 0 until tensor.linearStructure.size) { + tensor.buffer.array()[tensor.bufferStart + i] *= + newOther.buffer.array()[tensor.bufferStart + i] } } - override fun DoubleTensor.div(other: DoubleTensor): DoubleTensor { - val broadcast = broadcastTensors(this, other) + override fun TensorStructure.div(other: TensorStructure): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> @@ -70,11 +71,11 @@ public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun DoubleTensor.divAssign(other: DoubleTensor) { - val newOther = broadcastTo(other, this.shape) - for (i in 0 until this.linearStructure.size) { - this.buffer.array()[this.bufferStart + i] /= - newOther.buffer.array()[this.bufferStart + i] + override fun TensorStructure.divAssign(other: TensorStructure) { + val newOther = broadcastTo(other.tensor, tensor.shape) + for (i in 0 until tensor.linearStructure.size) { + tensor.buffer.array()[tensor.bufferStart + i] /= + newOther.buffer.array()[tensor.bufferStart + i] } } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 9e393f1a8..2b61e10b2 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -6,13 +6,13 @@ import space.kscience.kmath.tensors.TensorStructure public open class BufferedTensor( override val shape: IntArray, - public val buffer: MutableBuffer, + internal val buffer: MutableBuffer, internal val bufferStart: Int ) : TensorStructure { public val linearStructure: TensorLinearStructure get() = TensorLinearStructure(shape) - public val numel: Int + public val numElements: Int get() = linearStructure.size override fun get(index: IntArray): T = buffer[bufferStart + linearStructure.offset(index)] @@ -41,26 +41,6 @@ public class IntTensor internal constructor( this(bufferedTensor.shape, bufferedTensor.buffer.array(), bufferedTensor.bufferStart) } -public class LongTensor internal constructor( - shape: IntArray, - buffer: LongArray, - offset: Int = 0 -) : BufferedTensor(shape, LongBuffer(buffer), offset) -{ - internal constructor(bufferedTensor: BufferedTensor): - this(bufferedTensor.shape, bufferedTensor.buffer.array(), bufferedTensor.bufferStart) -} - -public class FloatTensor internal constructor( - shape: IntArray, - buffer: FloatArray, - offset: Int = 0 -) : BufferedTensor(shape, FloatBuffer(buffer), offset) -{ - internal constructor(bufferedTensor: BufferedTensor): - this(bufferedTensor.shape, bufferedTensor.buffer.array(), bufferedTensor.bufferStart) -} - public class DoubleTensor internal constructor( shape: IntArray, buffer: DoubleArray, @@ -74,7 +54,23 @@ public class DoubleTensor internal constructor( } -internal fun BufferedTensor.asTensor(): IntTensor = IntTensor(this) -internal fun BufferedTensor.asTensor(): LongTensor = LongTensor(this) -internal fun BufferedTensor.asTensor(): FloatTensor = FloatTensor(this) -internal fun BufferedTensor.asTensor(): DoubleTensor = DoubleTensor(this) +internal inline fun BufferedTensor.asTensor(): IntTensor = IntTensor(this) +internal inline fun BufferedTensor.asTensor(): DoubleTensor = DoubleTensor(this) + +internal inline fun TensorStructure.toBufferedTensor(): BufferedTensor = when (this) { + is BufferedTensor -> this + else -> BufferedTensor(this.shape, this.elements().map{ it.second }.toMutableList().asMutableBuffer(), 0) +} + +internal val TensorStructure.tensor: DoubleTensor + get() = when (this) { + is DoubleTensor -> this + else -> this.toBufferedTensor().asTensor() + } + +internal val TensorStructure.tensor: IntTensor + get() = when (this) { + is IntTensor -> this + else -> this.toBufferedTensor().asTensor() + } + diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt index b46c7fa9c..233217f2f 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt @@ -1,45 +1,46 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.tensors.AnalyticTensorAlgebra +import space.kscience.kmath.tensors.TensorStructure import kotlin.math.* public class DoubleAnalyticTensorAlgebra: - AnalyticTensorAlgebra, + AnalyticTensorAlgebra, DoubleTensorAlgebra() { - override fun DoubleTensor.exp(): DoubleTensor = this.map(::exp) + override fun TensorStructure.exp(): DoubleTensor = tensor.map(::exp) - override fun DoubleTensor.log(): DoubleTensor = this.map(::ln) + override fun TensorStructure.log(): DoubleTensor = tensor.map(::ln) - override fun DoubleTensor.sqrt(): DoubleTensor = this.map(::sqrt) + override fun TensorStructure.sqrt(): DoubleTensor = tensor.map(::sqrt) - override fun DoubleTensor.cos(): DoubleTensor = this.map(::cos) + override fun TensorStructure.cos(): DoubleTensor = tensor.map(::cos) - override fun DoubleTensor.acos(): DoubleTensor = this.map(::acos) + override fun TensorStructure.acos(): DoubleTensor = tensor.map(::acos) - override fun DoubleTensor.cosh(): DoubleTensor = this.map(::cosh) + override fun TensorStructure.cosh(): DoubleTensor = tensor.map(::cosh) - override fun DoubleTensor.acosh(): DoubleTensor = this.map(::acosh) + override fun TensorStructure.acosh(): DoubleTensor = tensor.map(::acosh) - override fun DoubleTensor.sin(): DoubleTensor = this.map(::sin) + override fun TensorStructure.sin(): DoubleTensor = tensor.map(::sin) - override fun DoubleTensor.asin(): DoubleTensor = this.map(::asin) + override fun TensorStructure.asin(): DoubleTensor = tensor.map(::asin) - override fun DoubleTensor.sinh(): DoubleTensor = this.map(::sinh) + override fun TensorStructure.sinh(): DoubleTensor = tensor.map(::sinh) - override fun DoubleTensor.asinh(): DoubleTensor = this.map(::asinh) + override fun TensorStructure.asinh(): DoubleTensor = tensor.map(::asinh) - override fun DoubleTensor.tan(): DoubleTensor = this.map(::tan) + override fun TensorStructure.tan(): DoubleTensor = tensor.map(::tan) - override fun DoubleTensor.atan(): DoubleTensor = this.map(::atan) + override fun TensorStructure.atan(): DoubleTensor = tensor.map(::atan) - override fun DoubleTensor.tanh(): DoubleTensor = this.map(::tanh) + override fun TensorStructure.tanh(): DoubleTensor = tensor.map(::tanh) - override fun DoubleTensor.atanh(): DoubleTensor = this.map(::atanh) + override fun TensorStructure.atanh(): DoubleTensor = tensor.map(::atanh) - override fun DoubleTensor.ceil(): DoubleTensor = this.map(::ceil) + override fun TensorStructure.ceil(): DoubleTensor = tensor.map(::ceil) - override fun DoubleTensor.floor(): DoubleTensor = this.map(::floor) + override fun TensorStructure.floor(): DoubleTensor = tensor.map(::floor) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt index e72948c84..386fc2a1b 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt @@ -3,44 +3,45 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.tensors.LinearOpsTensorAlgebra import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D +import space.kscience.kmath.tensors.TensorStructure import kotlin.math.min public class DoubleLinearOpsTensorAlgebra : - LinearOpsTensorAlgebra, + LinearOpsTensorAlgebra, DoubleTensorAlgebra() { - override fun DoubleTensor.inv(): DoubleTensor = invLU(1e-9) + override fun TensorStructure.inv(): DoubleTensor = invLU(1e-9) - override fun DoubleTensor.det(): DoubleTensor = detLU(1e-9) + override fun TensorStructure.det(): DoubleTensor = detLU(1e-9) - public fun DoubleTensor.lu(epsilon: Double): Pair = - computeLU(this, epsilon) ?: + public fun TensorStructure.lu(epsilon: Double): Pair = + computeLU(tensor, epsilon) ?: throw RuntimeException("Tensor contains matrices which are singular at precision $epsilon") - override fun DoubleTensor.lu(): Pair = lu(1e-9) + override fun TensorStructure.lu(): Pair = lu(1e-9) override fun luPivot( - luTensor: DoubleTensor, - pivotsTensor: IntTensor + luTensor: TensorStructure, + pivotsTensor: TensorStructure ): Triple { //todo checks checkSquareMatrix(luTensor.shape) check( luTensor.shape.dropLast(2).toIntArray() contentEquals pivotsTensor.shape.dropLast(1).toIntArray() || luTensor.shape.last() == pivotsTensor.shape.last() - 1 - ) { "Bed shapes ((" } //todo rewrite + ) { "Bad shapes ((" } //todo rewrite val n = luTensor.shape.last() val pTensor = luTensor.zeroesLike() - for ((p, pivot) in pTensor.matrixSequence().zip(pivotsTensor.vectorSequence())) + for ((p, pivot) in pTensor.matrixSequence().zip(pivotsTensor.tensor.vectorSequence())) pivInit(p.as2D(), pivot.as1D(), n) val lTensor = luTensor.zeroesLike() val uTensor = luTensor.zeroesLike() for ((pairLU, lu) in lTensor.matrixSequence().zip(uTensor.matrixSequence()) - .zip(luTensor.matrixSequence())) { + .zip(luTensor.tensor.matrixSequence())) { val (l, u) = pairLU luPivotHelper(l.as2D(), u.as2D(), lu.as2D(), n) } @@ -49,26 +50,26 @@ public class DoubleLinearOpsTensorAlgebra : } - public fun DoubleTensor.cholesky(epsilon: Double): DoubleTensor { + public fun TensorStructure.cholesky(epsilon: Double): DoubleTensor { checkSquareMatrix(shape) - checkPositiveDefinite(this, epsilon) + checkPositiveDefinite(tensor, epsilon) val n = shape.last() val lTensor = zeroesLike() - for ((a, l) in this.matrixSequence().zip(lTensor.matrixSequence())) + for ((a, l) in tensor.matrixSequence().zip(lTensor.matrixSequence())) for (i in 0 until n) choleskyHelper(a.as2D(), l.as2D(), n) return lTensor } - override fun DoubleTensor.cholesky(): DoubleTensor = cholesky(1e-6) + override fun TensorStructure.cholesky(): DoubleTensor = cholesky(1e-6) - override fun DoubleTensor.qr(): Pair { + override fun TensorStructure.qr(): Pair { checkSquareMatrix(shape) val qTensor = zeroesLike() val rTensor = zeroesLike() - val seq = matrixSequence().zip((qTensor.matrixSequence().zip(rTensor.matrixSequence()))) + val seq = tensor.matrixSequence().zip((qTensor.matrixSequence().zip(rTensor.matrixSequence()))) for ((matrix, qr) in seq) { val (q, r) = qr qrHelper(matrix.asTensor(), q.asTensor(), r.as2D()) @@ -76,18 +77,18 @@ public class DoubleLinearOpsTensorAlgebra : return qTensor to rTensor } - override fun DoubleTensor.svd(): Triple = + override fun TensorStructure.svd(): Triple = svd(epsilon = 1e-10) - public fun DoubleTensor.svd(epsilon: Double): Triple { - val size = this.linearStructure.dim - val commonShape = this.shape.sliceArray(0 until size - 2) - val (n, m) = this.shape.sliceArray(size - 2 until size) + public fun TensorStructure.svd(epsilon: Double): Triple { + val size = tensor.linearStructure.dim + val commonShape = tensor.shape.sliceArray(0 until size - 2) + val (n, m) = tensor.shape.sliceArray(size - 2 until size) val resU = zeros(commonShape + intArrayOf(min(n, m), n)) val resS = zeros(commonShape + intArrayOf(min(n, m))) val resV = zeros(commonShape + intArrayOf(min(n, m), m)) - for ((matrix, USV) in this.matrixSequence() + for ((matrix, USV) in tensor.matrixSequence() .zip(resU.matrixSequence().zip(resS.vectorSequence().zip(resV.matrixSequence())))) { val size = matrix.shape.reduce { acc, i -> acc * i } val curMatrix = DoubleTensor( @@ -99,13 +100,13 @@ public class DoubleLinearOpsTensorAlgebra : return Triple(resU.transpose(), resS, resV.transpose()) } - override fun DoubleTensor.symEig(): Pair = + override fun TensorStructure.symEig(): Pair = symEig(epsilon = 1e-15) //http://hua-zhou.github.io/teaching/biostatm280-2017spring/slides/16-eigsvd/eigsvd.html - public fun DoubleTensor.symEig(epsilon: Double): Pair { - checkSymmetric(this, epsilon) - val (u, s, v) = this.svd(epsilon) + public fun TensorStructure.symEig(epsilon: Double): Pair { + checkSymmetric(tensor, epsilon) + val (u, s, v) = tensor.svd(epsilon) val shp = s.shape + intArrayOf(1) val utv = u.transpose() dot v val n = s.shape.last() @@ -116,11 +117,11 @@ public class DoubleLinearOpsTensorAlgebra : return Pair(eig, v) } - public fun DoubleTensor.detLU(epsilon: Double = 1e-9): DoubleTensor { + public fun TensorStructure.detLU(epsilon: Double = 1e-9): DoubleTensor { - checkSquareMatrix(this.shape) - val luTensor = this.copy() - val pivotsTensor = this.setUpPivots() + checkSquareMatrix(tensor.shape) + val luTensor = tensor.copy() + val pivotsTensor = tensor.setUpPivots() val n = shape.size @@ -141,7 +142,7 @@ public class DoubleLinearOpsTensorAlgebra : return detTensor } - public fun DoubleTensor.invLU(epsilon: Double = 1e-9): DoubleTensor { + public fun TensorStructure.invLU(epsilon: Double = 1e-9): DoubleTensor { val (luTensor, pivotsTensor) = lu(epsilon) val invTensor = luTensor.zeroesLike() diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 8f355dd3d..7544bf68e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -1,16 +1,18 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.tensors.TensorPartialDivisionAlgebra import space.kscience.kmath.nd.as2D +import space.kscience.kmath.tensors.TensorPartialDivisionAlgebra +import space.kscience.kmath.tensors.TensorStructure import kotlin.math.abs -public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { +public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { - override fun DoubleTensor.value(): Double { - check(this.shape contentEquals intArrayOf(1)) { + + override fun TensorStructure.value(): Double { + check(tensor.shape contentEquals intArrayOf(1)) { "Inconsistent value for tensor of shape ${shape.toList()}" } - return this.buffer.array()[this.bufferStart] + return tensor.buffer.array()[tensor.bufferStart] } public fun fromArray(shape: IntArray, buffer: DoubleArray): DoubleTensor { @@ -20,11 +22,11 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra.get(i: Int): DoubleTensor { + val lastShape = tensor.shape.drop(1).toIntArray() val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) - val newStart = newShape.reduce(Int::times) * i + this.bufferStart - return DoubleTensor(newShape, this.buffer.array(), newStart) + val newStart = newShape.reduce(Int::times) * i + tensor.bufferStart + return DoubleTensor(newShape, tensor.buffer.array(), newStart) } public fun full(value: Double, shape: IntArray): DoubleTensor { @@ -33,19 +35,19 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra.fullLike(value: Double): DoubleTensor { + val shape = tensor.shape + val buffer = DoubleArray(tensor.numElements) { value } return DoubleTensor(shape, buffer) } public fun zeros(shape: IntArray): DoubleTensor = full(0.0, shape) - public fun DoubleTensor.zeroesLike(): DoubleTensor = this.fullLike(0.0) + public fun TensorStructure.zeroesLike(): DoubleTensor = tensor.fullLike(0.0) public fun ones(shape: IntArray): DoubleTensor = full(1.0, shape) - public fun DoubleTensor.onesLike(): DoubleTensor = this.fullLike(1.0) + public fun TensorStructure.onesLike(): DoubleTensor = tensor.fullLike(1.0) public fun eye(n: Int): DoubleTensor { val shape = intArrayOf(n, n) @@ -57,200 +59,200 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra.copy(): DoubleTensor { + return DoubleTensor(tensor.shape, tensor.buffer.array().copyOf(), tensor.bufferStart) } - override fun Double.plus(other: DoubleTensor): DoubleTensor { - val resBuffer = DoubleArray(other.linearStructure.size) { i -> - other.buffer.array()[other.bufferStart + i] + this + override fun Double.plus(other: TensorStructure): DoubleTensor { + val resBuffer = DoubleArray(other.tensor.numElements) { i -> + other.tensor.buffer.array()[other.tensor.bufferStart + i] + this } return DoubleTensor(other.shape, resBuffer) } - override fun DoubleTensor.plus(value: Double): DoubleTensor = value + this + override fun TensorStructure.plus(value: Double): DoubleTensor = value + tensor - override fun DoubleTensor.plus(other: DoubleTensor): DoubleTensor { - checkShapesCompatible(this, other) - val resBuffer = DoubleArray(this.linearStructure.size) { i -> - this.buffer.array()[i] + other.buffer.array()[i] + override fun TensorStructure.plus(other: TensorStructure): DoubleTensor { + checkShapesCompatible(tensor, other.tensor) + val resBuffer = DoubleArray(tensor.numElements) { i -> + tensor.buffer.array()[i] + other.tensor.buffer.array()[i] } - return DoubleTensor(this.shape, resBuffer) + return DoubleTensor(tensor.shape, resBuffer) } - override fun DoubleTensor.plusAssign(value: Double) { - for (i in 0 until this.linearStructure.size) { - this.buffer.array()[this.bufferStart + i] += value + override fun TensorStructure.plusAssign(value: Double) { + for (i in 0 until tensor.numElements) { + tensor.buffer.array()[tensor.bufferStart + i] += value } } - override fun DoubleTensor.plusAssign(other: DoubleTensor) { - checkShapesCompatible(this, other) - for (i in 0 until this.linearStructure.size) { - this.buffer.array()[this.bufferStart + i] += - other.buffer.array()[this.bufferStart + i] + override fun TensorStructure.plusAssign(other: TensorStructure) { + checkShapesCompatible(tensor, other.tensor) + for (i in 0 until tensor.numElements) { + tensor.buffer.array()[tensor.bufferStart + i] += + other.tensor.buffer.array()[tensor.bufferStart + i] } } - override fun Double.minus(other: DoubleTensor): DoubleTensor { - val resBuffer = DoubleArray(other.linearStructure.size) { i -> - this - other.buffer.array()[other.bufferStart + i] + override fun Double.minus(other: TensorStructure): DoubleTensor { + val resBuffer = DoubleArray(other.tensor.numElements) { i -> + this - other.tensor.buffer.array()[other.tensor.bufferStart + i] } return DoubleTensor(other.shape, resBuffer) } - override fun DoubleTensor.minus(value: Double): DoubleTensor { - val resBuffer = DoubleArray(this.linearStructure.size) { i -> - this.buffer.array()[this.bufferStart + i] - value + override fun TensorStructure.minus(value: Double): DoubleTensor { + val resBuffer = DoubleArray(tensor.numElements) { i -> + tensor.buffer.array()[tensor.bufferStart + i] - value } - return DoubleTensor(this.shape, resBuffer) + return DoubleTensor(tensor.shape, resBuffer) } - override fun DoubleTensor.minus(other: DoubleTensor): DoubleTensor { - checkShapesCompatible(this, other) - val resBuffer = DoubleArray(this.linearStructure.size) { i -> - this.buffer.array()[i] - other.buffer.array()[i] + override fun TensorStructure.minus(other: TensorStructure): DoubleTensor { + checkShapesCompatible(tensor, other) + val resBuffer = DoubleArray(tensor.numElements) { i -> + tensor.buffer.array()[i] - other.tensor.buffer.array()[i] } - return DoubleTensor(this.shape, resBuffer) + return DoubleTensor(tensor.shape, resBuffer) } - override fun DoubleTensor.minusAssign(value: Double) { - for (i in 0 until this.linearStructure.size) { - this.buffer.array()[this.bufferStart + i] -= value + override fun TensorStructure.minusAssign(value: Double) { + for (i in 0 until tensor.numElements) { + tensor.buffer.array()[tensor.bufferStart + i] -= value } } - override fun DoubleTensor.minusAssign(other: DoubleTensor) { - checkShapesCompatible(this, other) - for (i in 0 until this.linearStructure.size) { - this.buffer.array()[this.bufferStart + i] -= - other.buffer.array()[this.bufferStart + i] + override fun TensorStructure.minusAssign(other: TensorStructure) { + checkShapesCompatible(tensor, other) + for (i in 0 until tensor.numElements) { + tensor.buffer.array()[tensor.bufferStart + i] -= + other.tensor.buffer.array()[tensor.bufferStart + i] } } - override fun Double.times(other: DoubleTensor): DoubleTensor { - val resBuffer = DoubleArray(other.linearStructure.size) { i -> - other.buffer.array()[other.bufferStart + i] * this + override fun Double.times(other: TensorStructure): DoubleTensor { + val resBuffer = DoubleArray(other.tensor.numElements) { i -> + other.tensor.buffer.array()[other.tensor.bufferStart + i] * this } return DoubleTensor(other.shape, resBuffer) } - override fun DoubleTensor.times(value: Double): DoubleTensor = value * this + override fun TensorStructure.times(value: Double): DoubleTensor = value * tensor - override fun DoubleTensor.times(other: DoubleTensor): DoubleTensor { - checkShapesCompatible(this, other) - val resBuffer = DoubleArray(this.linearStructure.size) { i -> - this.buffer.array()[this.bufferStart + i] * - other.buffer.array()[other.bufferStart + i] + override fun TensorStructure.times(other: TensorStructure): DoubleTensor { + checkShapesCompatible(tensor, other) + val resBuffer = DoubleArray(tensor.numElements) { i -> + tensor.buffer.array()[tensor.bufferStart + i] * + other.tensor.buffer.array()[other.tensor.bufferStart + i] } - return DoubleTensor(this.shape, resBuffer) + return DoubleTensor(tensor.shape, resBuffer) } - override fun DoubleTensor.timesAssign(value: Double) { - for (i in 0 until this.linearStructure.size) { - this.buffer.array()[this.bufferStart + i] *= value + override fun TensorStructure.timesAssign(value: Double) { + for (i in 0 until tensor.numElements) { + tensor.buffer.array()[tensor.bufferStart + i] *= value } } - override fun DoubleTensor.timesAssign(other: DoubleTensor) { - checkShapesCompatible(this, other) - for (i in 0 until this.linearStructure.size) { - this.buffer.array()[this.bufferStart + i] *= - other.buffer.array()[this.bufferStart + i] + override fun TensorStructure.timesAssign(other: TensorStructure) { + checkShapesCompatible(tensor, other) + for (i in 0 until tensor.numElements) { + tensor.buffer.array()[tensor.bufferStart + i] *= + other.tensor.buffer.array()[tensor.bufferStart + i] } } - override fun DoubleTensor.div(value: Double): DoubleTensor { - val resBuffer = DoubleArray(this.linearStructure.size) { i -> - this.buffer.array()[this.bufferStart + i] / value + override fun TensorStructure.div(value: Double): DoubleTensor { + val resBuffer = DoubleArray(tensor.numElements) { i -> + tensor.buffer.array()[tensor.bufferStart + i] / value } - return DoubleTensor(this.shape, resBuffer) + return DoubleTensor(tensor.shape, resBuffer) } - override fun DoubleTensor.div(other: DoubleTensor): DoubleTensor { - checkShapesCompatible(this, other) - val resBuffer = DoubleArray(this.linearStructure.size) { i -> - this.buffer.array()[other.bufferStart + i] / - other.buffer.array()[other.bufferStart + i] + override fun TensorStructure.div(other: TensorStructure): DoubleTensor { + checkShapesCompatible(tensor, other) + val resBuffer = DoubleArray(tensor.numElements) { i -> + tensor.buffer.array()[other.tensor.bufferStart + i] / + other.tensor.buffer.array()[other.tensor.bufferStart + i] } - return DoubleTensor(this.shape, resBuffer) + return DoubleTensor(tensor.shape, resBuffer) } - override fun DoubleTensor.divAssign(value: Double) { - for (i in 0 until this.linearStructure.size) { - this.buffer.array()[this.bufferStart + i] /= value + override fun TensorStructure.divAssign(value: Double) { + for (i in 0 until tensor.numElements) { + tensor.buffer.array()[tensor.bufferStart + i] /= value } } - override fun DoubleTensor.divAssign(other: DoubleTensor) { - checkShapesCompatible(this, other) - for (i in 0 until this.linearStructure.size) { - this.buffer.array()[this.bufferStart + i] /= - other.buffer.array()[this.bufferStart + i] + override fun TensorStructure.divAssign(other: TensorStructure) { + checkShapesCompatible(tensor, other) + for (i in 0 until tensor.numElements) { + tensor.buffer.array()[tensor.bufferStart + i] /= + other.tensor.buffer.array()[tensor.bufferStart + i] } } - override fun DoubleTensor.unaryMinus(): DoubleTensor { - val resBuffer = DoubleArray(this.linearStructure.size) { i -> - this.buffer.array()[this.bufferStart + i].unaryMinus() + override fun TensorStructure.unaryMinus(): DoubleTensor { + val resBuffer = DoubleArray(tensor.numElements) { i -> + tensor.buffer.array()[tensor.bufferStart + i].unaryMinus() } - return DoubleTensor(this.shape, resBuffer) + return DoubleTensor(tensor.shape, resBuffer) } - override fun DoubleTensor.transpose(i: Int, j: Int): DoubleTensor { - val ii = minusIndex(i) - val jj = minusIndex(j) - checkTranspose(this.dimension, ii, jj) - val n = this.linearStructure.size + override fun TensorStructure.transpose(i: Int, j: Int): DoubleTensor { + val ii = tensor.minusIndex(i) + val jj = tensor.minusIndex(j) + checkTranspose(tensor.dimension, ii, jj) + val n = tensor.numElements val resBuffer = DoubleArray(n) - val resShape = this.shape.copyOf() + val resShape = tensor.shape.copyOf() resShape[ii] = resShape[jj].also { resShape[jj] = resShape[ii] } val resTensor = DoubleTensor(resShape, resBuffer) for (offset in 0 until n) { - val oldMultiIndex = this.linearStructure.index(offset) + val oldMultiIndex = tensor.linearStructure.index(offset) val newMultiIndex = oldMultiIndex.copyOf() newMultiIndex[ii] = newMultiIndex[jj].also { newMultiIndex[jj] = newMultiIndex[ii] } val linearIndex = resTensor.linearStructure.offset(newMultiIndex) resTensor.buffer.array()[linearIndex] = - this.buffer.array()[this.bufferStart + offset] + tensor.buffer.array()[tensor.bufferStart + offset] } return resTensor } - override fun DoubleTensor.view(shape: IntArray): DoubleTensor { - checkView(this, shape) - return DoubleTensor(shape, this.buffer.array(), this.bufferStart) + override fun TensorStructure.view(shape: IntArray): DoubleTensor { + checkView(tensor, shape) + return DoubleTensor(shape, tensor.buffer.array(), tensor.bufferStart) } - override fun DoubleTensor.viewAs(other: DoubleTensor): DoubleTensor { - return this.view(other.shape) + override fun TensorStructure.viewAs(other: TensorStructure): DoubleTensor { + return tensor.view(other.shape) } - override infix fun DoubleTensor.dot(other: DoubleTensor): DoubleTensor { - if (this.shape.size == 1 && other.shape.size == 1) { - return DoubleTensor(intArrayOf(1), doubleArrayOf(this.times(other).buffer.array().sum())) + override infix fun TensorStructure.dot(other: TensorStructure): DoubleTensor { + if (tensor.shape.size == 1 && other.shape.size == 1) { + return DoubleTensor(intArrayOf(1), doubleArrayOf(tensor.times(other).tensor.buffer.array().sum())) } - var newThis = this.copy() + var newThis = tensor.copy() var newOther = other.copy() var penultimateDim = false var lastDim = false - if (this.shape.size == 1) { + if (tensor.shape.size == 1) { penultimateDim = true - newThis = this.view(intArrayOf(1) + this.shape) + newThis = tensor.view(intArrayOf(1) + tensor.shape) } if (other.shape.size == 1) { lastDim = true - newOther = other.view(other.shape + intArrayOf(1)) + newOther = other.tensor.view(other.shape + intArrayOf(1)) } - val broadcastTensors = broadcastOuterTensors(newThis, newOther) + val broadcastTensors = broadcastOuterTensors(newThis.tensor, newOther.tensor) newThis = broadcastTensors[0] newOther = broadcastTensors[1] @@ -284,10 +286,12 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra, offset: Int, dim1: Int, dim2: Int): + DoubleTensor { val n = diagonalEntries.shape.size + val d1 = minusIndexFrom(n + 1, dim1) + val d2 = minusIndexFrom(n + 1, dim2) + if (d1 == d2) { throw RuntimeException("Diagonal dimensions cannot be identical $d1, $d2") } @@ -300,7 +304,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra greaterDim) { realOffset *= -1 - lessDim = greaterDim.also {greaterDim = lessDim} + lessDim = greaterDim.also { greaterDim = lessDim } } val resShape = diagonalEntries.shape.slice(0 until lessDim).toIntArray() + @@ -310,13 +314,13 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra Double): DoubleTensor { + public fun TensorStructure.map(transform: (Double) -> Double): DoubleTensor { return DoubleTensor( - this.shape, - this.buffer.array().map { transform(it) }.toDoubleArray(), - this.bufferStart + tensor.shape, + tensor.buffer.array().map { transform(it) }.toDoubleArray(), + tensor.bufferStart ) } - public fun DoubleTensor.eq(other: DoubleTensor, delta: Double): Boolean { - return this.eq(other) { x, y -> abs(x - y) < delta } + public fun TensorStructure.eq(other: TensorStructure, delta: Double): Boolean { + return tensor.eq(other) { x, y -> abs(x - y) < delta } } - public fun DoubleTensor.eq(other: DoubleTensor): Boolean = this.eq(other, 1e-5) + public fun TensorStructure.eq(other: TensorStructure): Boolean = tensor.eq(other, 1e-5) - private fun DoubleTensor.eq(other: DoubleTensor, eqFunction: (Double, Double) -> Boolean): Boolean { - checkShapesCompatible(this, other) - val n = this.linearStructure.size - if (n != other.linearStructure.size) { + private fun TensorStructure.eq( + other: TensorStructure, + eqFunction: (Double, Double) -> Boolean + ): Boolean { + checkShapesCompatible(tensor, other) + val n = tensor.numElements + if (n != other.tensor.numElements) { return false } for (i in 0 until n) { - if (!eqFunction(this.buffer[this.bufferStart + i], other.buffer[other.bufferStart + i])) { + if (!eqFunction(tensor.buffer[tensor.bufferStart + i], other.tensor.buffer[other.tensor.bufferStart + i])) { return false } } @@ -362,8 +369,8 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra.randNormalLike(seed: Long = 0): DoubleTensor = + DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed)) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt index 730b6ed9a..28828eb09 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -1,54 +1,40 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.tensors.TensorAlgebra import space.kscience.kmath.tensors.TensorStructure -internal inline fun , - TorchTensorAlgebraType : TensorAlgebra> - TorchTensorAlgebraType.checkEmptyShape(shape: IntArray): Unit = +internal inline fun checkEmptyShape(shape: IntArray): Unit = check(shape.isNotEmpty()) { "Illegal empty shape provided" } -internal inline fun , - TorchTensorAlgebraType : TensorAlgebra> - TorchTensorAlgebraType.checkEmptyDoubleBuffer(buffer: DoubleArray): Unit = +internal inline fun checkEmptyDoubleBuffer(buffer: DoubleArray): Unit = check(buffer.isNotEmpty()) { "Illegal empty buffer provided" } -internal inline fun , - TorchTensorAlgebraType : TensorAlgebra> - TorchTensorAlgebraType.checkBufferShapeConsistency(shape: IntArray, buffer: DoubleArray): Unit = +internal inline fun checkBufferShapeConsistency(shape: IntArray, buffer: DoubleArray): Unit = check(buffer.size == shape.reduce(Int::times)) { "Inconsistent shape ${shape.toList()} for buffer of size ${buffer.size} provided" } -internal inline fun , - TorchTensorAlgebraType : TensorAlgebra> - TorchTensorAlgebraType.checkShapesCompatible(a: TensorType, b: TensorType): Unit = +internal inline fun checkShapesCompatible(a: TensorStructure, b: TensorStructure): Unit = check(a.shape contentEquals b.shape) { "Incompatible shapes ${a.shape.toList()} and ${b.shape.toList()} " } -internal inline fun , - TorchTensorAlgebraType : TensorAlgebra> - TorchTensorAlgebraType.checkTranspose(dim: Int, i: Int, j: Int): Unit = +internal inline fun checkTranspose(dim: Int, i: Int, j: Int): Unit = check((i < dim) and (j < dim)) { "Cannot transpose $i to $j for a tensor of dim $dim" } -internal inline fun , - TorchTensorAlgebraType : TensorAlgebra> - TorchTensorAlgebraType.checkView(a: TensorType, shape: IntArray): Unit = +internal inline fun checkView(a: TensorStructure, shape: IntArray): Unit = check(a.shape.reduce(Int::times) == shape.reduce(Int::times)) -internal inline fun , - TorchTensorAlgebraType : TensorAlgebra> - TorchTensorAlgebraType.checkSquareMatrix(shape: IntArray): Unit { + +internal inline fun checkSquareMatrix(shape: IntArray): Unit { val n = shape.size check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n instead" @@ -58,16 +44,19 @@ internal inline fun , } } -internal inline fun DoubleTensorAlgebra.checkSymmetric(tensor: DoubleTensor, epsilon: Double = 1e-6): Unit = +internal inline fun DoubleTensorAlgebra.checkSymmetric( + tensor: TensorStructure, epsilon: Double = 1e-6 +): Unit = check(tensor.eq(tensor.transpose(), epsilon)) { "Tensor is not symmetric about the last 2 dimensions at precision $epsilon" } internal inline fun DoubleLinearOpsTensorAlgebra.checkPositiveDefinite( - tensor: DoubleTensor, epsilon: Double = 1e-6): Unit { + tensor: DoubleTensor, epsilon: Double = 1e-6 +): Unit { checkSymmetric(tensor, epsilon) - for( mat in tensor.matrixSequence()) - check(mat.asTensor().detLU().value() > 0.0){ + for (mat in tensor.matrixSequence()) + check(mat.asTensor().detLU().value() > 0.0) { "Tensor contains matrices which are not positive definite ${mat.asTensor().detLU().value()}" } } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt index ba5e0caaf..166f1d6c4 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linutils.kt @@ -14,7 +14,7 @@ internal inline fun BufferedTensor.vectorSequence(): Sequence BufferedTensor.matrixSequence(): Sequence= 0) i else { ii } -internal inline fun BufferedTensor.minusIndex(i: Int): Int = minusIndexFrom(this.linearStructure.dim, i) +internal inline fun BufferedTensor.minusIndex(i: Int): Int = minusIndexFrom(this.dimension, i) internal inline fun format(value: Double, digits: Int = 4): String { val ten = 10.0 @@ -111,7 +111,7 @@ internal inline fun DoubleTensor.toPrettyString(): String = buildString { } offset += vectorSize // todo refactor - if (this@toPrettyString.numel == offset) { + if (this@toPrettyString.numElements == offset) { break } append(",\n") From 559e8b24ab6189b523e3707b605b7f2c75c8b92c Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Wed, 21 Apr 2021 23:44:39 +0300 Subject: [PATCH 114/178] rework structure + fixes --- .../{ => api}/AnalyticTensorAlgebra.kt | 7 +- .../{ => api}/LinearOpsTensorAlgebra.kt | 7 +- .../kmath/tensors/{ => api}/TensorAlgebra.kt | 11 +- .../{ => api}/TensorPartialDivisionAlgebra.kt | 9 +- .../tensors/{ => api}/TensorStructure.kt | 2 +- .../kmath/tensors/core/BufferedTensor.kt | 3 +- .../algebras/BroadcastDoubleTensorAlgebra.kt | 89 ++++++++++ .../DoubleAnalyticTensorAlgebra.kt | 13 +- .../DoubleLinearOpsTensorAlgebra.kt | 27 +++- .../{ => algebras}/DoubleTensorAlgebra.kt | 27 +++- .../{ => algebras}/TensorLinearStructure.kt | 7 +- ...ubleTensorAlgebra.kt => broadcastUtils.kt} | 153 ++++-------------- .../kscience/kmath/tensors/core/checks.kt | 4 +- .../tensors/core/{linutils.kt => linUtils.kt} | 10 +- .../kscience/kmath/tensors/core/utils.kt | 1 - .../kmath/tensors/core/TestBroadcasting.kt | 1 + .../core/TestDoubleAnalyticTensorAlgebra.kt | 1 + .../core/TestDoubleLinearOpsAlgebra.kt | 3 +- .../kmath/tensors/core/TestDoubleTensor.kt | 2 +- .../tensors/core/TestDoubleTensorAlgebra.kt | 20 ++- 20 files changed, 237 insertions(+), 160 deletions(-) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => api}/AnalyticTensorAlgebra.kt (91%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => api}/LinearOpsTensorAlgebra.kt (86%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => api}/TensorAlgebra.kt (89%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => api}/TensorPartialDivisionAlgebra.kt (64%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/{ => api}/TensorStructure.kt (73%) create mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{ => algebras}/DoubleAnalyticTensorAlgebra.kt (77%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{ => algebras}/DoubleLinearOpsTensorAlgebra.kt (84%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{ => algebras}/DoubleTensorAlgebra.kt (92%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{ => algebras}/TensorLinearStructure.kt (90%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{BroadcastDoubleTensorAlgebra.kt => broadcastUtils.kt} (52%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{linutils.kt => linUtils.kt} (97%) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt similarity index 91% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt index 2a8b228f4..315f39027 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt @@ -1,4 +1,9 @@ -package space.kscience.kmath.tensors +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.api public interface AnalyticTensorAlgebra : diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt similarity index 86% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt index 8ca8945a5..5cd48ca78 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -1,4 +1,9 @@ -package space.kscience.kmath.tensors +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.api public interface LinearOpsTensorAlgebra : diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt similarity index 89% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index f64d49dd8..c1657d916 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -1,4 +1,9 @@ -package space.kscience.kmath.tensors +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.api // https://proofwiki.org/wiki/Definition:Algebra_over_Ring public interface TensorAlgebra { @@ -40,7 +45,9 @@ public interface TensorAlgebra { //https://pytorch.org/docs/stable/generated/torch.diag_embed.html public fun diagonalEmbedding( diagonalEntries: TensorStructure, - offset: Int = 0, dim1: Int = -2, dim2: Int = -1 + offset: Int = 0, + dim1: Int = -2, + dim2: Int = -1 ): TensorStructure } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt similarity index 64% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt index b37ac6b6e..075e86e61 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorPartialDivisionAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt @@ -1,8 +1,13 @@ -package space.kscience.kmath.tensors +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.api // https://proofwiki.org/wiki/Definition:Division_Algebra public interface TensorPartialDivisionAlgebra : - TensorAlgebra { + TensorAlgebra { public operator fun TensorStructure.div(value: T): TensorStructure public operator fun TensorStructure.div(other: TensorStructure): TensorStructure public operator fun TensorStructure.divAssign(value: T) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorStructure.kt similarity index 73% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorStructure.kt index 64c4d98b8..edecd6383 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/TensorStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorStructure.kt @@ -1,4 +1,4 @@ -package space.kscience.kmath.tensors +package space.kscience.kmath.tensors.api import space.kscience.kmath.nd.MutableStructureND diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 2b61e10b2..5c0d9c4ea 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -1,7 +1,8 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.structures.* -import space.kscience.kmath.tensors.TensorStructure +import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.core.algebras.TensorLinearStructure public open class BufferedTensor( diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt new file mode 100644 index 000000000..1b00197ff --- /dev/null +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt @@ -0,0 +1,89 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.core.algebras + +import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.core.* +import space.kscience.kmath.tensors.core.broadcastTensors +import space.kscience.kmath.tensors.core.broadcastTo + +public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { + + override fun TensorStructure.plus(other: TensorStructure): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) + val newThis = broadcast[0] + val newOther = broadcast[1] + val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> + newThis.buffer.array()[i] + newOther.buffer.array()[i] + } + return DoubleTensor(newThis.shape, resBuffer) + } + + override fun TensorStructure.plusAssign(other: TensorStructure) { + val newOther = broadcastTo(other.tensor, tensor.shape) + for (i in 0 until tensor.linearStructure.size) { + tensor.buffer.array()[tensor.bufferStart + i] += + newOther.buffer.array()[tensor.bufferStart + i] + } + } + + override fun TensorStructure.minus(other: TensorStructure): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) + val newThis = broadcast[0] + val newOther = broadcast[1] + val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> + newThis.buffer.array()[i] - newOther.buffer.array()[i] + } + return DoubleTensor(newThis.shape, resBuffer) + } + + override fun TensorStructure.minusAssign(other: TensorStructure) { + val newOther = broadcastTo(other.tensor, tensor.shape) + for (i in 0 until tensor.linearStructure.size) { + tensor.buffer.array()[tensor.bufferStart + i] -= + newOther.buffer.array()[tensor.bufferStart + i] + } + } + + override fun TensorStructure.times(other: TensorStructure): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) + val newThis = broadcast[0] + val newOther = broadcast[1] + val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> + newThis.buffer.array()[newThis.bufferStart + i] * + newOther.buffer.array()[newOther.bufferStart + i] + } + return DoubleTensor(newThis.shape, resBuffer) + } + + override fun TensorStructure.timesAssign(other: TensorStructure) { + val newOther = broadcastTo(other.tensor, tensor.shape) + for (i in 0 until tensor.linearStructure.size) { + tensor.buffer.array()[tensor.bufferStart + i] *= + newOther.buffer.array()[tensor.bufferStart + i] + } + } + + override fun TensorStructure.div(other: TensorStructure): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) + val newThis = broadcast[0] + val newOther = broadcast[1] + val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> + newThis.buffer.array()[newOther.bufferStart + i] / + newOther.buffer.array()[newOther.bufferStart + i] + } + return DoubleTensor(newThis.shape, resBuffer) + } + + override fun TensorStructure.divAssign(other: TensorStructure) { + val newOther = broadcastTo(other.tensor, tensor.shape) + for (i in 0 until tensor.linearStructure.size) { + tensor.buffer.array()[tensor.bufferStart + i] /= + newOther.buffer.array()[tensor.bufferStart + i] + } + } + +} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt similarity index 77% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt index 233217f2f..7d1cceb15 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt @@ -1,7 +1,14 @@ -package space.kscience.kmath.tensors.core +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ -import space.kscience.kmath.tensors.AnalyticTensorAlgebra -import space.kscience.kmath.tensors.TensorStructure +package space.kscience.kmath.tensors.core.algebras + +import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra +import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.core.DoubleTensor +import space.kscience.kmath.tensors.core.tensor import kotlin.math.* public class DoubleAnalyticTensorAlgebra: diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt similarity index 84% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt index 386fc2a1b..62629f3db 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt @@ -1,9 +1,23 @@ -package space.kscience.kmath.tensors.core +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ -import space.kscience.kmath.tensors.LinearOpsTensorAlgebra +package space.kscience.kmath.tensors.core.algebras + +import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D -import space.kscience.kmath.tensors.TensorStructure +import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.core.* +import space.kscience.kmath.tensors.core.checkSquareMatrix +import space.kscience.kmath.tensors.core.choleskyHelper +import space.kscience.kmath.tensors.core.cleanSymHelper +import space.kscience.kmath.tensors.core.luHelper +import space.kscience.kmath.tensors.core.luMatrixDet +import space.kscience.kmath.tensors.core.luMatrixInv +import space.kscience.kmath.tensors.core.luPivotHelper +import space.kscience.kmath.tensors.core.pivInit import kotlin.math.min @@ -25,12 +39,11 @@ public class DoubleLinearOpsTensorAlgebra : luTensor: TensorStructure, pivotsTensor: TensorStructure ): Triple { - //todo checks checkSquareMatrix(luTensor.shape) check( luTensor.shape.dropLast(2).toIntArray() contentEquals pivotsTensor.shape.dropLast(1).toIntArray() || luTensor.shape.last() == pivotsTensor.shape.last() - 1 - ) { "Bad shapes ((" } //todo rewrite + ) { "Inappropriate shapes of input tensors" } val n = luTensor.shape.last() val pTensor = luTensor.zeroesLike() @@ -90,10 +103,10 @@ public class DoubleLinearOpsTensorAlgebra : for ((matrix, USV) in tensor.matrixSequence() .zip(resU.matrixSequence().zip(resS.vectorSequence().zip(resV.matrixSequence())))) { - val size = matrix.shape.reduce { acc, i -> acc * i } + val matrixSize = matrix.shape.reduce { acc, i -> acc * i } val curMatrix = DoubleTensor( matrix.shape, - matrix.buffer.array().slice(matrix.bufferStart until matrix.bufferStart + size).toDoubleArray() + matrix.buffer.array().slice(matrix.bufferStart until matrix.bufferStart + matrixSize).toDoubleArray() ) svdHelper(curMatrix, USV, m, n, epsilon) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt similarity index 92% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index 7544bf68e..651db2c21 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -1,8 +1,24 @@ -package space.kscience.kmath.tensors.core +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.core.algebras import space.kscience.kmath.nd.as2D -import space.kscience.kmath.tensors.TensorPartialDivisionAlgebra -import space.kscience.kmath.tensors.TensorStructure +import space.kscience.kmath.tensors.api.TensorPartialDivisionAlgebra +import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.core.* +import space.kscience.kmath.tensors.core.broadcastOuterTensors +import space.kscience.kmath.tensors.core.checkBufferShapeConsistency +import space.kscience.kmath.tensors.core.checkEmptyDoubleBuffer +import space.kscience.kmath.tensors.core.checkEmptyShape +import space.kscience.kmath.tensors.core.checkShapesCompatible +import space.kscience.kmath.tensors.core.checkTranspose +import space.kscience.kmath.tensors.core.checkView +import space.kscience.kmath.tensors.core.dotHelper +import space.kscience.kmath.tensors.core.getRandomNormals +import space.kscience.kmath.tensors.core.minusIndexFrom import kotlin.math.abs public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { @@ -263,7 +279,6 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { if (m1 != m2) { throw RuntimeException("Tensors dot operation dimension mismatch: ($l, $m1) x ($m2, $n)") } - val m = m1 val resShape = newThis.shape.sliceArray(0..(newThis.shape.size - 2)) + intArrayOf(newOther.shape.last()) val resSize = resShape.reduce { acc, i -> acc * i } @@ -271,7 +286,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { for ((res, ab) in resTensor.matrixSequence().zip(newThis.matrixSequence().zip(newOther.matrixSequence()))) { val (a, b) = ab - dotHelper(a.as2D(), b.as2D(), res.as2D(), l, m, n) + dotHelper(a.as2D(), b.as2D(), res.as2D(), l, m1, n) } if (penultimateDim) { @@ -347,7 +362,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return tensor.eq(other) { x, y -> abs(x - y) < delta } } - public fun TensorStructure.eq(other: TensorStructure): Boolean = tensor.eq(other, 1e-5) + public infix fun TensorStructure.eq(other: TensorStructure): Boolean = tensor.eq(other, 1e-5) private fun TensorStructure.eq( other: TensorStructure, diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt similarity index 90% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt index 47745c2be..b16739892 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt @@ -1,4 +1,9 @@ -package space.kscience.kmath.tensors.core +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.core.algebras import kotlin.math.max diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt similarity index 52% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt index 53c385197..4378e9ac9 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt @@ -1,89 +1,31 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.tensors.TensorStructure +import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra import kotlin.math.max -public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { - - override fun TensorStructure.plus(other: TensorStructure): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> - newThis.buffer.array()[i] + newOther.buffer.array()[i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun TensorStructure.plusAssign(other: TensorStructure) { - val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.size) { - tensor.buffer.array()[tensor.bufferStart + i] += - newOther.buffer.array()[tensor.bufferStart + i] - } - } - - override fun TensorStructure.minus(other: TensorStructure): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> - newThis.buffer.array()[i] - newOther.buffer.array()[i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun TensorStructure.minusAssign(other: TensorStructure) { - val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.size) { - tensor.buffer.array()[tensor.bufferStart + i] -= - newOther.buffer.array()[tensor.bufferStart + i] - } - } - - override fun TensorStructure.times(other: TensorStructure): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> - newThis.buffer.array()[newThis.bufferStart + i] * - newOther.buffer.array()[newOther.bufferStart + i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun TensorStructure.timesAssign(other: TensorStructure) { - val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.size) { - tensor.buffer.array()[tensor.bufferStart + i] *= - newOther.buffer.array()[tensor.bufferStart + i] - } - } - - override fun TensorStructure.div(other: TensorStructure): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> - newThis.buffer.array()[newOther.bufferStart + i] / - newOther.buffer.array()[newOther.bufferStart + i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun TensorStructure.divAssign(other: TensorStructure) { - val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.size) { - tensor.buffer.array()[tensor.bufferStart + i] /= - newOther.buffer.array()[tensor.bufferStart + i] - } - } - -} - public inline fun BroadcastDoubleTensorAlgebra(block: BroadcastDoubleTensorAlgebra.() -> R): R = BroadcastDoubleTensorAlgebra().block() +internal inline fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTensor, linearSize: Int) { + for (linearIndex in 0 until linearSize) { + val totalMultiIndex = resTensor.linearStructure.index(linearIndex) + val curMultiIndex = tensor.shape.copyOf() + + val offset = totalMultiIndex.size - curMultiIndex.size + + for (i in curMultiIndex.indices) { + if (curMultiIndex[i] != 1) { + curMultiIndex[i] = totalMultiIndex[i + offset] + } else { + curMultiIndex[i] = 0 + } + } + + val curLinearIndex = tensor.linearStructure.offset(curMultiIndex) + resTensor.buffer.array()[linearIndex] = + tensor.buffer.array()[tensor.bufferStart + curLinearIndex] + } +} internal inline fun broadcastShapes(vararg shapes: IntArray): IntArray { var totalDim = 0 @@ -129,24 +71,7 @@ internal inline fun broadcastTo(tensor: DoubleTensor, newShape: IntArray): Doubl } } - for (linearIndex in 0 until n) { - val totalMultiIndex = resTensor.linearStructure.index(linearIndex) - val curMultiIndex = tensor.shape.copyOf() - - val offset = totalMultiIndex.size - curMultiIndex.size - - for (i in curMultiIndex.indices) { - if (curMultiIndex[i] != 1) { - curMultiIndex[i] = totalMultiIndex[i + offset] - } else { - curMultiIndex[i] = 0 - } - } - - val curLinearIndex = tensor.linearStructure.offset(curMultiIndex) - resTensor.buffer.array()[linearIndex] = - tensor.buffer.array()[tensor.bufferStart + curLinearIndex] - } + multiIndexBroadCasting(tensor, resTensor, n) return resTensor } @@ -157,25 +82,7 @@ internal inline fun broadcastTensors(vararg tensors: DoubleTensor): List(0) for (tensor in tensors) { val resTensor = DoubleTensor(totalShape, DoubleArray(n)) - - for (linearIndex in 0 until n) { - val totalMultiIndex = resTensor.linearStructure.index(linearIndex) - val curMultiIndex = tensor.shape.copyOf() - - val offset = totalMultiIndex.size - curMultiIndex.size - - for (i in curMultiIndex.indices) { - if (curMultiIndex[i] != 1) { - curMultiIndex[i] = totalMultiIndex[i + offset] - } else { - curMultiIndex[i] = 0 - } - } - - val curLinearIndex = tensor.linearStructure.offset(curMultiIndex) - resTensor.buffer.array()[linearIndex] = - tensor.buffer.array()[tensor.bufferStart + curLinearIndex] - } + multiIndexBroadCasting(tensor, resTensor, n) res.add(resTensor) } @@ -208,7 +115,7 @@ internal inline fun broadcastOuterTensors(vararg tensors: DoubleTensor): List BufferedTensor.matrixSequence(): Sequence BufferedTensor.forEachVector(vectorAction: (BufferedTensor) -> Unit): Unit { +internal inline fun BufferedTensor.forEachVector(vectorAction: (BufferedTensor) -> Unit) { for (vector in vectorSequence()) { vectorAction(vector) } } -internal inline fun BufferedTensor.forEachMatrix(matrixAction: (BufferedTensor) -> Unit): Unit { +internal inline fun BufferedTensor.forEachMatrix(matrixAction: (BufferedTensor) -> Unit) { for (matrix in matrixSequence()) { matrixAction(matrix) } @@ -284,7 +286,7 @@ internal inline fun DoubleLinearOpsTensorAlgebra.svdHelper( matrix: DoubleTensor, USV: Pair, Pair, BufferedTensor>>, m: Int, n: Int, epsilon: Double -): Unit { +) { val res = ArrayList>(0) val (matrixU, SV) = USV val (matrixS, matrixV) = SV @@ -332,7 +334,7 @@ internal inline fun DoubleLinearOpsTensorAlgebra.svdHelper( } } -internal inline fun cleanSymHelper(matrix: MutableStructure2D, n: Int): Unit { +internal inline fun cleanSymHelper(matrix: MutableStructure2D, n: Int) { for (i in 0 until n) for (j in 0 until n) { if (i == j) { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index ac823185b..d7d006e42 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -110,7 +110,6 @@ internal inline fun DoubleTensor.toPrettyString(): String = buildString { charOffset -=1 } offset += vectorSize - // todo refactor if (this@toPrettyString.numElements == offset) { break } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt index 41c9b72f7..d677f6966 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt @@ -1,5 +1,6 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import kotlin.test.Test import kotlin.test.assertTrue diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt index 4dcdb7848..060bc1607 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt @@ -1,5 +1,6 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra import kotlin.math.abs import kotlin.math.exp import kotlin.test.Test diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index d19d0b6f6..6120f0e4a 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -1,5 +1,6 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra import kotlin.math.abs import kotlin.test.Test import kotlin.test.assertEquals @@ -125,8 +126,6 @@ class TestDoubleLinearOpsTensorAlgebra { val (lu, pivots) = tensor.lu() - // todo check lu - val (p, l, u) = luPivot(lu, pivots) assertTrue { p.shape contentEquals shape } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index 4de69e1ad..5c068ce83 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -3,7 +3,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D import space.kscience.kmath.structures.toDoubleArray -import kotlin.test.Ignore +import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index fa7a8fd32..10a9176dc 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -1,7 +1,9 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import kotlin.test.Test +import kotlin.test.assertFalse import kotlin.test.assertTrue class TestDoubleTensorAlgebra { @@ -133,9 +135,9 @@ class TestDoubleTensorAlgebra { assertTrue(diagonal1.buffer.array() contentEquals doubleArrayOf(10.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 30.0)) - val diagonal1_offset = diagonalEmbedding(tensor1, 1, 1, 0) - assertTrue(diagonal1_offset.shape contentEquals intArrayOf(4, 4)) - assertTrue(diagonal1_offset.buffer.array() contentEquals + val diagonal1Offset = diagonalEmbedding(tensor1, 1, 1, 0) + assertTrue(diagonal1Offset.shape contentEquals intArrayOf(4, 4)) + assertTrue(diagonal1Offset.buffer.array() contentEquals doubleArrayOf(0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 30.0, 0.0)) val diagonal2 = diagonalEmbedding(tensor2, 1, 0, 2) @@ -149,7 +151,15 @@ class TestDoubleTensorAlgebra { } @Test - fun testContentEqual() = DoubleTensorAlgebra { - //TODO() + fun testEq() = DoubleTensorAlgebra { + 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 tensor3 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 5.0)) + val tensor4 = fromArray(intArrayOf(6, 1), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) + + assertTrue(tensor1 eq tensor1) + assertTrue(tensor1 eq tensor2) + assertFalse(tensor1.eq(tensor3)) + } } \ No newline at end of file From 287e2aeba2ba274508f42f1ab0a839ed69861bc1 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 23 Apr 2021 14:22:52 +0100 Subject: [PATCH 115/178] div operator --- .../kmath/tensors/api/TensorPartialDivisionAlgebra.kt | 1 + .../kmath/tensors/core/algebras/DoubleTensorAlgebra.kt | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt index 075e86e61..4dab3dd07 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt @@ -8,6 +8,7 @@ package space.kscience.kmath.tensors.api // https://proofwiki.org/wiki/Definition:Division_Algebra public interface TensorPartialDivisionAlgebra : TensorAlgebra { + public operator fun T.div(other: TensorStructure): TensorStructure public operator fun TensorStructure.div(value: T): TensorStructure public operator fun TensorStructure.div(other: TensorStructure): TensorStructure public operator fun TensorStructure.divAssign(value: T) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index 651db2c21..b61a484d0 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -178,13 +178,15 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { } } - override fun TensorStructure.div(value: Double): DoubleTensor { - val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.buffer.array()[tensor.bufferStart + i] / value + override fun Double.div(other: TensorStructure): DoubleTensor { + val resBuffer = DoubleArray(other.tensor.numElements) { i -> + other.tensor.buffer.array()[other.tensor.bufferStart + i] / this } - return DoubleTensor(tensor.shape, resBuffer) + return DoubleTensor(other.shape, resBuffer) } + override fun TensorStructure.div(value: Double): DoubleTensor = value / tensor + override fun TensorStructure.div(other: TensorStructure): DoubleTensor { checkShapesCompatible(tensor, other) val resBuffer = DoubleArray(tensor.numElements) { i -> From 4f593aec63cd931ebe2d254baf6cee0ef3ca342c Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Sat, 24 Apr 2021 18:53:21 +0100 Subject: [PATCH 116/178] Buffer mini-protocol --- kmath-core/api/kmath-core.api | 8 ++++- .../space/kscience/kmath/nd/BufferND.kt | 35 ++++++++++++++++++- .../kmath/tensors/core/BufferedTensor.kt | 2 ++ .../kscience/kmath/tensors/core/utils.kt | 23 +++--------- .../kmath/tensors/core/TestDoubleTensor.kt | 34 ++++++++++++++++++ 5 files changed, 81 insertions(+), 21 deletions(-) diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index 38cfbd58d..41b85b3bb 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -748,7 +748,7 @@ public final class space/kscience/kmath/nd/BufferAlgebraNDKt { public static final fun ring (Lspace/kscience/kmath/nd/AlgebraND$Companion;Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;[I)Lspace/kscience/kmath/nd/BufferedRingND; } -public final class space/kscience/kmath/nd/BufferND : space/kscience/kmath/nd/StructureND { +public class space/kscience/kmath/nd/BufferND : space/kscience/kmath/nd/StructureND { public fun (Lspace/kscience/kmath/nd/Strides;Lspace/kscience/kmath/structures/Buffer;)V public fun elements ()Lkotlin/sequences/Sequence; public fun get ([I)Ljava/lang/Object; @@ -876,6 +876,12 @@ public abstract interface class space/kscience/kmath/nd/GroupND : space/kscience public final class space/kscience/kmath/nd/GroupND$Companion { } +public final class space/kscience/kmath/nd/MutableBufferND : space/kscience/kmath/nd/BufferND, space/kscience/kmath/nd/MutableStructureND { + public fun (Lspace/kscience/kmath/nd/Strides;Lspace/kscience/kmath/structures/MutableBuffer;)V + public final fun getMutableBuffer ()Lspace/kscience/kmath/structures/MutableBuffer; + public fun set ([ILjava/lang/Object;)V +} + public abstract interface class space/kscience/kmath/nd/MutableStructure1D : space/kscience/kmath/nd/MutableStructureND, space/kscience/kmath/nd/Structure1D, space/kscience/kmath/structures/MutableBuffer { public fun set ([ILjava/lang/Object;)V } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt index 23d961a7e..1f608f478 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt @@ -7,6 +7,8 @@ package space.kscience.kmath.nd import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory +import space.kscience.kmath.structures.MutableBuffer +import space.kscience.kmath.structures.MutableBufferFactory /** * Represents [StructureND] over [Buffer]. @@ -15,7 +17,7 @@ import space.kscience.kmath.structures.BufferFactory * @param strides The strides to access elements of [Buffer] by linear indices. * @param buffer The underlying buffer. */ -public class BufferND( +public open class BufferND( public val strides: Strides, public val buffer: Buffer, ) : StructureND { @@ -50,4 +52,35 @@ public inline fun StructureND.mapToBuffer( val strides = DefaultStrides(shape) BufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) } +} + +/** + * Represents [MutableStructureND] over [MutableBuffer]. + * + * @param T the type of items. + * @param strides The strides to access elements of [MutableBuffer] by linear indices. + * @param mutableBuffer The underlying buffer. + */ +public class MutableBufferND( + strides: Strides, + public val mutableBuffer: MutableBuffer, +) : MutableStructureND, BufferND(strides, mutableBuffer) { + override fun set(index: IntArray, value: T) { + mutableBuffer[strides.offset(index)] = value + } +} + +/** + * Transform structure to a new structure using provided [MutableBufferFactory] and optimizing if argument is [MutableBufferND] + */ +public inline fun MutableStructureND.mapToMutableBuffer( + factory: MutableBufferFactory = MutableBuffer.Companion::auto, + crossinline transform: (T) -> R, +): MutableBufferND { + return if (this is MutableBufferND) + MutableBufferND(this.strides, factory.invoke(strides.linearSize) { transform(mutableBuffer[it]) }) + else { + val strides = DefaultStrides(shape) + MutableBufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) + } } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 5c0d9c4ea..1e9b458b1 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -1,5 +1,6 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.nd.MutableBufferND import space.kscience.kmath.structures.* import space.kscience.kmath.tensors.api.TensorStructure import space.kscience.kmath.tensors.core.algebras.TensorLinearStructure @@ -60,6 +61,7 @@ internal inline fun BufferedTensor.asTensor(): DoubleTensor = DoubleTens internal inline fun TensorStructure.toBufferedTensor(): BufferedTensor = when (this) { is BufferedTensor -> this + is MutableBufferND -> BufferedTensor(this.shape, this.mutableBuffer, 0) else -> BufferedTensor(this.shape, this.elements().map{ it.second }.toMutableList().asMutableBuffer(), 0) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index d7d006e42..89e9d0d96 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -7,35 +7,20 @@ import space.kscience.kmath.structures.* import kotlin.math.* /** - * Returns a reference to [IntArray] containing all of the elements of this [Buffer]. + * Returns a reference to [IntArray] containing all of the elements of this [Buffer] or copy the data. */ internal fun Buffer.array(): IntArray = when (this) { is IntBuffer -> array - else -> throw RuntimeException("Failed to cast Buffer to IntArray") + else -> this.toIntArray() } -/** - * Returns a reference to [LongArray] containing all of the elements of this [Buffer]. - */ -internal fun Buffer.array(): LongArray = when (this) { - is LongBuffer -> array - else -> throw RuntimeException("Failed to cast Buffer to LongArray") -} /** - * Returns a reference to [FloatArray] containing all of the elements of this [Buffer]. - */ -internal fun Buffer.array(): FloatArray = when (this) { - is FloatBuffer -> array - else -> throw RuntimeException("Failed to cast Buffer to FloatArray") -} - -/** - * Returns a reference to [DoubleArray] containing all of the elements of this [Buffer]. + * Returns a reference to [DoubleArray] containing all of the elements of this [Buffer] or copy the data. */ internal fun Buffer.array(): DoubleArray = when (this) { is DoubleBuffer -> array - else -> throw RuntimeException("Failed to cast Buffer to DoubleArray") + else -> this.toDoubleArray() } internal inline fun getRandomNormals(n: Int, seed: Long): DoubleArray { diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index 5c068ce83..f9d15c216 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -1,7 +1,11 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.nd.DefaultStrides +import space.kscience.kmath.nd.MutableBufferND import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D +import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.asMutableBuffer import space.kscience.kmath.structures.toDoubleArray import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import kotlin.test.Test @@ -47,4 +51,34 @@ class TestDoubleTensor { assertEquals(secondRow[1], secondColumn[1]) } } + + @Test + fun bufferProtocol() { + + // create buffers + val doubleBuffer = DoubleBuffer(doubleArrayOf(1.0,2.0,3.0)) + val doubleList = MutableList(3, doubleBuffer::get) + + // create ND buffers + val ndBuffer = MutableBufferND(DefaultStrides(intArrayOf(3)), doubleBuffer) + val ndList = MutableBufferND(DefaultStrides(intArrayOf(3)), doubleList.asMutableBuffer()) + + // map to tensors + val bufferedTensorBuffer = ndBuffer.toBufferedTensor() // strides are flipped + val tensorBuffer = bufferedTensorBuffer.asTensor() // no data copied + + val bufferedTensorList = ndList.toBufferedTensor() // strides are flipped + val tensorList = bufferedTensorList.asTensor() // data copied + + tensorBuffer[intArrayOf(0)] = 55.9 + assertEquals(ndBuffer[intArrayOf(0)], 55.9) + assertEquals(doubleBuffer[0], 55.9) + + tensorList[intArrayOf(0)] = 55.9 + assertEquals(ndList[intArrayOf(0)], 1.0) + assertEquals(doubleList[0], 1.0) + + ndList[intArrayOf(0)] = 55.9 + assertEquals(doubleList[0], 55.9) + } } \ No newline at end of file From 2c001cb1b32f25dc4c245bc32b4046bf78e85cca Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Mon, 26 Apr 2021 17:07:49 +0300 Subject: [PATCH 117/178] fix div + simple tests --- .../tensors/core/algebras/DoubleTensorAlgebra.kt | 9 +++++++-- .../kmath/tensors/core/TestDoubleTensorAlgebra.kt | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index b61a484d0..7414a4469 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -180,12 +180,17 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { override fun Double.div(other: TensorStructure): DoubleTensor { val resBuffer = DoubleArray(other.tensor.numElements) { i -> - other.tensor.buffer.array()[other.tensor.bufferStart + i] / this + this / other.tensor.buffer.array()[other.tensor.bufferStart + i] } return DoubleTensor(other.shape, resBuffer) } - override fun TensorStructure.div(value: Double): DoubleTensor = value / tensor + override fun TensorStructure.div(value: Double): DoubleTensor { + val resBuffer = DoubleArray(tensor.numElements) { i -> + tensor.buffer.array()[tensor.bufferStart + i] / value + } + return DoubleTensor(shape, resBuffer) + } override fun TensorStructure.div(other: TensorStructure): DoubleTensor { checkShapesCompatible(tensor, other) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index 10a9176dc..1333a7a1f 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -15,6 +15,20 @@ class TestDoubleTensorAlgebra { assertTrue(res.buffer.array() contentEquals doubleArrayOf(11.0, 12.0)) } + @Test + fun doubleDiv() = DoubleTensorAlgebra { + val tensor = fromArray(intArrayOf(2), doubleArrayOf(2.0, 4.0)) + val res = 2.0/tensor + assertTrue(res.buffer.array() contentEquals doubleArrayOf(1.0, 0.5)) + } + + @Test + fun divDouble() = DoubleTensorAlgebra { + val tensor = fromArray(intArrayOf(2), doubleArrayOf(10.0, 5.0)) + val res = tensor / 2.5 + assertTrue(res.buffer.array() contentEquals doubleArrayOf(4.0, 2.0)) + } + @Test fun transpose1x1() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(1), doubleArrayOf(0.0)) From 30ca333c040b09ca65d528b052fa27492161654a Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Mon, 26 Apr 2021 17:27:50 +0300 Subject: [PATCH 118/178] OLS/SVD example --- examples/build.gradle.kts | 1 + .../kscience/kmath/tensors/OLSWithSVD.kt | 68 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 56feee9dc..a4eabc2b8 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -28,6 +28,7 @@ dependencies { implementation(project(":kmath-dimensions")) implementation(project(":kmath-ejml")) implementation(project(":kmath-nd4j")) + implementation(project(":kmath-tensors")) implementation(project(":kmath-for-real")) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt new file mode 100644 index 000000000..063a1d1c4 --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt @@ -0,0 +1,68 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors + +import space.kscience.kmath.tensors.core.DoubleTensor +import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra +import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra + +// OLS estimator using SVD + +fun main() { + //seed for random + val randSeed = 100500L + + // work in context with linear operations + DoubleLinearOpsTensorAlgebra { + // take coefficient vector from normal distribution + val alpha = randNormal( + intArrayOf(5), + randSeed + ) + fromArray( + intArrayOf(5), + doubleArrayOf(1.0, 2.5, 3.4, 5.0, 10.1) + ) + + println("Real alpha:\n" + + "$alpha") + + // also take sample of size 20 from normal distribution for x TODO rename + val x = randNormal( + intArrayOf(20, 5), + randSeed + ) + + // calculate y and add gaussian noise (N(0, 0.05)) TODO rename + val y = x dot alpha + y += y.randNormalLike(randSeed) * 0.05 + + // now restore the coefficient vector with OSL estimator with SVD + val (u, singValues, v) = x.svd() + + // we have to make sure the singular values of the matrix are not close to zero + println("Singular values:\n" + + "$singValues") + // TODO something with Boolean tensors + + // inverse Sigma matrix can be restored from singular values with diagonalEmbedding function + val sigma = diagonalEmbedding(1.0/singValues) + + val alphaOLS = v dot sigma dot u.transpose() dot y + println("Estimated alpha:\n" + + "$alphaOLS") + + // figure out MSE of approximation + fun mse(yTrue: DoubleTensor, yPred: DoubleTensor): Double = DoubleAnalyticTensorAlgebra{ + require(yTrue.shape.size == 1) + require(yTrue.shape contentEquals yPred.shape) + + val diff = yTrue - yPred + diff.dot(diff).sqrt().value() + } + + println("MSE: ${mse(alpha, alphaOLS)}") + } +} \ No newline at end of file From c2db3a23e1e6a14463d3dadac6d279ccabb49272 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Mon, 26 Apr 2021 16:24:26 +0100 Subject: [PATCH 119/178] Feedback for SVD --- .../space/kscience/kmath/tensors/OLSWithSVD.kt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt index 063a1d1c4..a9b154017 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt @@ -9,6 +9,8 @@ import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra +import kotlin.math.abs + // OLS estimator using SVD fun main() { @@ -26,8 +28,7 @@ fun main() { doubleArrayOf(1.0, 2.5, 3.4, 5.0, 10.1) ) - println("Real alpha:\n" + - "$alpha") + println("Real alpha:\n$alpha") // also take sample of size 20 from normal distribution for x TODO rename val x = randNormal( @@ -35,20 +36,22 @@ fun main() { randSeed ) - // calculate y and add gaussian noise (N(0, 0.05)) TODO rename + // calculate y and add gaussian noise (N(0, 0.05)) + // TODO: please add an intercept: Y = beta * X + alpha + N(0,0.5) val y = x dot alpha y += y.randNormalLike(randSeed) * 0.05 // now restore the coefficient vector with OSL estimator with SVD + // TODO: you need to change accordingly [X 1] [alpha beta] = Y + // TODO: inverting [X 1] via SVD val (u, singValues, v) = x.svd() // we have to make sure the singular values of the matrix are not close to zero - println("Singular values:\n" + - "$singValues") - // TODO something with Boolean tensors + println("Singular values:\n$singValues") + // inverse Sigma matrix can be restored from singular values with diagonalEmbedding function - val sigma = diagonalEmbedding(1.0/singValues) + val sigma = diagonalEmbedding(singValues.map{ x -> if (abs(x) < 1e-3) 0.0 else 1.0/x }) val alphaOLS = v dot sigma dot u.transpose() dot y println("Estimated alpha:\n" + From 23ea4a95a151e8ce1a70566a4ede3c7d343e5caa Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Tue, 27 Apr 2021 19:01:54 +0100 Subject: [PATCH 120/178] Fixed strides flipping --- .../kmath/tensors/core/BufferedTensor.kt | 23 +++++--- .../kmath/tensors/core/TestDoubleTensor.kt | 58 ++++++++++--------- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 1e9b458b1..6e1cab11a 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -37,9 +37,8 @@ public class IntTensor internal constructor( shape: IntArray, buffer: IntArray, offset: Int = 0 -) : BufferedTensor(shape, IntBuffer(buffer), offset) -{ - internal constructor(bufferedTensor: BufferedTensor): +) : BufferedTensor(shape, IntBuffer(buffer), offset) { + internal constructor(bufferedTensor: BufferedTensor) : this(bufferedTensor.shape, bufferedTensor.buffer.array(), bufferedTensor.bufferStart) } @@ -47,9 +46,8 @@ public class DoubleTensor internal constructor( shape: IntArray, buffer: DoubleArray, offset: Int = 0 -) : BufferedTensor(shape, DoubleBuffer(buffer), offset) -{ - internal constructor(bufferedTensor: BufferedTensor): +) : BufferedTensor(shape, DoubleBuffer(buffer), offset) { + internal constructor(bufferedTensor: BufferedTensor) : this(bufferedTensor.shape, bufferedTensor.buffer.array(), bufferedTensor.bufferStart) override fun toString(): String = toPrettyString() @@ -59,10 +57,17 @@ public class DoubleTensor internal constructor( internal inline fun BufferedTensor.asTensor(): IntTensor = IntTensor(this) internal inline fun BufferedTensor.asTensor(): DoubleTensor = DoubleTensor(this) +internal inline fun TensorStructure.copyToBufferedTensor(): BufferedTensor = + BufferedTensor( + this.shape, + TensorLinearStructure(this.shape).indices().map(this::get).toMutableList().asMutableBuffer(), 0 + ) + internal inline fun TensorStructure.toBufferedTensor(): BufferedTensor = when (this) { is BufferedTensor -> this - is MutableBufferND -> BufferedTensor(this.shape, this.mutableBuffer, 0) - else -> BufferedTensor(this.shape, this.elements().map{ it.second }.toMutableList().asMutableBuffer(), 0) + is MutableBufferND -> if (this.strides.strides.toIntArray() contentEquals TensorLinearStructure(this.shape).strides) + BufferedTensor(this.shape, this.mutableBuffer, 0) else this.copyToBufferedTensor() + else -> this.copyToBufferedTensor() } internal val TensorStructure.tensor: DoubleTensor @@ -77,3 +82,5 @@ internal val TensorStructure.tensor: IntTensor else -> this.toBufferedTensor().asTensor() } +public fun TensorStructure.toTypedTensor(): DoubleTensor = this.tensor +public fun TensorStructure.toTypedTensor(): IntTensor = this.tensor \ No newline at end of file diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index f9d15c216..7103eafaa 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -23,62 +23,64 @@ class TestDoubleTensor { @Test fun stridesTest() = DoubleTensorAlgebra { - val tensor = fromArray(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.toDoubleArray()) + val tensor = fromArray(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.toDoubleArray() + ) } @Test 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() - assertEquals(matrix[0,1], 5.8) + assertEquals(matrix[0, 1], 5.8) val vector = tensor[0][1].as1D() assertEquals(vector[0], 58.4) - matrix[0,1] = 77.89 - assertEquals(tensor[intArrayOf(0,0,1)], 77.89) + matrix[0, 1] = 77.89 + assertEquals(tensor[intArrayOf(0, 0, 1)], 77.89) vector[0] = 109.56 - assertEquals(tensor[intArrayOf(0,1,0)], 109.56) + assertEquals(tensor[intArrayOf(0, 1, 0)], 109.56) tensor.matrixSequence().forEach { val a = it.asTensor() val secondRow = a[1].as1D() - val secondColumn = a.transpose(0,1)[1].as1D() + val secondColumn = a.transpose(0, 1)[1].as1D() assertEquals(secondColumn[0], 77.89) assertEquals(secondRow[1], secondColumn[1]) } } @Test - fun bufferProtocol() { + fun noBufferProtocol() { - // create buffers - val doubleBuffer = DoubleBuffer(doubleArrayOf(1.0,2.0,3.0)) - val doubleList = MutableList(3, doubleBuffer::get) + // create buffer + val doubleArray = DoubleBuffer(doubleArrayOf(1.0, 2.0, 3.0)) - // create ND buffers - val ndBuffer = MutableBufferND(DefaultStrides(intArrayOf(3)), doubleBuffer) - val ndList = MutableBufferND(DefaultStrides(intArrayOf(3)), doubleList.asMutableBuffer()) + // create ND buffers, no data is copied + val ndArray = MutableBufferND(DefaultStrides(intArrayOf(3)), doubleArray) // map to tensors - val bufferedTensorBuffer = ndBuffer.toBufferedTensor() // strides are flipped - val tensorBuffer = bufferedTensorBuffer.asTensor() // no data copied + val bufferedTensorArray = ndArray.toBufferedTensor() // strides are flipped so data copied + val tensorArray = bufferedTensorArray.asTensor() // data not contiguous so copied again - val bufferedTensorList = ndList.toBufferedTensor() // strides are flipped - val tensorList = bufferedTensorList.asTensor() // data copied + val tensorArrayPublic = ndArray.toTypedTensor() // public API, data copied twice + val sharedTensorArray = tensorArrayPublic.toTypedTensor() // no data copied by matching type - tensorBuffer[intArrayOf(0)] = 55.9 - assertEquals(ndBuffer[intArrayOf(0)], 55.9) - assertEquals(doubleBuffer[0], 55.9) + assertTrue(tensorArray.buffer.array() contentEquals sharedTensorArray.buffer.array()) - tensorList[intArrayOf(0)] = 55.9 - assertEquals(ndList[intArrayOf(0)], 1.0) - assertEquals(doubleList[0], 1.0) + tensorArray[intArrayOf(0)] = 55.9 + assertEquals(tensorArrayPublic[intArrayOf(0)], 1.0) + + tensorArrayPublic[intArrayOf(0)] = 55.9 + assertEquals(sharedTensorArray[intArrayOf(0)], 55.9) + assertEquals(bufferedTensorArray[intArrayOf(0)], 1.0) + + bufferedTensorArray[intArrayOf(0)] = 55.9 + assertEquals(ndArray[intArrayOf(0)], 1.0) - ndList[intArrayOf(0)] = 55.9 - assertEquals(doubleList[0], 55.9) } } \ No newline at end of file From b65a673173e6b1cd209fa355349bf9b90f718887 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 28 Apr 2021 14:16:57 +0100 Subject: [PATCH 121/178] Fix format for 0.0 --- .../kotlin/space/kscience/kmath/tensors/core/utils.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index 89e9d0d96..cb23dbdd6 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -47,17 +47,17 @@ internal inline fun BufferedTensor.minusIndex(i: Int): Int = minusIndexF internal inline fun format(value: Double, digits: Int = 4): String { val ten = 10.0 - val approxOrder = ceil(log10(abs(value))).toInt() + val approxOrder = if(value == 0.0) 0 else ceil(log10(abs(value))).toInt() val order = if( ((value % ten) == 0.0) or (value == 1.0) or ((1/value) % ten == 0.0)) approxOrder else approxOrder - 1 - val lead = value / ten.pow(order) val leadDisplay = round(lead*ten.pow(digits)) / ten.pow(digits) val orderDisplay = if(order == 0) "" else if(order > 0) "E+$order" else "E$order" val valueDisplay = "$leadDisplay$orderDisplay" val res = if(value < 0.0) valueDisplay else " $valueDisplay" + val fLength = digits + 6 val endSpace = " ".repeat(fLength - res.length) return "$res$endSpace" From a0e9180db6da06c2cdac36a25c4b44d951945850 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Wed, 28 Apr 2021 18:18:57 +0300 Subject: [PATCH 122/178] example with LUP --- .../tensors/LinearSystemSolvingWithLUP.kt | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt new file mode 100644 index 000000000..526b6781f --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt @@ -0,0 +1,97 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors + +import space.kscience.kmath.tensors.core.DoubleTensor +import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra + +// solving linear system with LUP decomposition + +fun main () { + + // work in context with linear operations + DoubleLinearOpsTensorAlgebra { + + // set true value of x + val trueX = fromArray( + intArrayOf(4), + doubleArrayOf(-2.0, 1.5, 6.8, -2.4) + ) + + // and A matrix + val a = fromArray( + intArrayOf(4, 4), + doubleArrayOf( + 0.5, 10.5, 4.5, 1.0, + 8.5, 0.9, 12.8, 0.1, + 5.56, 9.19, 7.62, 5.45, + 1.0, 2.0, -3.0, -2.5 + ) + ) + + // calculate y value + val b = a dot trueX + + // check out A and b + println("A:\n$a") + println("b:\n$b") + + // solve `Ax = b` system using LUP decomposition + + // get P, L, U such that PA = LU + val (lu, pivots) = a.lu() + val (p, l, u) = luPivot(lu, pivots) + + // check that P is permutation matrix + println("P:\n$p") + // L is lower triangular matrix and U is upper triangular matrix + println("L:\n$l") + println("U:\n$u") + // and PA = LU + println("PA:\n${p dot a}") + println("LU:\n${l dot u}") + + /* Ax = b; + PAx = Pb; + LUx = Pb; + let y = Ux, then + Ly = Pb -- this system can be easily solved, since the matrix L is lower triangular; + Ux = y can be solved the same way, since the matrix L is upper triangular + */ + + + + // this function returns solution x of a system lx = b, l should be lower triangular + fun solveLT(l: DoubleTensor, b: DoubleTensor): DoubleTensor { + val n = l.shape[0] + val x = zeros(intArrayOf(n)) + for (i in 0 until n){ + x[intArrayOf(i)] = (b[intArrayOf(i)] - l[i].dot(x).value()) / l[intArrayOf(i, i)] + } + return x + } + + val y = solveLT(l, p dot b) + + // solveLT(l, b) function can be easily adapted for upper triangular matrix by the permutation matrix revMat + // create it by placing ones on side diagonal + val revMat = u.zeroesLike() + val n = revMat.shape[0] + for (i in 0 until n) { + revMat[intArrayOf(i, n - 1 - i)] = 1.0 + } + + // solution of system ux = b, u should be upper triangular + fun solveUT(u: DoubleTensor, b: DoubleTensor): DoubleTensor = revMat dot solveLT( + revMat dot u dot revMat, revMat dot b + ) + + val x = solveUT(u, y) + + println("True x:\n$trueX") + println("x founded with LU method:\n$x") + } +} \ No newline at end of file From 51f084d28be21118c403ce5ae29775ab894971ae Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 28 Apr 2021 17:07:10 +0100 Subject: [PATCH 123/178] merge PR --- .../main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt index a9b154017..9318fe928 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt @@ -30,20 +30,17 @@ fun main() { println("Real alpha:\n$alpha") - // also take sample of size 20 from normal distribution for x TODO rename + // also take sample of size 20 from normal distribution for x val x = randNormal( intArrayOf(20, 5), randSeed ) // calculate y and add gaussian noise (N(0, 0.05)) - // TODO: please add an intercept: Y = beta * X + alpha + N(0,0.5) val y = x dot alpha y += y.randNormalLike(randSeed) * 0.05 // now restore the coefficient vector with OSL estimator with SVD - // TODO: you need to change accordingly [X 1] [alpha beta] = Y - // TODO: inverting [X 1] via SVD val (u, singValues, v) = x.svd() // we have to make sure the singular values of the matrix are not close to zero From 6f5b0f0a03e941b33d4adc22e341bce2f7d8bd00 Mon Sep 17 00:00:00 2001 From: AlyaNovikova Date: Thu, 29 Apr 2021 17:09:50 +0300 Subject: [PATCH 124/178] add README and documentation for the main functions of tensor algebra --- README.md | 12 + kmath-tensors/README.md | 37 +++ kmath-tensors/build.gradle.kts | 26 ++- kmath-tensors/docs/README-TEMPLATE.md | 7 + .../tensors/api/LinearOpsTensorAlgebra.kt | 84 ++++++- .../kmath/tensors/api/TensorAlgebra.kt | 211 +++++++++++++++++- .../algebras/BroadcastDoubleTensorAlgebra.kt | 4 + 7 files changed, 365 insertions(+), 16 deletions(-) create mode 100644 kmath-tensors/README.md create mode 100644 kmath-tensors/docs/README-TEMPLATE.md diff --git a/README.md b/README.md index 773eb6398..19c59e79e 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,18 @@ One can still use generic algebras though. > **Maturity**: EXPERIMENTAL
+* ### [kmath-tensors](kmath-tensors) +> +> +> **Maturity**: PROTOTYPE +> +> **Features:** +> - [tensor algebra](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt) : Basic linear algebra operations on tensors (plus, dot, etc.) +> - [tensor algebra with broadcasting](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt) : Basic linear algebra operations implemented with broadcasting. +> - [linear algebra operations](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt) : Advanced linear algebra operations like LU decomposition, SVD, etc. + +
+ * ### [kmath-viktor](kmath-viktor) > > diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md new file mode 100644 index 000000000..3b82829f0 --- /dev/null +++ b/kmath-tensors/README.md @@ -0,0 +1,37 @@ +# Module kmath-tensors + +Common linear algebra operations on tensors. + + - [tensor algebra](src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt) : Basic linear algebra operations on tensors (plus, dot, etc.) + - [tensor algebra with broadcasting](src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt) : Basic linear algebra operations implemented with broadcasting. + - [linear algebra operations](src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt) : Advanced linear algebra operations like LU decomposition, SVD, etc. + + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-7`. + +**Gradle:** +```gradle +repositories { + maven { url 'https://repo.kotlin.link' } + maven { url 'https://dl.bintray.com/hotkeytlt/maven' } + maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap +} + +dependencies { + implementation 'space.kscience:kmath-tensors:0.3.0-dev-7' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap + maven("https://dl.bintray.com/hotkeytlt/maven") // required for a +} + +dependencies { + implementation("space.kscience:kmath-tensors:0.3.0-dev-7") +} +``` diff --git a/kmath-tensors/build.gradle.kts b/kmath-tensors/build.gradle.kts index 8e823416b..af5116022 100644 --- a/kmath-tensors/build.gradle.kts +++ b/kmath-tensors/build.gradle.kts @@ -11,6 +11,30 @@ kotlin.sourceSets { } } +tasks.dokkaHtml { + dependsOn(tasks.build) +} + readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL + maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) + + feature( + id = "tensor algebra", + description = "Basic linear algebra operations on tensors (plus, dot, etc.)", + ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt" + ) + + feature( + id = "tensor algebra with broadcasting", + description = "Basic linear algebra operations implemented with broadcasting.", + ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt" + ) + + feature( + id = "linear algebra operations", + description = "Advanced linear algebra operations like LU decomposition, SVD, etc.", + ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt" + ) + } \ No newline at end of file diff --git a/kmath-tensors/docs/README-TEMPLATE.md b/kmath-tensors/docs/README-TEMPLATE.md new file mode 100644 index 000000000..5fd968afd --- /dev/null +++ b/kmath-tensors/docs/README-TEMPLATE.md @@ -0,0 +1,7 @@ +# Module kmath-tensors + +Common linear algebra operations on tensors. + +${features} + +${artifact} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt index 5cd48ca78..6735efacb 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -5,33 +5,99 @@ package space.kscience.kmath.tensors.api - +/** + * Common linear algebra operations. Operates on [TensorStructure]. + * + * @param T the type of items in the tensors. + */ public interface LinearOpsTensorAlgebra : TensorPartialDivisionAlgebra { - //https://pytorch.org/docs/stable/linalg.html#torch.linalg.det + /** + * Computes the determinant of a square matrix input, or of each square matrix in a batched input. + * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.det + * + * @return the determinant. + */ public fun TensorStructure.det(): TensorStructure - //https://pytorch.org/docs/stable/linalg.html#torch.linalg.inv + /** + * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input. + * Given a square matrix `a`, return the matrix `aInv` satisfying + * ``a.dot(aInv) = aInv.dot(a) = eye(a.shape[0])``. + * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.inv + * + * @return the multiplicative inverse of a matrix. + */ public fun TensorStructure.inv(): TensorStructure - //https://pytorch.org/docs/stable/linalg.html#torch.linalg.cholesky + /** + * Cholesky decomposition. + * + * Computes the Cholesky decomposition of a Hermitian (or symmetric for real-valued matrices) + * positive-definite matrix or the Cholesky decompositions for a batch of such matrices. + * Each decomposition has the form: + * Given a tensor `input`, return the tensor `L` satisfying ``input = L * L.H``, + * where L is a lower-triangular matrix and L.H is the conjugate transpose of L, + * which is just a transpose for the case of real-valued input matrices. + * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.cholesky + * + * @return the batch of L matrices. + */ public fun TensorStructure.cholesky(): TensorStructure - //https://pytorch.org/docs/stable/linalg.html#torch.linalg.qr + /** + * QR decomposition. + * + * Computes the QR decomposition of a matrix or a batch of matrices, and returns a namedtuple `(Q, R)` of tensors. + * Given a tensor `input`, return tensors (Q, R) satisfying ``input = Q * R``, + * with `Q` being an orthogonal matrix or batch of orthogonal matrices + * and `R` being an upper triangular matrix or batch of upper triangular matrices. + * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.qr + * + * @return tuple of Q and R tensors. + */ public fun TensorStructure.qr(): Pair, TensorStructure> - //https://pytorch.org/docs/stable/generated/torch.lu.html + /** + * TODO('Andrew') + * For more information: https://pytorch.org/docs/stable/generated/torch.lu.html + * + * @return ... + */ public fun TensorStructure.lu(): Pair, TensorStructure> - //https://pytorch.org/docs/stable/generated/torch.lu_unpack.html + /** + * TODO('Andrew') + * For more information: https://pytorch.org/docs/stable/generated/torch.lu_unpack.html + * + * @param luTensor ... + * @param pivotsTensor ... + * @return ... + */ public fun luPivot(luTensor: TensorStructure, pivotsTensor: TensorStructure): Triple, TensorStructure, TensorStructure> - //https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd + /** + * Singular Value Decomposition. + * + * Computes the singular value decomposition of either a matrix or batch of matrices `input`. + * The singular value decomposition is represented as a namedtuple `(U, S, V)`, + * such that ``input = U.dot(diagonalEmbedding(S).dot(V.T))``. + * If input is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as input. + * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd + * + * @return the determinant. + */ public fun TensorStructure.svd(): Triple, TensorStructure, TensorStructure> - //https://pytorch.org/docs/stable/generated/torch.symeig.html + /** + * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, + * represented by a namedtuple (eigenvalues, eigenvectors). + * For more information: https://pytorch.org/docs/stable/generated/torch.symeig.html + * + * @return a namedtuple (eigenvalues, eigenvectors) + */ public fun TensorStructure.symEig(): Pair, TensorStructure> } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index c1657d916..92aafb8ea 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -5,44 +5,243 @@ package space.kscience.kmath.tensors.api -// https://proofwiki.org/wiki/Definition:Algebra_over_Ring +/** + * Basic linear algebra operations on [TensorStructure]. + * For more information: https://proofwiki.org/wiki/Definition:Algebra_over_Ring + * + * @param T the type of items in the tensors. + */ public interface TensorAlgebra { + /** + * Returns a single tensor value of unit dimension. The tensor shape must be equal to [1]. + * + * @return the value of a scalar tensor. + */ public fun TensorStructure.value(): T + /** + * Each element of the tensor [other] is added to this value. + * The resulting tensor is returned. + * + * @param other tensor to be added. + * @return the sum of this value and tensor [other]. + */ public operator fun T.plus(other: TensorStructure): TensorStructure + + /** + * Adds the scalar [value] to each element of this tensor and returns a new resulting tensor. + * + * @param value the number to be added to each element of this tensor. + * @return the sum of this tensor and [value]. + */ public operator fun TensorStructure.plus(value: T): TensorStructure + + /** + * Each element of the tensor [other] is added to each element of this tensor. + * The resulting tensor is returned. + * + * @param other tensor to be added. + * @return the sum of this tensor and [other]. + */ public operator fun TensorStructure.plus(other: TensorStructure): TensorStructure + + /** + * Adds the scalar [value] to each element of this tensor. + * + * @param value the number to be added to each element of this tensor. + */ public operator fun TensorStructure.plusAssign(value: T): Unit + + /** + * Each element of the tensor [other] is added to each element of this tensor. + * + * @param other tensor to be added. + */ public operator fun TensorStructure.plusAssign(other: TensorStructure): Unit + + /** + * Each element of the tensor [other] is subtracted from this value. + * The resulting tensor is returned. + * + * @param other tensor to be subtracted. + * @return the difference between this value and tensor [other]. + */ public operator fun T.minus(other: TensorStructure): TensorStructure + + /** + * Subtracts the scalar [value] from each element of this tensor and returns a new resulting tensor. + * + * @param value the number to be subtracted from each element of this tensor. + * @return the difference between this tensor and [value]. + */ public operator fun TensorStructure.minus(value: T): TensorStructure + + /** + * Each element of the tensor [other] is subtracted from each element of this tensor. + * The resulting tensor is returned. + * + * @param other tensor to be subtracted. + * @return the difference between this tensor and [other]. + */ public operator fun TensorStructure.minus(other: TensorStructure): TensorStructure + + /** + * Subtracts the scalar [value] from each element of this tensor. + * + * @param value the number to be subtracted from each element of this tensor. + */ public operator fun TensorStructure.minusAssign(value: T): Unit + + /** + * Each element of the tensor [other] is subtracted from each element of this tensor. + * + * @param other tensor to be subtracted. + */ public operator fun TensorStructure.minusAssign(other: TensorStructure): Unit + + /** + * Each element of the tensor [other] is multiplied by this value. + * The resulting tensor is returned. + * + * @param other tensor to be multiplied. + * @return the product of this value and tensor [other]. + */ public operator fun T.times(other: TensorStructure): TensorStructure + + /** + * Multiplies the scalar [value] by each element of this tensor and returns a new resulting tensor. + * + * @param value the number to be multiplied by each element of this tensor. + * @return the product of this tensor and [value]. + */ public operator fun TensorStructure.times(value: T): TensorStructure + + /** + * Each element of the tensor [other] is multiplied by each element of this tensor. + * The resulting tensor is returned. + * + * @param other tensor to be multiplied. + * @return the product of this tensor and [other]. + */ public operator fun TensorStructure.times(other: TensorStructure): TensorStructure + + /** + * Multiplies the scalar [value] by each element of this tensor. + * + * @param value the number to be multiplied by each element of this tensor. + */ public operator fun TensorStructure.timesAssign(value: T): Unit + + /** + * Each element of the tensor [other] is multiplied by each element of this tensor. + * + * @param other tensor to be multiplied. + */ public operator fun TensorStructure.timesAssign(other: TensorStructure): Unit + + /** + * Numerical negative, element-wise. + * + * @return tensor - negation of the original tensor. + */ public operator fun TensorStructure.unaryMinus(): TensorStructure - //https://pytorch.org/cppdocs/notes/tensor_indexing.html + /** + * Returns the tensor at index i + * For more information: https://pytorch.org/cppdocs/notes/tensor_indexing.html + * + * @param i index of the extractable tensor + * @return subtensor of the original tensor with index [i] + */ public operator fun TensorStructure.get(i: Int): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.transpose.html + /** + * Returns a tensor that is a transposed version of this tensor. The given dimensions [i] and [j] are swapped. + * For more information: https://pytorch.org/docs/stable/generated/torch.transpose.html + * + * @param i the first dimension to be transposed + * @param j the second dimension to be transposed + * @return transposed tensor + */ public fun TensorStructure.transpose(i: Int = -2, j: Int = -1): TensorStructure - //https://pytorch.org/docs/stable/tensor_view.html + /** + * Returns a new tensor with the same data as the self tensor but of a different shape. + * The returned tensor shares the same data and must have the same number of elements, but may have a different size + * For more information: https://pytorch.org/docs/stable/tensor_view.html + * + * @param shape the desired size + * @return tensor with new shape + */ public fun TensorStructure.view(shape: IntArray): TensorStructure + + /** + * View this tensor as the same size as [other]. + * ``this.viewAs(other) is equivalent to this.view(other.shape)``. + * For more information: https://pytorch.org/cppdocs/notes/tensor_indexing.html + * + * @param other the result tensor has the same size as other. + * @return the result tensor with the same size as other. + */ public fun TensorStructure.viewAs(other: TensorStructure): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.matmul.html + /** + * Matrix product of two tensors. + * + * The behavior depends on the dimensionality of the tensors as follows: + * 1. If both tensors are 1-dimensional, the dot product (scalar) is returned. + * + * 2. If both arguments are 2-dimensional, the matrix-matrix product is returned. + * + * 3. If the first argument is 1-dimensional and the second argument is 2-dimensional, + * a 1 is prepended to its dimension for the purpose of the matrix multiply. + * After the matrix multiply, the prepended dimension is removed. + * + * 4. If the first argument is 2-dimensional and the second argument is 1-dimensional, + * the matrix-vector product is returned. + * + * 5. If both arguments are at least 1-dimensional and at least one argument is N-dimensional (where N > 2), + * then a batched matrix multiply is returned. If the first argument is 1-dimensional, + * a 1 is prepended to its dimension for the purpose of the batched matrix multiply and removed after. + * If the second argument is 1-dimensional, a 1 is appended to its dimension for the purpose of the batched matrix + * multiple and removed after. + * The non-matrix (i.e. batch) dimensions are broadcasted (and thus must be broadcastable). + * For example, if `input` is a (j \times 1 \times n \times n) tensor and `other` is a + * (k \times n \times n) tensor, out will be a (j \times k \times n \times n) tensor. + * + * For more information: https://pytorch.org/docs/stable/generated/torch.matmul.html + * + * @param other tensor to be multiplied + * @return mathematical product of two tensors + */ public infix fun TensorStructure.dot(other: TensorStructure): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.diag_embed.html + /** + * Creates a tensor whose diagonals of certain 2D planes (specified by [dim1] and [dim2]) + * are filled by [diagonalEntries]. + * To facilitate creating batched diagonal matrices, + * the 2D planes formed by the last two dimensions of the returned tensor are chosen by default. + * + * The argument [offset] controls which diagonal to consider: + * 1. If [offset] = 0, it is the main diagonal. + * 2. If [offset] > 0, it is above the main diagonal. + * 3. If [offset] < 0, it is below the main diagonal. + * + * The size of the new matrix will be calculated + * to make the specified diagonal of the size of the last input dimension. + * For more information: https://pytorch.org/docs/stable/generated/torch.diag_embed.html + * + * @param diagonalEntries - the input tensor. Must be at least 1-dimensional. + * @param offset - which diagonal to consider. Default: 0 (main diagonal). + * @param dim1 - first dimension with respect to which to take diagonal. Default: -2. + * @param dim2 - second dimension with respect to which to take diagonal. Default: -1. + * + * @return tensor whose diagonals of certain 2D planes (specified by [dim1] and [dim2]) + * are filled by [diagonalEntries] + */ public fun diagonalEmbedding( diagonalEntries: TensorStructure, offset: Int = 0, diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt index 1b00197ff..a49d9ab29 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt @@ -10,6 +10,10 @@ import space.kscience.kmath.tensors.core.* import space.kscience.kmath.tensors.core.broadcastTensors import space.kscience.kmath.tensors.core.broadcastTo +/** + * Basic linear algebra operations implemented with broadcasting. + * For more information: https://pytorch.org/docs/stable/notes/broadcasting.html + */ public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun TensorStructure.plus(other: TensorStructure): DoubleTensor { From 64c6cbf8603a267f7a85af65f16d567c448eeb0a Mon Sep 17 00:00:00 2001 From: AlyaNovikova Date: Thu, 29 Apr 2021 17:21:29 +0300 Subject: [PATCH 125/178] change tuple to pair/triple --- .../kmath/tensors/api/LinearOpsTensorAlgebra.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt index 6735efacb..aa10ae49b 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -49,13 +49,13 @@ public interface LinearOpsTensorAlgebra : /** * QR decomposition. * - * Computes the QR decomposition of a matrix or a batch of matrices, and returns a namedtuple `(Q, R)` of tensors. + * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `(Q, R)` of tensors. * Given a tensor `input`, return tensors (Q, R) satisfying ``input = Q * R``, * with `Q` being an orthogonal matrix or batch of orthogonal matrices * and `R` being an upper triangular matrix or batch of upper triangular matrices. * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.qr * - * @return tuple of Q and R tensors. + * @return pair of Q and R tensors. */ public fun TensorStructure.qr(): Pair, TensorStructure> @@ -82,7 +82,7 @@ public interface LinearOpsTensorAlgebra : * Singular Value Decomposition. * * Computes the singular value decomposition of either a matrix or batch of matrices `input`. - * The singular value decomposition is represented as a namedtuple `(U, S, V)`, + * The singular value decomposition is represented as a triple `(U, S, V)`, * such that ``input = U.dot(diagonalEmbedding(S).dot(V.T))``. * If input is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as input. * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd @@ -93,10 +93,10 @@ public interface LinearOpsTensorAlgebra : /** * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, - * represented by a namedtuple (eigenvalues, eigenvectors). + * represented by a pair (eigenvalues, eigenvectors). * For more information: https://pytorch.org/docs/stable/generated/torch.symeig.html * - * @return a namedtuple (eigenvalues, eigenvectors) + * @return a pair (eigenvalues, eigenvectors) */ public fun TensorStructure.symEig(): Pair, TensorStructure> From b9f1f0e5259b771727a4cdbdfbefc5d5047cf08e Mon Sep 17 00:00:00 2001 From: AlyaNovikova Date: Thu, 29 Apr 2021 20:00:05 +0300 Subject: [PATCH 126/178] fixes --- .../kmath/tensors/api/TensorAlgebra.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 92aafb8ea..62d4a1b89 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -145,7 +145,7 @@ public interface TensorAlgebra { /** * Numerical negative, element-wise. * - * @return tensor - negation of the original tensor. + * @return tensor negation of the original tensor. */ public operator fun TensorStructure.unaryMinus(): TensorStructure @@ -209,8 +209,8 @@ public interface TensorAlgebra { * If the second argument is 1-dimensional, a 1 is appended to its dimension for the purpose of the batched matrix * multiple and removed after. * The non-matrix (i.e. batch) dimensions are broadcasted (and thus must be broadcastable). - * For example, if `input` is a (j \times 1 \times n \times n) tensor and `other` is a - * (k \times n \times n) tensor, out will be a (j \times k \times n \times n) tensor. + * For example, if `input` is a (j × 1 × n × n) tensor and `other` is a + * (k × n × n) tensor, out will be a (j × k × n × n) tensor. * * For more information: https://pytorch.org/docs/stable/generated/torch.matmul.html * @@ -227,17 +227,17 @@ public interface TensorAlgebra { * * The argument [offset] controls which diagonal to consider: * 1. If [offset] = 0, it is the main diagonal. - * 2. If [offset] > 0, it is above the main diagonal. - * 3. If [offset] < 0, it is below the main diagonal. + * 1. If [offset] > 0, it is above the main diagonal. + * 1. If [offset] < 0, it is below the main diagonal. * * The size of the new matrix will be calculated * to make the specified diagonal of the size of the last input dimension. * For more information: https://pytorch.org/docs/stable/generated/torch.diag_embed.html * - * @param diagonalEntries - the input tensor. Must be at least 1-dimensional. - * @param offset - which diagonal to consider. Default: 0 (main diagonal). - * @param dim1 - first dimension with respect to which to take diagonal. Default: -2. - * @param dim2 - second dimension with respect to which to take diagonal. Default: -1. + * @param diagonalEntries the input tensor. Must be at least 1-dimensional. + * @param offset which diagonal to consider. Default: 0 (main diagonal). + * @param dim1 first dimension with respect to which to take diagonal. Default: -2. + * @param dim2 second dimension with respect to which to take diagonal. Default: -1. * * @return tensor whose diagonals of certain 2D planes (specified by [dim1] and [dim2]) * are filled by [diagonalEntries] From 432f404d7c00c4d090f5496ae8ffb5e69d9330d8 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Thu, 29 Apr 2021 18:45:46 +0100 Subject: [PATCH 127/178] More descriptions --- kmath-tensors/README.md | 13 +++--- .../tensors/api/AnalyticTensorAlgebra.kt | 38 +++++++++-------- .../tensors/api/LinearOpsTensorAlgebra.kt | 2 +- .../kmath/tensors/api/TensorAlgebra.kt | 2 +- .../api/TensorPartialDivisionAlgebra.kt | 42 ++++++++++++++++++- 5 files changed, 72 insertions(+), 25 deletions(-) diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index 3b82829f0..24d46cd16 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -1,12 +1,15 @@ # Module kmath-tensors -Common linear algebra operations on tensors. - - - [tensor algebra](src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt) : Basic linear algebra operations on tensors (plus, dot, etc.) - - [tensor algebra with broadcasting](src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt) : Basic linear algebra operations implemented with broadcasting. - - [linear algebra operations](src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt) : Advanced linear algebra operations like LU decomposition, SVD, etc. +Common operations on tensors, the API consists of: + - [TensorAlgebra](src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt) : Basic algebra operations on tensors (plus, dot, etc.) + - [TensorPartialDivisionAlgebra](src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt) : Emulates an algebra over a field + - [LinearOpsTensorAlgebra](src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt) : Linear algebra operations including LU, QR, Cholesky LL and SVD decompositions + - [AnalyticTensorAlgebra](src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt) : Element-wise analytic operations +The library offers a multiplatform implementation for this interface over the `Double`'s. As the highlight, the user can find: + - [BroadcastDoubleTensorAlgebra](src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt) : Basic algebra operations implemented with broadcasting. + - [DoubleLinearOpsTensorAlgebra](src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt) : Includes the power method for SVD and the spectrum of symmetric matrices. ## Artifact: The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-7`. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt index 315f39027..5c92c56c4 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt @@ -5,59 +5,63 @@ package space.kscience.kmath.tensors.api - +/** + * Element-wise analytic operations on [TensorStructure]. + * + * @param T the type of items closed under analytic functions in the tensors. + */ public interface AnalyticTensorAlgebra : TensorPartialDivisionAlgebra { - //https://pytorch.org/docs/stable/generated/torch.exp.html + //For information: https://pytorch.org/docs/stable/generated/torch.exp.html public fun TensorStructure.exp(): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.log.html + //For information: https://pytorch.org/docs/stable/generated/torch.log.html public fun TensorStructure.log(): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.sqrt.html + //For information: https://pytorch.org/docs/stable/generated/torch.sqrt.html public fun TensorStructure.sqrt(): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.acos.html#torch.cos + //For information: https://pytorch.org/docs/stable/generated/torch.acos.html#torch.cos public fun TensorStructure.cos(): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.acos.html#torch.acos + //For information: https://pytorch.org/docs/stable/generated/torch.acos.html#torch.acos public fun TensorStructure.acos(): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.cosh + //For information: https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.cosh public fun TensorStructure.cosh(): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.acosh + //For information: https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.acosh public fun TensorStructure.acosh(): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sin + //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sin public fun TensorStructure.sin(): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asin + //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asin public fun TensorStructure.asin(): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sinh + //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sinh public fun TensorStructure.sinh(): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asinh + //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asinh public fun TensorStructure.asinh(): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.atan.html#torch.tan + //For information: https://pytorch.org/docs/stable/generated/torch.atan.html#torch.tan public fun TensorStructure.tan(): TensorStructure //https://pytorch.org/docs/stable/generated/torch.atan.html#torch.atan public fun TensorStructure.atan(): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.tanh + //For information: https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.tanh public fun TensorStructure.tanh(): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.atanh + //For information: https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.atanh public fun TensorStructure.atanh(): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.ceil.html#torch.ceil + //For information: https://pytorch.org/docs/stable/generated/torch.ceil.html#torch.ceil public fun TensorStructure.ceil(): TensorStructure - //https://pytorch.org/docs/stable/generated/torch.floor.html#torch.floor + //For information: https://pytorch.org/docs/stable/generated/torch.floor.html#torch.floor public fun TensorStructure.floor(): TensorStructure } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt index aa10ae49b..7a19c5d5a 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -8,7 +8,7 @@ package space.kscience.kmath.tensors.api /** * Common linear algebra operations. Operates on [TensorStructure]. * - * @param T the type of items in the tensors. + * @param T the type of items closed under division in the tensors. */ public interface LinearOpsTensorAlgebra : TensorPartialDivisionAlgebra { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 62d4a1b89..338064231 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.tensors.api /** - * Basic linear algebra operations on [TensorStructure]. + * Algebra over a ring on [TensorStructure]. * For more information: https://proofwiki.org/wiki/Definition:Algebra_over_Ring * * @param T the type of items in the tensors. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt index 4dab3dd07..eccc6fa0d 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt @@ -5,12 +5,52 @@ package space.kscience.kmath.tensors.api -// https://proofwiki.org/wiki/Definition:Division_Algebra +/** + * Algebra over a field with partial division on [TensorStructure]. + * For more information: https://proofwiki.org/wiki/Definition:Division_Algebra + * + * @param T the type of items closed under division in the tensors. + */ public interface TensorPartialDivisionAlgebra : TensorAlgebra { + + /** + * Each element of the tensor [other] is divided by this value. + * The resulting tensor is returned. + * + * @param other tensor to divide by. + * @return the division of this value by the tensor [other]. + */ public operator fun T.div(other: TensorStructure): TensorStructure + + /** + * Divide by the scalar [value] each element of this tensor returns a new resulting tensor. + * + * @param value the number to divide by each element of this tensor. + * @return the division of this tensor by the [value]. + */ public operator fun TensorStructure.div(value: T): TensorStructure + + /** + * Each element of the tensor [other] is divided by each element of this tensor. + * The resulting tensor is returned. + * + * @param other tensor to be divided by. + * @return the division of this tensor by [other]. + */ public operator fun TensorStructure.div(other: TensorStructure): TensorStructure + + /** + * Divides by the scalar [value] each element of this tensor. + * + * @param value the number to divide by each element of this tensor. + */ public operator fun TensorStructure.divAssign(value: T) + + /** + * Each element of this tensor is divided by each element of the [other] tensor. + * + * @param other tensor to be divide by. + */ public operator fun TensorStructure.divAssign(other: TensorStructure) } From cba62a9468c84bb476dbf905bd44c4df90d9b735 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Thu, 29 Apr 2021 18:48:41 +0100 Subject: [PATCH 128/178] English typo --- kmath-tensors/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index 24d46cd16..a81b7277c 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -7,9 +7,9 @@ Common operations on tensors, the API consists of: - [LinearOpsTensorAlgebra](src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt) : Linear algebra operations including LU, QR, Cholesky LL and SVD decompositions - [AnalyticTensorAlgebra](src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt) : Element-wise analytic operations -The library offers a multiplatform implementation for this interface over the `Double`'s. As the highlight, the user can find: +The library offers a multiplatform implementation for this interface over the `Double`'s. As a highlight, the user can find: - [BroadcastDoubleTensorAlgebra](src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt) : Basic algebra operations implemented with broadcasting. - - [DoubleLinearOpsTensorAlgebra](src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt) : Includes the power method for SVD and the spectrum of symmetric matrices. + - [DoubleLinearOpsTensorAlgebra](src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt) : Contains the power method for SVD and the spectrum of symmetric matrices. ## Artifact: The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-7`. From 09f0a2879e50c364ee969930576af8e453e32748 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Fri, 30 Apr 2021 11:08:22 +0300 Subject: [PATCH 129/178] refactor lu + docs --- .../tensors/LinearSystemSolvingWithLUP.kt | 3 +-- .../tensors/api/LinearOpsTensorAlgebra.kt | 22 +++++++------------ .../algebras/DoubleLinearOpsTensorAlgebra.kt | 17 ++++++++++---- .../core/TestDoubleLinearOpsAlgebra.kt | 4 +--- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt index 526b6781f..38d8c1437 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt @@ -42,8 +42,7 @@ fun main () { // solve `Ax = b` system using LUP decomposition // get P, L, U such that PA = LU - val (lu, pivots) = a.lu() - val (p, l, u) = luPivot(lu, pivots) + val (p, l, u) = a.lu() // check that P is permutation matrix println("P:\n$p") diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt index 7a19c5d5a..bcbb52a1b 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -60,23 +60,17 @@ public interface LinearOpsTensorAlgebra : public fun TensorStructure.qr(): Pair, TensorStructure> /** - * TODO('Andrew') - * For more information: https://pytorch.org/docs/stable/generated/torch.lu.html + * LUP decomposition * - * @return ... - */ - public fun TensorStructure.lu(): Pair, TensorStructure> - - /** - * TODO('Andrew') - * For more information: https://pytorch.org/docs/stable/generated/torch.lu_unpack.html + * Computes the LUP decomposition of a matrix or a batch of matrices. + * Given a tensor `input`, return tensors (P, L, U) satisfying ``P * input = L * U``, + * with `P` being a permutation matrix or batch of matrices, + * `L` being a lower triangular matrix or batch of matrices, + * `U` being an upper triangular matrix or batch of matrices. * - * @param luTensor ... - * @param pivotsTensor ... - * @return ... + * * @return triple of P, L and U tensors */ - public fun luPivot(luTensor: TensorStructure, pivotsTensor: TensorStructure): - Triple, TensorStructure, TensorStructure> + public fun TensorStructure.lu(): Triple, TensorStructure, TensorStructure> /** * Singular Value Decomposition. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt index 62629f3db..97eed289a 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt @@ -29,13 +29,13 @@ public class DoubleLinearOpsTensorAlgebra : override fun TensorStructure.det(): DoubleTensor = detLU(1e-9) - public fun TensorStructure.lu(epsilon: Double): Pair = + public fun TensorStructure.luFactor(epsilon: Double): Pair = computeLU(tensor, epsilon) ?: throw RuntimeException("Tensor contains matrices which are singular at precision $epsilon") - override fun TensorStructure.lu(): Pair = lu(1e-9) + public fun TensorStructure.luFactor(): Pair = luFactor(1e-9) - override fun luPivot( + public fun luPivot( luTensor: TensorStructure, pivotsTensor: TensorStructure ): Triple { @@ -156,7 +156,7 @@ public class DoubleLinearOpsTensorAlgebra : } public fun TensorStructure.invLU(epsilon: Double = 1e-9): DoubleTensor { - val (luTensor, pivotsTensor) = lu(epsilon) + val (luTensor, pivotsTensor) = luFactor(epsilon) val invTensor = luTensor.zeroesLike() val seq = luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).zip(invTensor.matrixSequence()) @@ -167,6 +167,15 @@ public class DoubleLinearOpsTensorAlgebra : return invTensor } + + public fun TensorStructure.lu(epsilon: Double = 1e-9): Triple { + val (lu, pivots) = this.luFactor(epsilon) + return luPivot(lu, pivots) + } + + override fun TensorStructure.lu(): Triple = lu(1e-9) + + } public inline fun DoubleLinearOpsTensorAlgebra(block: DoubleLinearOpsTensorAlgebra.() -> R): R = diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 6120f0e4a..1f7e955d4 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -124,9 +124,7 @@ class TestDoubleLinearOpsTensorAlgebra { ) val tensor = fromArray(shape, buffer) - val (lu, pivots) = tensor.lu() - - val (p, l, u) = luPivot(lu, pivots) + val (p, l, u) = tensor.lu() assertTrue { p.shape contentEquals shape } assertTrue { l.shape contentEquals shape } From b546f3f78bf019c65b6bf4e1dda7cf521da46884 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 30 Apr 2021 09:19:30 +0100 Subject: [PATCH 130/178] Merge PR --- .../kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt index 97eed289a..03f383728 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt @@ -116,7 +116,7 @@ public class DoubleLinearOpsTensorAlgebra : override fun TensorStructure.symEig(): Pair = symEig(epsilon = 1e-15) - //http://hua-zhou.github.io/teaching/biostatm280-2017spring/slides/16-eigsvd/eigsvd.html + //For information: http://hua-zhou.github.io/teaching/biostatm280-2017spring/slides/16-eigsvd/eigsvd.html public fun TensorStructure.symEig(epsilon: Double): Pair { checkSymmetric(tensor, epsilon) val (u, s, v) = tensor.svd(epsilon) From bd068b2c1438e912a1a0b96bab72ffe55478374e Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 30 Apr 2021 09:54:25 +0100 Subject: [PATCH 131/178] Smaller SVD test --- .../kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 1f7e955d4..b2ef6b4c4 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -163,7 +163,7 @@ class TestDoubleLinearOpsTensorAlgebra { @Test fun testBatchedSVD() = DoubleLinearOpsTensorAlgebra { - val tensor = randNormal(intArrayOf(1, 15, 4, 7, 5, 3), 0) + val tensor = randNormal(intArrayOf(2, 5, 3), 0) val (tensorU, tensorS, tensorV) = tensor.svd() val tensorSVD = tensorU dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) assertTrue(tensor.eq(tensorSVD)) @@ -171,7 +171,7 @@ class TestDoubleLinearOpsTensorAlgebra { @Test fun testBatchedSymEig() = DoubleLinearOpsTensorAlgebra { - val tensor = randNormal(shape = intArrayOf(5, 3, 3), 0) + val tensor = randNormal(shape = intArrayOf(2, 3, 3), 0) val tensorSigma = tensor + tensor.transpose() val (tensorS, tensorV) = tensorSigma.symEig() val tensorSigmaCalc = tensorV dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) From e5e62bc544143ef4f341257c7d143a5b8a813656 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 30 Apr 2021 14:38:03 +0100 Subject: [PATCH 132/178] Extending from Algebra --- .../kmath/tensors/api/TensorAlgebra.kt | 4 ++- .../algebras/BroadcastDoubleTensorAlgebra.kt | 3 +- .../algebras/DoubleAnalyticTensorAlgebra.kt | 10 ++----- .../algebras/DoubleLinearOpsTensorAlgebra.kt | 12 +++----- .../core/algebras/DoubleTensorAlgebra.kt | 5 +--- .../kmath/tensors/core/broadcastUtils.kt | 4 --- .../kscience/kmath/tensors/core/linUtils.kt | 3 +- .../kmath/tensors/core/TestBroadcasting.kt | 16 ++++++----- .../core/TestDoubleAnalyticTensorAlgebra.kt | 5 ++-- .../core/TestDoubleLinearOpsAlgebra.kt | 28 +++++++++---------- .../kmath/tensors/core/TestDoubleTensor.kt | 9 +++--- .../tensors/core/TestDoubleTensorAlgebra.kt | 21 +++++++------- 12 files changed, 56 insertions(+), 64 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 338064231..96d6985d8 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -5,13 +5,15 @@ package space.kscience.kmath.tensors.api +import space.kscience.kmath.operations.Algebra + /** * Algebra over a ring on [TensorStructure]. * For more information: https://proofwiki.org/wiki/Definition:Algebra_over_Ring * * @param T the type of items in the tensors. */ -public interface TensorAlgebra { +public interface TensorAlgebra: Algebra> { /** * Returns a single tensor value of unit dimension. The tensor shape must be equal to [1]. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt index a49d9ab29..fa64092d6 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt @@ -14,7 +14,7 @@ import space.kscience.kmath.tensors.core.broadcastTo * Basic linear algebra operations implemented with broadcasting. * For more information: https://pytorch.org/docs/stable/notes/broadcasting.html */ -public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { +public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun TensorStructure.plus(other: TensorStructure): DoubleTensor { val broadcast = broadcastTensors(tensor, other.tensor) @@ -89,5 +89,4 @@ public class BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { newOther.buffer.array()[tensor.bufferStart + i] } } - } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt index 7d1cceb15..4a942df84 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt @@ -11,10 +11,9 @@ import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.tensor import kotlin.math.* -public class DoubleAnalyticTensorAlgebra: +public object DoubleAnalyticTensorAlgebra : AnalyticTensorAlgebra, - DoubleTensorAlgebra() -{ + DoubleTensorAlgebra() { override fun TensorStructure.exp(): DoubleTensor = tensor.map(::exp) override fun TensorStructure.log(): DoubleTensor = tensor.map(::ln) @@ -49,7 +48,4 @@ public class DoubleAnalyticTensorAlgebra: override fun TensorStructure.floor(): DoubleTensor = tensor.map(::floor) -} - -public inline fun DoubleAnalyticTensorAlgebra(block: DoubleAnalyticTensorAlgebra.() -> R): R = - DoubleAnalyticTensorAlgebra().block() \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt index 03f383728..975755656 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt @@ -21,7 +21,7 @@ import space.kscience.kmath.tensors.core.pivInit import kotlin.math.min -public class DoubleLinearOpsTensorAlgebra : +public object DoubleLinearOpsTensorAlgebra : LinearOpsTensorAlgebra, DoubleTensorAlgebra() { @@ -30,8 +30,8 @@ public class DoubleLinearOpsTensorAlgebra : override fun TensorStructure.det(): DoubleTensor = detLU(1e-9) public fun TensorStructure.luFactor(epsilon: Double): Pair = - computeLU(tensor, epsilon) ?: - throw RuntimeException("Tensor contains matrices which are singular at precision $epsilon") + computeLU(tensor, epsilon) + ?: throw RuntimeException("Tensor contains matrices which are singular at precision $epsilon") public fun TensorStructure.luFactor(): Pair = luFactor(1e-9) @@ -175,8 +175,4 @@ public class DoubleLinearOpsTensorAlgebra : override fun TensorStructure.lu(): Triple = lu(1e-9) - -} - -public inline fun DoubleLinearOpsTensorAlgebra(block: DoubleLinearOpsTensorAlgebra.() -> R): R = - DoubleLinearOpsTensorAlgebra().block() \ No newline at end of file +} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index 7414a4469..8729358cc 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -23,6 +23,7 @@ import kotlin.math.abs public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { + public companion object : DoubleTensorAlgebra() override fun TensorStructure.value(): Double { check(tensor.shape contentEquals intArrayOf(1)) { @@ -395,7 +396,3 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed)) } - - -public inline fun DoubleTensorAlgebra(block: DoubleTensorAlgebra.() -> R): R = - DoubleTensorAlgebra().block() diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt index 4378e9ac9..71ccbf97b 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt @@ -1,11 +1,7 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra import kotlin.math.max -public inline fun BroadcastDoubleTensorAlgebra(block: BroadcastDoubleTensorAlgebra.() -> R): R = - BroadcastDoubleTensorAlgebra().block() - internal inline fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTensor, linearSize: Int) { for (linearIndex in 0 until linearSize) { val totalMultiIndex = resTensor.linearStructure.index(linearIndex) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt index 3a130c71e..c7a730018 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt @@ -4,6 +4,7 @@ import space.kscience.kmath.nd.MutableStructure1D import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D +import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra import kotlin.math.abs @@ -251,7 +252,7 @@ internal inline fun DoubleLinearOpsTensorAlgebra.qrHelper( } } } - r[j, j] = DoubleAnalyticTensorAlgebra { (v dot v).sqrt().value() } + r[j, j] = DoubleAnalyticTensorAlgebra.invoke { (v dot v).sqrt().value() } for (i in 0 until n) { qM[i, j] = vv[i] / r[j, j] } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt index d677f6966..207dd1c98 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt @@ -1,13 +1,15 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import kotlin.test.Test import kotlin.test.assertTrue -class TestBroadcasting { +internal class TestBroadcasting { @Test - fun broadcastShapes() = DoubleTensorAlgebra { + fun broadcastShapes() = DoubleTensorAlgebra.invoke { assertTrue( broadcastShapes( intArrayOf(2, 3), intArrayOf(1, 3), intArrayOf(1, 1, 1) @@ -22,7 +24,7 @@ class TestBroadcasting { } @Test - fun broadcastTo() = DoubleTensorAlgebra { + fun broadcastTo() = DoubleTensorAlgebra.invoke { 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)) @@ -32,7 +34,7 @@ class TestBroadcasting { } @Test - fun broadcastTensors() = DoubleTensorAlgebra { + fun broadcastTensors() = DoubleTensorAlgebra.invoke { 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 tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) @@ -49,7 +51,7 @@ class TestBroadcasting { } @Test - fun broadcastOuterTensors() = DoubleTensorAlgebra { + fun broadcastOuterTensors() = DoubleTensorAlgebra.invoke { 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 tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) @@ -66,7 +68,7 @@ class TestBroadcasting { } @Test - fun broadcastOuterTensorsShapes() = DoubleTensorAlgebra { + fun broadcastOuterTensorsShapes() = DoubleTensorAlgebra.invoke { 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 tensor3 = fromArray(intArrayOf(1, 1), doubleArrayOf(500.0)) @@ -79,7 +81,7 @@ class TestBroadcasting { } @Test - fun minusTensor() = BroadcastDoubleTensorAlgebra { + fun minusTensor() = BroadcastDoubleTensorAlgebra.invoke { 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 tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt index 060bc1607..3b3e22acc 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt @@ -1,12 +1,13 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra import kotlin.math.abs import kotlin.math.exp import kotlin.test.Test import kotlin.test.assertTrue -class TestDoubleAnalyticTensorAlgebra { +internal class TestDoubleAnalyticTensorAlgebra { val shape = intArrayOf(2, 1, 3, 2) val buffer = doubleArrayOf(27.1, 20.0, 19.84, 23.123, 0.0, 1.0, 3.23, 133.7, 25.3, 100.3, 11.0, 12.012) @@ -26,7 +27,7 @@ class TestDoubleAnalyticTensorAlgebra { } @Test - fun testExp() = DoubleAnalyticTensorAlgebra { + fun testExp() = DoubleAnalyticTensorAlgebra.invoke { tensor.exp().let { assertTrue { shape contentEquals it.shape } assertTrue { buffer.fmap(::exp).epsEqual(it.buffer.array())} diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index b2ef6b4c4..aa68340d4 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -1,15 +1,16 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra import kotlin.math.abs import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue -class TestDoubleLinearOpsTensorAlgebra { +internal class TestDoubleLinearOpsTensorAlgebra { @Test - fun testDetLU() = DoubleLinearOpsTensorAlgebra { + fun testDetLU() = DoubleLinearOpsTensorAlgebra.invoke { val tensor = fromArray( intArrayOf(2, 2, 2), doubleArrayOf( @@ -34,7 +35,7 @@ class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testDet() = DoubleLinearOpsTensorAlgebra { + fun testDet() = DoubleLinearOpsTensorAlgebra.invoke { val expectedValue = 0.019827417 val m = fromArray( intArrayOf(3, 3), doubleArrayOf( @@ -48,7 +49,7 @@ class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testDetSingle() = DoubleLinearOpsTensorAlgebra { + fun testDetSingle() = DoubleLinearOpsTensorAlgebra.invoke { val expectedValue = 48.151623 val m = fromArray( intArrayOf(1, 1), doubleArrayOf( @@ -60,7 +61,7 @@ class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testInvLU() = DoubleLinearOpsTensorAlgebra { + fun testInvLU() = DoubleLinearOpsTensorAlgebra.invoke { val tensor = fromArray( intArrayOf(2, 2, 2), doubleArrayOf( @@ -85,14 +86,14 @@ class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testScalarProduct() = DoubleLinearOpsTensorAlgebra { + fun testScalarProduct() = DoubleLinearOpsTensorAlgebra.invoke { val a = fromArray(intArrayOf(3), doubleArrayOf(1.8, 2.5, 6.8)) val b = fromArray(intArrayOf(3), doubleArrayOf(5.5, 2.6, 6.4)) assertEquals(a.dot(b).value(), 59.92) } @Test - fun testQR() = DoubleLinearOpsTensorAlgebra { + fun testQR() = DoubleLinearOpsTensorAlgebra.invoke { val shape = intArrayOf(2, 2, 2) val buffer = doubleArrayOf( 1.0, 3.0, @@ -110,11 +111,10 @@ class TestDoubleLinearOpsTensorAlgebra { assertTrue((q dot r).eq(tensor)) - //todo check orthogonality/upper triang. } @Test - fun testLU() = DoubleLinearOpsTensorAlgebra { + fun testLU() = DoubleLinearOpsTensorAlgebra.invoke { val shape = intArrayOf(2, 2, 2) val buffer = doubleArrayOf( 1.0, 3.0, @@ -134,7 +134,7 @@ class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testCholesky() = DoubleLinearOpsTensorAlgebra { + fun testCholesky() = DoubleLinearOpsTensorAlgebra.invoke { val tensor = randNormal(intArrayOf(2, 5, 5), 0) val sigma = (tensor dot tensor.transpose()) + diagonalEmbedding( fromArray(intArrayOf(2, 5), DoubleArray(10) { 0.1 }) @@ -145,7 +145,7 @@ class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testSVD1D() = DoubleLinearOpsTensorAlgebra { + fun testSVD1D() = DoubleLinearOpsTensorAlgebra.invoke { val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val res = svd1d(tensor2) @@ -156,13 +156,13 @@ class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testSVD() = DoubleLinearOpsTensorAlgebra { + fun testSVD() = DoubleLinearOpsTensorAlgebra.invoke{ 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))) } @Test - fun testBatchedSVD() = DoubleLinearOpsTensorAlgebra { + fun testBatchedSVD() = DoubleLinearOpsTensorAlgebra.invoke { val tensor = randNormal(intArrayOf(2, 5, 3), 0) val (tensorU, tensorS, tensorV) = tensor.svd() val tensorSVD = tensorU dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) @@ -170,7 +170,7 @@ class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testBatchedSymEig() = DoubleLinearOpsTensorAlgebra { + fun testBatchedSymEig() = DoubleLinearOpsTensorAlgebra.invoke { val tensor = randNormal(shape = intArrayOf(2, 3, 3), 0) val tensorSigma = tensor + tensor.transpose() val (tensorS, tensorV) = tensorSigma.symEig() diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index 7103eafaa..20acc0901 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -4,6 +4,7 @@ import space.kscience.kmath.nd.DefaultStrides import space.kscience.kmath.nd.MutableBufferND import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D +import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.asMutableBuffer import space.kscience.kmath.structures.toDoubleArray @@ -12,17 +13,17 @@ import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue -class TestDoubleTensor { +internal class TestDoubleTensor { @Test - fun valueTest() = DoubleTensorAlgebra { + fun valueTest() = DoubleTensorAlgebra.invoke { val value = 12.5 val tensor = fromArray(intArrayOf(1), doubleArrayOf(value)) assertEquals(tensor.value(), value) } @Test - fun stridesTest() = DoubleTensorAlgebra { + fun stridesTest() = DoubleTensorAlgebra.invoke { val tensor = fromArray(intArrayOf(2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4)) assertEquals(tensor[intArrayOf(0, 1)], 5.8) assertTrue( @@ -31,7 +32,7 @@ class TestDoubleTensor { } @Test - fun getTest() = DoubleTensorAlgebra { + fun getTest() = DoubleTensorAlgebra.invoke { val tensor = fromArray(intArrayOf(1, 2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4)) val matrix = tensor[0].as2D() assertEquals(matrix[0, 1], 5.8) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index 1333a7a1f..115016974 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -1,29 +1,30 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import kotlin.test.Test import kotlin.test.assertFalse import kotlin.test.assertTrue -class TestDoubleTensorAlgebra { +internal class TestDoubleTensorAlgebra { @Test - fun doublePlus() = DoubleTensorAlgebra { + fun doublePlus() = DoubleTensorAlgebra.invoke { val tensor = fromArray(intArrayOf(2), doubleArrayOf(1.0, 2.0)) val res = 10.0 + tensor assertTrue(res.buffer.array() contentEquals doubleArrayOf(11.0, 12.0)) } @Test - fun doubleDiv() = DoubleTensorAlgebra { + fun doubleDiv() = DoubleTensorAlgebra.invoke { val tensor = fromArray(intArrayOf(2), doubleArrayOf(2.0, 4.0)) val res = 2.0/tensor assertTrue(res.buffer.array() contentEquals doubleArrayOf(1.0, 0.5)) } @Test - fun divDouble() = DoubleTensorAlgebra { + fun divDouble() = DoubleTensorAlgebra.invoke { val tensor = fromArray(intArrayOf(2), doubleArrayOf(10.0, 5.0)) val res = tensor / 2.5 assertTrue(res.buffer.array() contentEquals doubleArrayOf(4.0, 2.0)) @@ -39,7 +40,7 @@ class TestDoubleTensorAlgebra { } @Test - fun transpose3x2() = DoubleTensorAlgebra { + fun transpose3x2() = DoubleTensorAlgebra.invoke { 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) @@ -48,7 +49,7 @@ class TestDoubleTensorAlgebra { } @Test - fun transpose1x2x3() = DoubleTensorAlgebra { + fun transpose1x2x3() = DoubleTensorAlgebra.invoke { 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 res02 = tensor.transpose(-3, 2) @@ -64,7 +65,7 @@ class TestDoubleTensorAlgebra { } @Test - fun linearStructure() = DoubleTensorAlgebra { + fun linearStructure() = DoubleTensorAlgebra.invoke { val shape = intArrayOf(3) val tensorA = full(value = -4.5, shape = shape) val tensorB = full(value = 10.9, shape = shape) @@ -96,7 +97,7 @@ class TestDoubleTensorAlgebra { } @Test - fun dot() = DoubleTensorAlgebra { + fun dot() = DoubleTensorAlgebra.invoke { 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 tensor2 = fromArray(intArrayOf(3), doubleArrayOf(10.0, 20.0, 30.0)) @@ -132,7 +133,7 @@ class TestDoubleTensorAlgebra { } @Test - fun diagonalEmbedding() = DoubleTensorAlgebra { + fun diagonalEmbedding() = DoubleTensorAlgebra.invoke { 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 tensor3 = zeros(intArrayOf(2, 3, 4, 5)) @@ -165,7 +166,7 @@ class TestDoubleTensorAlgebra { } @Test - fun testEq() = DoubleTensorAlgebra { + fun testEq() = DoubleTensorAlgebra.invoke { 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 tensor3 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 5.0)) From 6be5caa93f4086e222677a55d15edaca707b16f0 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 30 Apr 2021 14:44:42 +0100 Subject: [PATCH 133/178] No secondary constructors --- .../kmath/tensors/core/BufferedTensor.kt | 25 +++---- .../algebras/BroadcastDoubleTensorAlgebra.kt | 28 ++++---- .../algebras/DoubleLinearOpsTensorAlgebra.kt | 2 +- .../core/algebras/DoubleTensorAlgebra.kt | 68 +++++++++---------- .../kmath/tensors/core/broadcastUtils.kt | 10 +-- .../kscience/kmath/tensors/core/linUtils.kt | 14 ++-- .../kmath/tensors/core/TestBroadcasting.kt | 20 +++--- .../core/TestDoubleAnalyticTensorAlgebra.kt | 2 +- .../core/TestDoubleLinearOpsAlgebra.kt | 4 +- .../kmath/tensors/core/TestDoubleTensor.kt | 5 +- .../tensors/core/TestDoubleTensorAlgebra.kt | 34 +++++----- 11 files changed, 103 insertions(+), 109 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 6e1cab11a..fae59804d 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -8,7 +8,7 @@ import space.kscience.kmath.tensors.core.algebras.TensorLinearStructure public open class BufferedTensor( override val shape: IntArray, - internal val buffer: MutableBuffer, + internal val mutableBuffer: MutableBuffer, internal val bufferStart: Int ) : TensorStructure { public val linearStructure: TensorLinearStructure @@ -17,10 +17,10 @@ public open class BufferedTensor( public val numElements: Int get() = linearStructure.size - override fun get(index: IntArray): T = buffer[bufferStart + linearStructure.offset(index)] + override fun get(index: IntArray): T = mutableBuffer[bufferStart + linearStructure.offset(index)] override fun set(index: IntArray, value: T) { - buffer[bufferStart + linearStructure.offset(index)] = value + mutableBuffer[bufferStart + linearStructure.offset(index)] = value } override fun elements(): Sequence> = linearStructure.indices().map { @@ -37,33 +37,28 @@ public class IntTensor internal constructor( shape: IntArray, buffer: IntArray, offset: Int = 0 -) : BufferedTensor(shape, IntBuffer(buffer), offset) { - internal constructor(bufferedTensor: BufferedTensor) : - this(bufferedTensor.shape, bufferedTensor.buffer.array(), bufferedTensor.bufferStart) -} +) : BufferedTensor(shape, IntBuffer(buffer), offset) public class DoubleTensor internal constructor( shape: IntArray, buffer: DoubleArray, offset: Int = 0 ) : BufferedTensor(shape, DoubleBuffer(buffer), offset) { - internal constructor(bufferedTensor: BufferedTensor) : - this(bufferedTensor.shape, bufferedTensor.buffer.array(), bufferedTensor.bufferStart) - override fun toString(): String = toPrettyString() - } -internal inline fun BufferedTensor.asTensor(): IntTensor = IntTensor(this) -internal inline fun BufferedTensor.asTensor(): DoubleTensor = DoubleTensor(this) +internal fun BufferedTensor.asTensor(): IntTensor = + IntTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) +internal fun BufferedTensor.asTensor(): DoubleTensor = + DoubleTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) -internal inline fun TensorStructure.copyToBufferedTensor(): BufferedTensor = +internal fun TensorStructure.copyToBufferedTensor(): BufferedTensor = BufferedTensor( this.shape, TensorLinearStructure(this.shape).indices().map(this::get).toMutableList().asMutableBuffer(), 0 ) -internal inline fun TensorStructure.toBufferedTensor(): BufferedTensor = when (this) { +internal fun TensorStructure.toBufferedTensor(): BufferedTensor = when (this) { is BufferedTensor -> this is MutableBufferND -> if (this.strides.strides.toIntArray() contentEquals TensorLinearStructure(this.shape).strides) BufferedTensor(this.shape, this.mutableBuffer, 0) else this.copyToBufferedTensor() diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt index fa64092d6..350d939af 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt @@ -21,7 +21,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> - newThis.buffer.array()[i] + newOther.buffer.array()[i] + newThis.mutableBuffer.array()[i] + newOther.mutableBuffer.array()[i] } return DoubleTensor(newThis.shape, resBuffer) } @@ -29,8 +29,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun TensorStructure.plusAssign(other: TensorStructure) { val newOther = broadcastTo(other.tensor, tensor.shape) for (i in 0 until tensor.linearStructure.size) { - tensor.buffer.array()[tensor.bufferStart + i] += - newOther.buffer.array()[tensor.bufferStart + i] + tensor.mutableBuffer.array()[tensor.bufferStart + i] += + newOther.mutableBuffer.array()[tensor.bufferStart + i] } } @@ -39,7 +39,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> - newThis.buffer.array()[i] - newOther.buffer.array()[i] + newThis.mutableBuffer.array()[i] - newOther.mutableBuffer.array()[i] } return DoubleTensor(newThis.shape, resBuffer) } @@ -47,8 +47,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun TensorStructure.minusAssign(other: TensorStructure) { val newOther = broadcastTo(other.tensor, tensor.shape) for (i in 0 until tensor.linearStructure.size) { - tensor.buffer.array()[tensor.bufferStart + i] -= - newOther.buffer.array()[tensor.bufferStart + i] + tensor.mutableBuffer.array()[tensor.bufferStart + i] -= + newOther.mutableBuffer.array()[tensor.bufferStart + i] } } @@ -57,8 +57,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> - newThis.buffer.array()[newThis.bufferStart + i] * - newOther.buffer.array()[newOther.bufferStart + i] + newThis.mutableBuffer.array()[newThis.bufferStart + i] * + newOther.mutableBuffer.array()[newOther.bufferStart + i] } return DoubleTensor(newThis.shape, resBuffer) } @@ -66,8 +66,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun TensorStructure.timesAssign(other: TensorStructure) { val newOther = broadcastTo(other.tensor, tensor.shape) for (i in 0 until tensor.linearStructure.size) { - tensor.buffer.array()[tensor.bufferStart + i] *= - newOther.buffer.array()[tensor.bufferStart + i] + tensor.mutableBuffer.array()[tensor.bufferStart + i] *= + newOther.mutableBuffer.array()[tensor.bufferStart + i] } } @@ -76,8 +76,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val newThis = broadcast[0] val newOther = broadcast[1] val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> - newThis.buffer.array()[newOther.bufferStart + i] / - newOther.buffer.array()[newOther.bufferStart + i] + newThis.mutableBuffer.array()[newOther.bufferStart + i] / + newOther.mutableBuffer.array()[newOther.bufferStart + i] } return DoubleTensor(newThis.shape, resBuffer) } @@ -85,8 +85,8 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun TensorStructure.divAssign(other: TensorStructure) { val newOther = broadcastTo(other.tensor, tensor.shape) for (i in 0 until tensor.linearStructure.size) { - tensor.buffer.array()[tensor.bufferStart + i] /= - newOther.buffer.array()[tensor.bufferStart + i] + tensor.mutableBuffer.array()[tensor.bufferStart + i] /= + newOther.mutableBuffer.array()[tensor.bufferStart + i] } } } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt index 975755656..ab73b25b1 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt @@ -106,7 +106,7 @@ public object DoubleLinearOpsTensorAlgebra : val matrixSize = matrix.shape.reduce { acc, i -> acc * i } val curMatrix = DoubleTensor( matrix.shape, - matrix.buffer.array().slice(matrix.bufferStart until matrix.bufferStart + matrixSize).toDoubleArray() + matrix.mutableBuffer.array().slice(matrix.bufferStart until matrix.bufferStart + matrixSize).toDoubleArray() ) svdHelper(curMatrix, USV, m, n, epsilon) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index 8729358cc..f428b9d2e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -29,7 +29,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { check(tensor.shape contentEquals intArrayOf(1)) { "Inconsistent value for tensor of shape ${shape.toList()}" } - return tensor.buffer.array()[tensor.bufferStart] + return tensor.mutableBuffer.array()[tensor.bufferStart] } public fun fromArray(shape: IntArray, buffer: DoubleArray): DoubleTensor { @@ -43,7 +43,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { val lastShape = tensor.shape.drop(1).toIntArray() val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) val newStart = newShape.reduce(Int::times) * i + tensor.bufferStart - return DoubleTensor(newShape, tensor.buffer.array(), newStart) + return DoubleTensor(newShape, tensor.mutableBuffer.array(), newStart) } public fun full(value: Double, shape: IntArray): DoubleTensor { @@ -77,12 +77,12 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { } public fun TensorStructure.copy(): DoubleTensor { - return DoubleTensor(tensor.shape, tensor.buffer.array().copyOf(), tensor.bufferStart) + return DoubleTensor(tensor.shape, tensor.mutableBuffer.array().copyOf(), tensor.bufferStart) } override fun Double.plus(other: TensorStructure): DoubleTensor { val resBuffer = DoubleArray(other.tensor.numElements) { i -> - other.tensor.buffer.array()[other.tensor.bufferStart + i] + this + other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] + this } return DoubleTensor(other.shape, resBuffer) } @@ -92,35 +92,35 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { override fun TensorStructure.plus(other: TensorStructure): DoubleTensor { checkShapesCompatible(tensor, other.tensor) val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.buffer.array()[i] + other.tensor.buffer.array()[i] + tensor.mutableBuffer.array()[i] + other.tensor.mutableBuffer.array()[i] } return DoubleTensor(tensor.shape, resBuffer) } override fun TensorStructure.plusAssign(value: Double) { for (i in 0 until tensor.numElements) { - tensor.buffer.array()[tensor.bufferStart + i] += value + tensor.mutableBuffer.array()[tensor.bufferStart + i] += value } } override fun TensorStructure.plusAssign(other: TensorStructure) { checkShapesCompatible(tensor, other.tensor) for (i in 0 until tensor.numElements) { - tensor.buffer.array()[tensor.bufferStart + i] += - other.tensor.buffer.array()[tensor.bufferStart + i] + tensor.mutableBuffer.array()[tensor.bufferStart + i] += + other.tensor.mutableBuffer.array()[tensor.bufferStart + i] } } override fun Double.minus(other: TensorStructure): DoubleTensor { val resBuffer = DoubleArray(other.tensor.numElements) { i -> - this - other.tensor.buffer.array()[other.tensor.bufferStart + i] + this - other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] } return DoubleTensor(other.shape, resBuffer) } override fun TensorStructure.minus(value: Double): DoubleTensor { val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.buffer.array()[tensor.bufferStart + i] - value + tensor.mutableBuffer.array()[tensor.bufferStart + i] - value } return DoubleTensor(tensor.shape, resBuffer) } @@ -128,28 +128,28 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { override fun TensorStructure.minus(other: TensorStructure): DoubleTensor { checkShapesCompatible(tensor, other) val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.buffer.array()[i] - other.tensor.buffer.array()[i] + tensor.mutableBuffer.array()[i] - other.tensor.mutableBuffer.array()[i] } return DoubleTensor(tensor.shape, resBuffer) } override fun TensorStructure.minusAssign(value: Double) { for (i in 0 until tensor.numElements) { - tensor.buffer.array()[tensor.bufferStart + i] -= value + tensor.mutableBuffer.array()[tensor.bufferStart + i] -= value } } override fun TensorStructure.minusAssign(other: TensorStructure) { checkShapesCompatible(tensor, other) for (i in 0 until tensor.numElements) { - tensor.buffer.array()[tensor.bufferStart + i] -= - other.tensor.buffer.array()[tensor.bufferStart + i] + tensor.mutableBuffer.array()[tensor.bufferStart + i] -= + other.tensor.mutableBuffer.array()[tensor.bufferStart + i] } } override fun Double.times(other: TensorStructure): DoubleTensor { val resBuffer = DoubleArray(other.tensor.numElements) { i -> - other.tensor.buffer.array()[other.tensor.bufferStart + i] * this + other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] * this } return DoubleTensor(other.shape, resBuffer) } @@ -159,36 +159,36 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { override fun TensorStructure.times(other: TensorStructure): DoubleTensor { checkShapesCompatible(tensor, other) val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.buffer.array()[tensor.bufferStart + i] * - other.tensor.buffer.array()[other.tensor.bufferStart + i] + tensor.mutableBuffer.array()[tensor.bufferStart + i] * + other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] } return DoubleTensor(tensor.shape, resBuffer) } override fun TensorStructure.timesAssign(value: Double) { for (i in 0 until tensor.numElements) { - tensor.buffer.array()[tensor.bufferStart + i] *= value + tensor.mutableBuffer.array()[tensor.bufferStart + i] *= value } } override fun TensorStructure.timesAssign(other: TensorStructure) { checkShapesCompatible(tensor, other) for (i in 0 until tensor.numElements) { - tensor.buffer.array()[tensor.bufferStart + i] *= - other.tensor.buffer.array()[tensor.bufferStart + i] + tensor.mutableBuffer.array()[tensor.bufferStart + i] *= + other.tensor.mutableBuffer.array()[tensor.bufferStart + i] } } override fun Double.div(other: TensorStructure): DoubleTensor { val resBuffer = DoubleArray(other.tensor.numElements) { i -> - this / other.tensor.buffer.array()[other.tensor.bufferStart + i] + this / other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] } return DoubleTensor(other.shape, resBuffer) } override fun TensorStructure.div(value: Double): DoubleTensor { val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.buffer.array()[tensor.bufferStart + i] / value + tensor.mutableBuffer.array()[tensor.bufferStart + i] / value } return DoubleTensor(shape, resBuffer) } @@ -196,29 +196,29 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { override fun TensorStructure.div(other: TensorStructure): DoubleTensor { checkShapesCompatible(tensor, other) val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.buffer.array()[other.tensor.bufferStart + i] / - other.tensor.buffer.array()[other.tensor.bufferStart + i] + tensor.mutableBuffer.array()[other.tensor.bufferStart + i] / + other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] } return DoubleTensor(tensor.shape, resBuffer) } override fun TensorStructure.divAssign(value: Double) { for (i in 0 until tensor.numElements) { - tensor.buffer.array()[tensor.bufferStart + i] /= value + tensor.mutableBuffer.array()[tensor.bufferStart + i] /= value } } override fun TensorStructure.divAssign(other: TensorStructure) { checkShapesCompatible(tensor, other) for (i in 0 until tensor.numElements) { - tensor.buffer.array()[tensor.bufferStart + i] /= - other.tensor.buffer.array()[tensor.bufferStart + i] + tensor.mutableBuffer.array()[tensor.bufferStart + i] /= + other.tensor.mutableBuffer.array()[tensor.bufferStart + i] } } override fun TensorStructure.unaryMinus(): DoubleTensor { val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.buffer.array()[tensor.bufferStart + i].unaryMinus() + tensor.mutableBuffer.array()[tensor.bufferStart + i].unaryMinus() } return DoubleTensor(tensor.shape, resBuffer) } @@ -241,8 +241,8 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { newMultiIndex[ii] = newMultiIndex[jj].also { newMultiIndex[jj] = newMultiIndex[ii] } val linearIndex = resTensor.linearStructure.offset(newMultiIndex) - resTensor.buffer.array()[linearIndex] = - tensor.buffer.array()[tensor.bufferStart + offset] + resTensor.mutableBuffer.array()[linearIndex] = + tensor.mutableBuffer.array()[tensor.bufferStart + offset] } return resTensor } @@ -250,7 +250,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { override fun TensorStructure.view(shape: IntArray): DoubleTensor { checkView(tensor, shape) - return DoubleTensor(shape, tensor.buffer.array(), tensor.bufferStart) + return DoubleTensor(shape, tensor.mutableBuffer.array(), tensor.bufferStart) } override fun TensorStructure.viewAs(other: TensorStructure): DoubleTensor { @@ -259,7 +259,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { override infix fun TensorStructure.dot(other: TensorStructure): DoubleTensor { if (tensor.shape.size == 1 && other.shape.size == 1) { - return DoubleTensor(intArrayOf(1), doubleArrayOf(tensor.times(other).tensor.buffer.array().sum())) + return DoubleTensor(intArrayOf(1), doubleArrayOf(tensor.times(other).tensor.mutableBuffer.array().sum())) } var newThis = tensor.copy() @@ -361,7 +361,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { public fun TensorStructure.map(transform: (Double) -> Double): DoubleTensor { return DoubleTensor( tensor.shape, - tensor.buffer.array().map { transform(it) }.toDoubleArray(), + tensor.mutableBuffer.array().map { transform(it) }.toDoubleArray(), tensor.bufferStart ) } @@ -382,7 +382,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return false } for (i in 0 until n) { - if (!eqFunction(tensor.buffer[tensor.bufferStart + i], other.tensor.buffer[other.tensor.bufferStart + i])) { + if (!eqFunction(tensor.mutableBuffer[tensor.bufferStart + i], other.tensor.mutableBuffer[other.tensor.bufferStart + i])) { return false } } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt index 71ccbf97b..2d4d6f0f7 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt @@ -18,8 +18,8 @@ internal inline fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: Doub } val curLinearIndex = tensor.linearStructure.offset(curMultiIndex) - resTensor.buffer.array()[linearIndex] = - tensor.buffer.array()[tensor.bufferStart + curLinearIndex] + resTensor.mutableBuffer.array()[linearIndex] = + tensor.mutableBuffer.array()[tensor.bufferStart + curLinearIndex] } } @@ -113,7 +113,7 @@ internal inline fun broadcastOuterTensors(vararg tensors: DoubleTensor): List BufferedTensor.vectorSequence(): Sequence BufferedTensor.matrixSequence(): Sequence Date: Fri, 30 Apr 2021 14:53:02 +0100 Subject: [PATCH 134/178] Fixed strides code duplication --- kmath-core/api/kmath-core.api | 4 ++-- .../space/kscience/kmath/nd/StructureND.kt | 6 +++--- .../kmath/tensors/core/BufferedTensor.kt | 4 ++-- .../algebras/BroadcastDoubleTensorAlgebra.kt | 16 +++++++------- .../core/algebras/TensorLinearStructure.kt | 21 ++++++++++--------- 5 files changed, 26 insertions(+), 25 deletions(-) diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index 41b85b3bb..1b98f547c 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -789,7 +789,7 @@ public final class space/kscience/kmath/nd/DefaultStrides : space/kscience/kmath public fun equals (Ljava/lang/Object;)Z public fun getLinearSize ()I public fun getShape ()[I - public fun getStrides ()Ljava/util/List; + public fun getStrides ()[I public fun hashCode ()I public fun index (I)[I public fun offset ([I)I @@ -931,7 +931,7 @@ public final class space/kscience/kmath/nd/ShortRingNDKt { public abstract interface class space/kscience/kmath/nd/Strides { public abstract fun getLinearSize ()I public abstract fun getShape ()[I - public abstract fun getStrides ()Ljava/util/List; + public abstract fun getStrides ()[I public abstract fun index (I)[I public fun indices ()Lkotlin/sequences/Sequence; public abstract fun offset ([I)I diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt index 0656b1f7f..65c233012 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt @@ -184,7 +184,7 @@ public interface Strides { /** * Array strides */ - public val strides: List + public val strides: IntArray /** * Get linear index from multidimensional index @@ -221,7 +221,7 @@ public class DefaultStrides private constructor(override val shape: IntArray) : /** * Strides for memory access */ - override val strides: List by lazy { + override val strides: IntArray by lazy { sequence { var current = 1 yield(1) @@ -230,7 +230,7 @@ public class DefaultStrides private constructor(override val shape: IntArray) : current *= it yield(current) } - }.toList() + }.toList().toIntArray() } override fun offset(index: IntArray): Int = index.mapIndexed { i, value -> diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index fae59804d..21030bbc7 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -15,7 +15,7 @@ public open class BufferedTensor( get() = TensorLinearStructure(shape) public val numElements: Int - get() = linearStructure.size + get() = linearStructure.linearSize override fun get(index: IntArray): T = mutableBuffer[bufferStart + linearStructure.offset(index)] @@ -60,7 +60,7 @@ internal fun TensorStructure.copyToBufferedTensor(): BufferedTensor = internal fun TensorStructure.toBufferedTensor(): BufferedTensor = when (this) { is BufferedTensor -> this - is MutableBufferND -> if (this.strides.strides.toIntArray() contentEquals TensorLinearStructure(this.shape).strides) + is MutableBufferND -> if (this.strides.strides contentEquals TensorLinearStructure(this.shape).strides) BufferedTensor(this.shape, this.mutableBuffer, 0) else this.copyToBufferedTensor() else -> this.copyToBufferedTensor() } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt index 350d939af..9b97d5ef2 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt @@ -20,7 +20,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> + val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> newThis.mutableBuffer.array()[i] + newOther.mutableBuffer.array()[i] } return DoubleTensor(newThis.shape, resBuffer) @@ -28,7 +28,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun TensorStructure.plusAssign(other: TensorStructure) { val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.size) { + for (i in 0 until tensor.linearStructure.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] += newOther.mutableBuffer.array()[tensor.bufferStart + i] } @@ -38,7 +38,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> + val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> newThis.mutableBuffer.array()[i] - newOther.mutableBuffer.array()[i] } return DoubleTensor(newThis.shape, resBuffer) @@ -46,7 +46,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun TensorStructure.minusAssign(other: TensorStructure) { val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.size) { + for (i in 0 until tensor.linearStructure.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] -= newOther.mutableBuffer.array()[tensor.bufferStart + i] } @@ -56,7 +56,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> + val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> newThis.mutableBuffer.array()[newThis.bufferStart + i] * newOther.mutableBuffer.array()[newOther.bufferStart + i] } @@ -65,7 +65,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun TensorStructure.timesAssign(other: TensorStructure) { val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.size) { + for (i in 0 until tensor.linearStructure.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] *= newOther.mutableBuffer.array()[tensor.bufferStart + i] } @@ -75,7 +75,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.size) { i -> + val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> newThis.mutableBuffer.array()[newOther.bufferStart + i] / newOther.mutableBuffer.array()[newOther.bufferStart + i] } @@ -84,7 +84,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { override fun TensorStructure.divAssign(other: TensorStructure) { val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.size) { + for (i in 0 until tensor.linearStructure.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] /= newOther.mutableBuffer.array()[tensor.bufferStart + i] } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt index b16739892..8e83dafd6 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt @@ -5,16 +5,17 @@ package space.kscience.kmath.tensors.core.algebras +import space.kscience.kmath.nd.Strides import kotlin.math.max -internal inline fun offsetFromIndex(index: IntArray, shape: IntArray, strides: IntArray): Int = +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 inline fun stridesFromShape(shape: IntArray): IntArray { +internal fun stridesFromShape(shape: IntArray): IntArray { val nDim = shape.size val res = IntArray(nDim) if (nDim == 0) @@ -31,7 +32,7 @@ internal inline fun stridesFromShape(shape: IntArray): IntArray { } -internal inline fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): IntArray { +internal fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): IntArray { val res = IntArray(nDim) var current = offset var strideIndex = 0 @@ -44,7 +45,7 @@ internal inline fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): return res } -internal inline fun stepIndex(index: IntArray, shape: IntArray, nDim: Int): IntArray { +internal fun stepIndex(index: IntArray, shape: IntArray, nDim: Int): IntArray { val res = index.copyOf() var current = nDim - 1 var carry = 0 @@ -62,26 +63,26 @@ internal inline fun stepIndex(index: IntArray, shape: IntArray, nDim: Int): IntA } -public class TensorLinearStructure(public val shape: IntArray) +public class TensorLinearStructure(override val shape: IntArray) : Strides { - public val strides: IntArray + override val strides: IntArray get() = stridesFromShape(shape) - public fun offset(index: IntArray): Int = offsetFromIndex(index, shape, strides) + override fun offset(index: IntArray): Int = offsetFromIndex(index, shape, strides) - public fun index(offset: Int): IntArray = + override fun index(offset: Int): IntArray = indexFromOffset(offset, strides, shape.size) public fun stepIndex(index: IntArray): IntArray = stepIndex(index, shape, shape.size) - public val size: Int + override val linearSize: Int get() = shape.reduce(Int::times) public val dim: Int get() = shape.size - public fun indices(): Sequence = (0 until size).asSequence().map { + override fun indices(): Sequence = (0 until linearSize).asSequence().map { index(it) } } \ No newline at end of file From 42ddd2e5692156ac4263f28fa9848e62180f2b38 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 30 Apr 2021 15:08:32 +0100 Subject: [PATCH 135/178] MutableBufferFromGenerator --- kmath-core/api/kmath-core.api | 18 +++++++++--------- .../space/kscience/kmath/nd/Structure1D.kt | 4 ++-- .../space/kscience/kmath/nd/Structure2D.kt | 6 +++--- .../space/kscience/kmath/structures/Buffer.kt | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index 1b98f547c..687de9cc8 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -1882,6 +1882,15 @@ public final class space/kscience/kmath/structures/MutableBuffer$Companion { public final fun short-1yRgbGw (ILkotlin/jvm/functions/Function1;)[S } +public final class space/kscience/kmath/structures/MutableBufferFromGenerator : space/kscience/kmath/structures/MutableBuffer { + public fun (ILkotlin/jvm/functions/Function1;)V + public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; + public fun get (I)Ljava/lang/Object; + public fun getSize ()I + public fun iterator ()Ljava/util/Iterator; + public fun set (ILjava/lang/Object;)V +} + public final class space/kscience/kmath/structures/MutableListBuffer : space/kscience/kmath/structures/MutableBuffer { public static final synthetic fun box-impl (Ljava/util/List;)Lspace/kscience/kmath/structures/MutableListBuffer; public static fun constructor-impl (ILkotlin/jvm/functions/Function1;)Ljava/util/List; @@ -1990,12 +1999,3 @@ public final class space/kscience/kmath/structures/VirtualBuffer : space/kscienc public fun iterator ()Ljava/util/Iterator; } -public final class space/kscience/kmath/structures/VirtualMutableBuffer : space/kscience/kmath/structures/MutableBuffer { - public fun (ILkotlin/jvm/functions/Function1;)V - public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun get (I)Ljava/lang/Object; - public fun getSize ()I - public fun iterator ()Ljava/util/Iterator; - public fun set (ILjava/lang/Object;)V -} - diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt index 93fc48713..8ea6d0f02 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt @@ -52,7 +52,7 @@ private value class Structure1DWrapper(val structure: StructureND) : Struc /** * A 1D wrapper for a mutable nd-structure */ -private inline class MutableStructure1DWrapper(val structure: MutableStructureND) : MutableStructure1D { +private class MutableStructure1DWrapper(val structure: MutableStructureND) : MutableStructure1D { override val shape: IntArray get() = structure.shape override val size: Int get() = structure.shape[0] override fun elements(): Sequence> = structure.elements() @@ -81,7 +81,7 @@ private value class Buffer1DWrapper(val buffer: Buffer) : Structure1D { override operator fun get(index: Int): T = buffer[index] } -internal inline class MutableBuffer1DWrapper(val buffer: MutableBuffer) : MutableStructure1D { +internal class MutableBuffer1DWrapper(val buffer: MutableBuffer) : MutableStructure1D { override val shape: IntArray get() = intArrayOf(buffer.size) override val size: Int get() = buffer.size diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt index 4c17d25d0..d987d8cf4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt @@ -8,7 +8,7 @@ package space.kscience.kmath.nd import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.VirtualBuffer -import space.kscience.kmath.structures.VirtualMutableBuffer +import space.kscience.kmath.structures.MutableBufferFromGenerator import kotlin.jvm.JvmInline import kotlin.reflect.KClass @@ -81,13 +81,13 @@ public interface MutableStructure2D : Structure2D, MutableStructureND { * The buffer of rows of this structure. It gets elements from the structure dynamically. */ override val rows: List> - get() = List(rowNum) { i -> MutableBuffer1DWrapper(VirtualMutableBuffer(colNum) { j -> get(i, j) })} + get() = List(rowNum) { i -> MutableBuffer1DWrapper(MutableBufferFromGenerator(colNum) { j -> get(i, j) })} /** * The buffer of columns of this structure. It gets elements from the structure dynamically. */ override val columns: List> - get() = List(colNum) { j -> MutableBuffer1DWrapper(VirtualMutableBuffer(rowNum) { i -> get(i, j) }) } + get() = List(colNum) { j -> MutableBuffer1DWrapper(MutableBufferFromGenerator(rowNum) { i -> get(i, j) }) } } /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt index 980fe698e..19018ffb5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt @@ -292,7 +292,7 @@ public class VirtualBuffer(override val size: Int, private val generator: (In override operator fun iterator(): Iterator = (0 until size).asSequence().map(generator).iterator() } -public class VirtualMutableBuffer(override val size: Int, private val generator: (Int) -> T) : MutableBuffer { +public class MutableBufferFromGenerator(override val size: Int, private val generator: (Int) -> T) : MutableBuffer { private val bufferHolder: MutableListBuffer = (0 until size).map(generator).toMutableList().asMutableBuffer() From 1695fc5075712c1c89121c0860c7c1e985737dbf Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 30 Apr 2021 15:25:45 +0100 Subject: [PATCH 136/178] Fix examples --- .../space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt | 3 ++- .../src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt index 38d8c1437..a84224bcf 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.tensors +import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra @@ -13,7 +14,7 @@ import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra fun main () { // work in context with linear operations - DoubleLinearOpsTensorAlgebra { + DoubleLinearOpsTensorAlgebra.invoke { // set true value of x val trueX = fromArray( diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt index 9318fe928..0408bba63 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt @@ -5,6 +5,7 @@ package space.kscience.kmath.tensors +import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra @@ -18,7 +19,7 @@ fun main() { val randSeed = 100500L // work in context with linear operations - DoubleLinearOpsTensorAlgebra { + DoubleLinearOpsTensorAlgebra.invoke { // take coefficient vector from normal distribution val alpha = randNormal( intArrayOf(5), From e2c7751c7eb146641cec0bba6e10e51e849e8371 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Fri, 30 Apr 2021 19:45:31 +0300 Subject: [PATCH 137/178] refactor linops --- .../algebras/DoubleLinearOpsTensorAlgebra.kt | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt index ab73b25b1..700fafbeb 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt @@ -53,14 +53,15 @@ public object DoubleLinearOpsTensorAlgebra : val lTensor = luTensor.zeroesLike() val uTensor = luTensor.zeroesLike() - for ((pairLU, lu) in lTensor.matrixSequence().zip(uTensor.matrixSequence()) - .zip(luTensor.tensor.matrixSequence())) { - val (l, u) = pairLU - luPivotHelper(l.as2D(), u.as2D(), lu.as2D(), n) - } + lTensor.matrixSequence() + .zip(uTensor.matrixSequence()) + .zip(luTensor.tensor.matrixSequence()) + .forEach { (pairLU, lu) -> + val (l, u) = pairLU + luPivotHelper(l.as2D(), u.as2D(), lu.as2D(), n) + } return Triple(pTensor, lTensor, uTensor) - } public fun TensorStructure.cholesky(epsilon: Double): DoubleTensor { @@ -82,11 +83,13 @@ public object DoubleLinearOpsTensorAlgebra : checkSquareMatrix(shape) val qTensor = zeroesLike() val rTensor = zeroesLike() - val seq = tensor.matrixSequence().zip((qTensor.matrixSequence().zip(rTensor.matrixSequence()))) - for ((matrix, qr) in seq) { + tensor.matrixSequence() + .zip((qTensor.matrixSequence() + .zip(rTensor.matrixSequence()))).forEach { (matrix, qr) -> val (q, r) = qr qrHelper(matrix.asTensor(), q.asTensor(), r.as2D()) } + return qTensor to rTensor } @@ -97,20 +100,24 @@ public object DoubleLinearOpsTensorAlgebra : val size = tensor.linearStructure.dim val commonShape = tensor.shape.sliceArray(0 until size - 2) val (n, m) = tensor.shape.sliceArray(size - 2 until size) - val resU = zeros(commonShape + intArrayOf(min(n, m), n)) - val resS = zeros(commonShape + intArrayOf(min(n, m))) - val resV = zeros(commonShape + intArrayOf(min(n, m), m)) + val uTensor = zeros(commonShape + intArrayOf(min(n, m), n)) + val sTensor = zeros(commonShape + intArrayOf(min(n, m))) + val vTensor = zeros(commonShape + intArrayOf(min(n, m), m)) - for ((matrix, USV) in tensor.matrixSequence() - .zip(resU.matrixSequence().zip(resS.vectorSequence().zip(resV.matrixSequence())))) { - val matrixSize = matrix.shape.reduce { acc, i -> acc * i } - val curMatrix = DoubleTensor( - matrix.shape, - matrix.mutableBuffer.array().slice(matrix.bufferStart until matrix.bufferStart + matrixSize).toDoubleArray() - ) - svdHelper(curMatrix, USV, m, n, epsilon) - } - return Triple(resU.transpose(), resS, resV.transpose()) + tensor.matrixSequence() + .zip(uTensor.matrixSequence() + .zip(sTensor.vectorSequence() + .zip(vTensor.matrixSequence()))).forEach { (matrix, USV) -> + val matrixSize = matrix.shape.reduce { acc, i -> acc * i } + val curMatrix = DoubleTensor( + matrix.shape, + matrix.mutableBuffer.array().slice(matrix.bufferStart until matrix.bufferStart + matrixSize) + .toDoubleArray() + ) + svdHelper(curMatrix, USV, m, n, epsilon) + } + + return Triple(uTensor.transpose(), sTensor, vTensor.transpose()) } override fun TensorStructure.symEig(): Pair = @@ -127,7 +134,7 @@ public object DoubleLinearOpsTensorAlgebra : cleanSymHelper(matrix.as2D(), n) val eig = (utv dot s.view(shp)).view(s.shape) - return Pair(eig, v) + return eig to v } public fun TensorStructure.detLU(epsilon: Double = 1e-9): DoubleTensor { From f0cdb9b6571774bd861288f059abaf0571c232bf Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Fri, 30 Apr 2021 20:07:59 +0300 Subject: [PATCH 138/178] refactor utils and remove inline --- .../kmath/tensors/core/broadcastUtils.kt | 77 +++++++++---------- .../kscience/kmath/tensors/core/checks.kt | 18 ++--- .../kscience/kmath/tensors/core/linUtils.kt | 41 +++++----- .../kscience/kmath/tensors/core/utils.kt | 45 ++++++----- .../core/TestDoubleLinearOpsAlgebra.kt | 2 +- 5 files changed, 94 insertions(+), 89 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt index 2d4d6f0f7..58d8654af 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt @@ -2,7 +2,7 @@ package space.kscience.kmath.tensors.core import kotlin.math.max -internal inline fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTensor, linearSize: Int) { +internal fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTensor, linearSize: Int) { for (linearIndex in 0 until linearSize) { val totalMultiIndex = resTensor.linearStructure.index(linearIndex) val curMultiIndex = tensor.shape.copyOf() @@ -23,7 +23,7 @@ internal inline fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: Doub } } -internal inline fun broadcastShapes(vararg shapes: IntArray): IntArray { +internal fun broadcastShapes(vararg shapes: IntArray): IntArray { var totalDim = 0 for (shape in shapes) { totalDim = max(totalDim, shape.size) @@ -51,7 +51,7 @@ internal inline fun broadcastShapes(vararg shapes: IntArray): IntArray { return totalShape } -internal inline fun broadcastTo(tensor: DoubleTensor, newShape: IntArray): DoubleTensor { +internal fun broadcastTo(tensor: DoubleTensor, newShape: IntArray): DoubleTensor { if (tensor.shape.size > newShape.size) { throw RuntimeException("Tensor is not compatible with the new shape") } @@ -71,7 +71,7 @@ internal inline fun broadcastTo(tensor: DoubleTensor, newShape: IntArray): Doubl return resTensor } -internal inline fun broadcastTensors(vararg tensors: DoubleTensor): List { +internal fun broadcastTensors(vararg tensors: DoubleTensor): List { val totalShape = broadcastShapes(*(tensors.map { it.shape }).toTypedArray()) val n = totalShape.reduce { acc, i -> acc * i } @@ -85,7 +85,7 @@ internal inline fun broadcastTensors(vararg tensors: DoubleTensor): List { +internal fun broadcastOuterTensors(vararg tensors: DoubleTensor): List { val onlyTwoDims = tensors.asSequence().onEach { require(it.shape.size >= 2) { throw RuntimeException("Tensors must have at least 2 dimensions") @@ -99,46 +99,45 @@ internal inline fun broadcastOuterTensors(vararg tensors: DoubleTensor): List acc * i } - val res = ArrayList(0) - for (tensor in tensors) { - val matrixShape = tensor.shape.sliceArray(tensor.shape.size - 2 until tensor.shape.size).copyOf() - val matrixSize = matrixShape[0] * matrixShape[1] - val matrix = DoubleTensor(matrixShape, DoubleArray(matrixSize)) + return buildList { + for (tensor in tensors) { + val matrixShape = tensor.shape.sliceArray(tensor.shape.size - 2 until tensor.shape.size).copyOf() + val matrixSize = matrixShape[0] * matrixShape[1] + val matrix = DoubleTensor(matrixShape, DoubleArray(matrixSize)) - val outerTensor = DoubleTensor(totalShape, DoubleArray(n)) - val resTensor = DoubleTensor(totalShape + matrixShape, DoubleArray(n * matrixSize)) + val outerTensor = DoubleTensor(totalShape, DoubleArray(n)) + val resTensor = DoubleTensor(totalShape + matrixShape, DoubleArray(n * matrixSize)) - for (linearIndex in 0 until n) { - val totalMultiIndex = outerTensor.linearStructure.index(linearIndex) - var curMultiIndex = tensor.shape.sliceArray(0..tensor.shape.size - 3).copyOf() - curMultiIndex = IntArray(totalMultiIndex.size - curMultiIndex.size) { 1 } + curMultiIndex + for (linearIndex in 0 until n) { + val totalMultiIndex = outerTensor.linearStructure.index(linearIndex) + var curMultiIndex = tensor.shape.sliceArray(0..tensor.shape.size - 3).copyOf() + curMultiIndex = IntArray(totalMultiIndex.size - curMultiIndex.size) { 1 } + curMultiIndex - val newTensor = DoubleTensor(curMultiIndex + matrixShape, tensor.mutableBuffer.array()) + val newTensor = DoubleTensor(curMultiIndex + matrixShape, tensor.mutableBuffer.array()) - for (i in curMultiIndex.indices) { - if (curMultiIndex[i] != 1) { - curMultiIndex[i] = totalMultiIndex[i] - } else { - curMultiIndex[i] = 0 + for (i in curMultiIndex.indices) { + if (curMultiIndex[i] != 1) { + curMultiIndex[i] = totalMultiIndex[i] + } else { + curMultiIndex[i] = 0 + } + } + + for (i in 0 until matrixSize) { + val curLinearIndex = newTensor.linearStructure.offset( + curMultiIndex + + matrix.linearStructure.index(i) + ) + val newLinearIndex = resTensor.linearStructure.offset( + totalMultiIndex + + matrix.linearStructure.index(i) + ) + + resTensor.mutableBuffer.array()[resTensor.bufferStart + newLinearIndex] = + newTensor.mutableBuffer.array()[newTensor.bufferStart + curLinearIndex] } } - - for (i in 0 until matrixSize) { - val curLinearIndex = newTensor.linearStructure.offset( - curMultiIndex + - matrix.linearStructure.index(i) - ) - val newLinearIndex = resTensor.linearStructure.offset( - totalMultiIndex + - matrix.linearStructure.index(i) - ) - - resTensor.mutableBuffer.array()[resTensor.bufferStart + newLinearIndex] = - newTensor.mutableBuffer.array()[newTensor.bufferStart + curLinearIndex] - } + add(resTensor) } - res += resTensor } - - return res } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt index fd5c8413d..fd98be8b2 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -5,38 +5,38 @@ import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra -internal inline fun checkEmptyShape(shape: IntArray): Unit = +internal fun checkEmptyShape(shape: IntArray): Unit = check(shape.isNotEmpty()) { "Illegal empty shape provided" } -internal inline fun checkEmptyDoubleBuffer(buffer: DoubleArray): Unit = +internal fun checkEmptyDoubleBuffer(buffer: DoubleArray): Unit = check(buffer.isNotEmpty()) { "Illegal empty buffer provided" } -internal inline fun checkBufferShapeConsistency(shape: IntArray, buffer: DoubleArray): Unit = +internal fun checkBufferShapeConsistency(shape: IntArray, buffer: DoubleArray): Unit = check(buffer.size == shape.reduce(Int::times)) { "Inconsistent shape ${shape.toList()} for buffer of size ${buffer.size} provided" } -internal inline fun checkShapesCompatible(a: TensorStructure, b: TensorStructure): Unit = +internal fun checkShapesCompatible(a: TensorStructure, b: TensorStructure): Unit = check(a.shape contentEquals b.shape) { "Incompatible shapes ${a.shape.toList()} and ${b.shape.toList()} " } -internal inline fun checkTranspose(dim: Int, i: Int, j: Int): Unit = +internal fun checkTranspose(dim: Int, i: Int, j: Int): Unit = check((i < dim) and (j < dim)) { "Cannot transpose $i to $j for a tensor of dim $dim" } -internal inline fun checkView(a: TensorStructure, shape: IntArray): Unit = +internal fun checkView(a: TensorStructure, shape: IntArray): Unit = check(a.shape.reduce(Int::times) == shape.reduce(Int::times)) -internal inline fun checkSquareMatrix(shape: IntArray): Unit { +internal fun checkSquareMatrix(shape: IntArray): Unit { val n = shape.size check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n instead" @@ -46,14 +46,14 @@ internal inline fun checkSquareMatrix(shape: IntArray): Unit { } } -internal inline fun DoubleTensorAlgebra.checkSymmetric( +internal fun DoubleTensorAlgebra.checkSymmetric( tensor: TensorStructure, epsilon: Double = 1e-6 ): Unit = check(tensor.eq(tensor.transpose(), epsilon)) { "Tensor is not symmetric about the last 2 dimensions at precision $epsilon" } -internal inline fun DoubleLinearOpsTensorAlgebra.checkPositiveDefinite( +internal fun DoubleLinearOpsTensorAlgebra.checkPositiveDefinite( tensor: DoubleTensor, epsilon: Double = 1e-6 ): Unit { checkSymmetric(tensor, epsilon) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt index 776a5e4d5..a152b3a17 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt @@ -13,7 +13,7 @@ import kotlin.math.sign import kotlin.math.sqrt -internal inline fun BufferedTensor.vectorSequence(): Sequence> = sequence { +internal fun BufferedTensor.vectorSequence(): Sequence> = sequence { val n = shape.size val vectorOffset = shape[n - 1] val vectorShape = intArrayOf(shape.last()) @@ -23,9 +23,9 @@ internal inline fun BufferedTensor.vectorSequence(): Sequence BufferedTensor.matrixSequence(): Sequence> = sequence { - check(shape.size >= 2) { "todo" } +internal fun BufferedTensor.matrixSequence(): Sequence> = sequence { val n = shape.size + check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" } val matrixOffset = shape[n - 1] * shape[n - 2] val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) for (offset in 0 until numElements step matrixOffset) { @@ -46,8 +46,7 @@ internal inline fun BufferedTensor.forEachMatrix(matrixAction: (BufferedT } } - -internal inline fun dotHelper( +internal fun dotHelper( a: MutableStructure2D, b: MutableStructure2D, res: MutableStructure2D, @@ -64,10 +63,11 @@ internal inline fun dotHelper( } } -internal inline fun luHelper( +internal fun luHelper( lu: MutableStructure2D, pivots: MutableStructure1D, - epsilon: Double): Boolean { + epsilon: Double +): Boolean { val m = lu.rowNum @@ -114,7 +114,7 @@ internal inline fun luHelper( return false } -internal inline fun BufferedTensor.setUpPivots(): IntTensor { +internal fun BufferedTensor.setUpPivots(): IntTensor { val n = this.shape.size val m = this.shape.last() val pivotsShape = IntArray(n - 1) { i -> this.shape[i] } @@ -126,22 +126,23 @@ internal inline fun BufferedTensor.setUpPivots(): IntTensor { ) } -internal inline fun DoubleLinearOpsTensorAlgebra.computeLU( +internal fun DoubleLinearOpsTensorAlgebra.computeLU( tensor: DoubleTensor, - epsilon: Double): Pair? { + epsilon: Double +): Pair? { checkSquareMatrix(tensor.shape) val luTensor = tensor.copy() val pivotsTensor = tensor.setUpPivots() for ((lu, pivots) in luTensor.matrixSequence().zip(pivotsTensor.vectorSequence())) - if(luHelper(lu.as2D(), pivots.as1D(), epsilon)) + if (luHelper(lu.as2D(), pivots.as1D(), epsilon)) return null return Pair(luTensor, pivotsTensor) } -internal inline fun pivInit( +internal fun pivInit( p: MutableStructure2D, pivot: MutableStructure1D, n: Int @@ -151,7 +152,7 @@ internal inline fun pivInit( } } -internal inline fun luPivotHelper( +internal fun luPivotHelper( l: MutableStructure2D, u: MutableStructure2D, lu: MutableStructure2D, @@ -172,7 +173,7 @@ internal inline fun luPivotHelper( } } -internal inline fun choleskyHelper( +internal fun choleskyHelper( a: MutableStructure2D, l: MutableStructure2D, n: Int @@ -193,7 +194,7 @@ internal inline fun choleskyHelper( } } -internal inline fun luMatrixDet(lu: MutableStructure2D, pivots: MutableStructure1D): Double { +internal fun luMatrixDet(lu: MutableStructure2D, pivots: MutableStructure1D): Double { if (lu[0, 0] == 0.0) { return 0.0 } @@ -202,7 +203,7 @@ internal inline fun luMatrixDet(lu: MutableStructure2D, pivots: MutableS return (0 until m).asSequence().map { lu[it, it] }.fold(sign) { left, right -> left * right } } -internal inline fun luMatrixInv( +internal fun luMatrixInv( lu: MutableStructure2D, pivots: MutableStructure1D, invMatrix: MutableStructure2D @@ -229,7 +230,7 @@ internal inline fun luMatrixInv( } } -internal inline fun DoubleLinearOpsTensorAlgebra.qrHelper( +internal fun DoubleLinearOpsTensorAlgebra.qrHelper( matrix: DoubleTensor, q: DoubleTensor, r: MutableStructure2D @@ -259,7 +260,7 @@ internal inline fun DoubleLinearOpsTensorAlgebra.qrHelper( } } -internal inline fun DoubleLinearOpsTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10): DoubleTensor { +internal fun DoubleLinearOpsTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10): DoubleTensor { val (n, m) = a.shape var v: DoubleTensor val b: DoubleTensor @@ -283,7 +284,7 @@ internal inline fun DoubleLinearOpsTensorAlgebra.svd1d(a: DoubleTensor, epsilon: } } -internal inline fun DoubleLinearOpsTensorAlgebra.svdHelper( +internal fun DoubleLinearOpsTensorAlgebra.svdHelper( matrix: DoubleTensor, USV: Pair, Pair, BufferedTensor>>, m: Int, n: Int, epsilon: Double @@ -335,7 +336,7 @@ internal inline fun DoubleLinearOpsTensorAlgebra.svdHelper( } } -internal inline fun cleanSymHelper(matrix: MutableStructure2D, n: Int) { +internal fun cleanSymHelper(matrix: MutableStructure2D, n: Int) { for (i in 0 until n) for (j in 0 until n) { if (i == j) { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index cb23dbdd6..58d280307 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -23,19 +23,19 @@ internal fun Buffer.array(): DoubleArray = when (this) { else -> this.toDoubleArray() } -internal inline fun getRandomNormals(n: Int, seed: Long): DoubleArray { +internal fun getRandomNormals(n: Int, seed: Long): DoubleArray { val distribution = GaussianSampler(0.0, 1.0) val generator = RandomGenerator.default(seed) return distribution.sample(generator).nextBufferBlocking(n).toDoubleArray() } -internal inline fun getRandomUnitVector(n: Int, seed: Long): DoubleArray { +internal fun getRandomUnitVector(n: Int, seed: Long): DoubleArray { val unnorm = getRandomNormals(n, seed) val norm = sqrt(unnorm.map { it * it }.sum()) return unnorm.map { it / norm }.toDoubleArray() } -internal inline fun minusIndexFrom(n: Int, i: Int) : Int = if (i >= 0) i else { +internal fun minusIndexFrom(n: Int, i: Int): Int = if (i >= 0) i else { val ii = n + i check(ii >= 0) { "Out of bound index $i for tensor of dim $n" @@ -43,27 +43,28 @@ internal inline fun minusIndexFrom(n: Int, i: Int) : Int = if (i >= 0) i else { ii } -internal inline fun BufferedTensor.minusIndex(i: Int): Int = minusIndexFrom(this.dimension, i) +internal fun BufferedTensor.minusIndex(i: Int): Int = minusIndexFrom(this.dimension, i) -internal inline fun format(value: Double, digits: Int = 4): String { +internal fun format(value: Double, digits: Int = 4): String { val ten = 10.0 - val approxOrder = if(value == 0.0) 0 else ceil(log10(abs(value))).toInt() - val order = if( + val approxOrder = if (value == 0.0) 0 else ceil(log10(abs(value))).toInt() + val order = if ( ((value % ten) == 0.0) or (value == 1.0) or - ((1/value) % ten == 0.0)) approxOrder else approxOrder - 1 + ((1 / value) % ten == 0.0) + ) approxOrder else approxOrder - 1 val lead = value / ten.pow(order) - val leadDisplay = round(lead*ten.pow(digits)) / ten.pow(digits) - val orderDisplay = if(order == 0) "" else if(order > 0) "E+$order" else "E$order" + val leadDisplay = round(lead * ten.pow(digits)) / ten.pow(digits) + val orderDisplay = if (order == 0) "" else if (order > 0) "E+$order" else "E$order" val valueDisplay = "$leadDisplay$orderDisplay" - val res = if(value < 0.0) valueDisplay else " $valueDisplay" + val res = if (value < 0.0) valueDisplay else " $valueDisplay" val fLength = digits + 6 val endSpace = " ".repeat(fLength - res.length) return "$res$endSpace" } -internal inline fun DoubleTensor.toPrettyString(): String = buildString { +internal fun DoubleTensor.toPrettyString(): String = buildString { var offset = 0 val shape = this@toPrettyString.shape val linearStructure = this@toPrettyString.linearStructure @@ -72,32 +73,36 @@ internal inline fun DoubleTensor.toPrettyString(): String = buildString { append(initString) var charOffset = 3 for (vector in vectorSequence()) { - append(" ".repeat(charOffset)) + repeat(charOffset) { append(' ') } val index = linearStructure.index(offset) for (ind in index.reversed()) { if (ind != 0) { break } - append("[") + append('[') charOffset += 1 } val values = vector.as1D().toMutableList().map(::format) - append(values.joinToString(", ")) - append("]") + values.joinTo(this, separator = ", ") + + append(']') charOffset -= 1 - for ((ind, maxInd) in index.reversed().zip(shape.reversed()).drop(1)){ + + index.reversed().zip(shape.reversed()).drop(1).forEach { (ind, maxInd) -> if (ind != maxInd - 1) { - break + return@forEach } - append("]") - charOffset -=1 + append(']') + charOffset -= 1 } + offset += vectorSize if (this@toPrettyString.numElements == offset) { break } + append(",\n") } append("\n)") diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 1148c0aad..2282d7fcb 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -182,7 +182,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } -private inline fun DoubleLinearOpsTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double = 1e-10): Unit { +private fun DoubleLinearOpsTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double = 1e-10): Unit { val svd = tensor.svd() val tensorSVD = svd.first From 8a039326d40fe4e840bed09170607c457a89e5a3 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 30 Apr 2021 19:47:05 +0100 Subject: [PATCH 139/178] Minor corrections --- kmath-core/api/kmath-core.api | 3 +-- .../kotlin/space/kscience/kmath/nd/StructureND.kt | 10 ++++------ .../tensors/core/algebras/TensorLinearStructure.kt | 5 ----- .../kscience/kmath/tensors/core/broadcastUtils.kt | 13 ++++++------- .../kmath/tensors/core/TestDoubleTensorAlgebra.kt | 1 - 5 files changed, 11 insertions(+), 21 deletions(-) diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index 687de9cc8..261aa1e24 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -792,7 +792,6 @@ public final class space/kscience/kmath/nd/DefaultStrides : space/kscience/kmath public fun getStrides ()[I public fun hashCode ()I public fun index (I)[I - public fun offset ([I)I } public final class space/kscience/kmath/nd/DefaultStrides$Companion { @@ -934,7 +933,7 @@ public abstract interface class space/kscience/kmath/nd/Strides { public abstract fun getStrides ()[I public abstract fun index (I)[I public fun indices ()Lkotlin/sequences/Sequence; - public abstract fun offset ([I)I + public fun offset ([I)I } public abstract interface class space/kscience/kmath/nd/Structure1D : space/kscience/kmath/nd/StructureND, space/kscience/kmath/structures/Buffer { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt index 65c233012..a3331d71a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt @@ -189,7 +189,10 @@ public interface Strides { /** * Get linear index from multidimensional index */ - public fun offset(index: IntArray): Int + public fun offset(index: IntArray): Int = index.mapIndexed { i, value -> + if (value < 0 || value >= shape[i]) throw IndexOutOfBoundsException("Index $value out of shape bounds: (0,${this.shape[i]})") + value * strides[i] + }.sum() /** * Get multidimensional from linear @@ -233,11 +236,6 @@ public class DefaultStrides private constructor(override val shape: IntArray) : }.toList().toIntArray() } - override fun offset(index: IntArray): Int = index.mapIndexed { i, value -> - if (value < 0 || value >= shape[i]) throw IndexOutOfBoundsException("Index $value out of shape bounds: (0,${this.shape[i]})") - value * strides[i] - }.sum() - override fun index(offset: Int): IntArray { val res = IntArray(shape.size) var current = offset diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt index 8e83dafd6..08aab5175 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt @@ -68,8 +68,6 @@ public class TensorLinearStructure(override val shape: IntArray) : Strides override val strides: IntArray get() = stridesFromShape(shape) - override fun offset(index: IntArray): Int = offsetFromIndex(index, shape, strides) - override fun index(offset: Int): IntArray = indexFromOffset(offset, strides, shape.size) @@ -82,7 +80,4 @@ public class TensorLinearStructure(override val shape: IntArray) : Strides public val dim: Int get() = shape.size - override fun indices(): Sequence = (0 until linearSize).asSequence().map { - index(it) - } } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt index 58d8654af..e883b7861 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt @@ -75,14 +75,13 @@ internal fun broadcastTensors(vararg tensors: DoubleTensor): List val totalShape = broadcastShapes(*(tensors.map { it.shape }).toTypedArray()) val n = totalShape.reduce { acc, i -> acc * i } - val res = ArrayList(0) - for (tensor in tensors) { - val resTensor = DoubleTensor(totalShape, DoubleArray(n)) - multiIndexBroadCasting(tensor, resTensor, n) - res.add(resTensor) + return buildList { + for (tensor in tensors) { + val resTensor = DoubleTensor(totalShape, DoubleArray(n)) + multiIndexBroadCasting(tensor, resTensor, n) + add(resTensor) + } } - - return res } internal fun broadcastOuterTensors(vararg tensors: DoubleTensor): List { diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index 34fe5d5f1..a0efa4573 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -170,7 +170,6 @@ internal class TestDoubleTensorAlgebra { 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 tensor3 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 5.0)) - val tensor4 = fromArray(intArrayOf(6, 1), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) assertTrue(tensor1 eq tensor1) assertTrue(tensor1 eq tensor2) From 74773686b432eac9e7d7804ffabf38eb1dbf1dca Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 30 Apr 2021 19:49:43 +0100 Subject: [PATCH 140/178] toDoubleTensor and toIntTensor renaming --- .../space/kscience/kmath/tensors/core/BufferedTensor.kt | 4 ++-- .../space/kscience/kmath/tensors/core/TestDoubleTensor.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 21030bbc7..4e286b489 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -77,5 +77,5 @@ internal val TensorStructure.tensor: IntTensor else -> this.toBufferedTensor().asTensor() } -public fun TensorStructure.toTypedTensor(): DoubleTensor = this.tensor -public fun TensorStructure.toTypedTensor(): IntTensor = this.tensor \ No newline at end of file +public fun TensorStructure.toDoubleTensor(): DoubleTensor = this.tensor +public fun TensorStructure.toIntTensor(): IntTensor = this.tensor \ No newline at end of file diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index eca54f68b..333a7bdec 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -67,8 +67,8 @@ internal class TestDoubleTensor { val bufferedTensorArray = ndArray.toBufferedTensor() // strides are flipped so data copied val tensorArray = bufferedTensorArray.asTensor() // data not contiguous so copied again - val tensorArrayPublic = ndArray.toTypedTensor() // public API, data copied twice - val sharedTensorArray = tensorArrayPublic.toTypedTensor() // no data copied by matching type + val tensorArrayPublic = ndArray.toDoubleTensor() // public API, data copied twice + val sharedTensorArray = tensorArrayPublic.toDoubleTensor() // no data copied by matching type assertTrue(tensorArray.mutableBuffer.array() contentEquals sharedTensorArray.mutableBuffer.array()) From 1b6bd67b903f761bf009a0677e422f637dd775d4 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 30 Apr 2021 21:11:01 +0100 Subject: [PATCH 141/178] No virtual mutable buffers --- kmath-core/api/kmath-core.api | 9 --------- .../space/kscience/kmath/nd/Structure2D.kt | 6 +++--- .../space/kscience/kmath/structures/Buffer.kt | 18 ------------------ 3 files changed, 3 insertions(+), 30 deletions(-) diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api index 261aa1e24..865ad2f6d 100644 --- a/kmath-core/api/kmath-core.api +++ b/kmath-core/api/kmath-core.api @@ -1881,15 +1881,6 @@ public final class space/kscience/kmath/structures/MutableBuffer$Companion { public final fun short-1yRgbGw (ILkotlin/jvm/functions/Function1;)[S } -public final class space/kscience/kmath/structures/MutableBufferFromGenerator : space/kscience/kmath/structures/MutableBuffer { - public fun (ILkotlin/jvm/functions/Function1;)V - public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun get (I)Ljava/lang/Object; - public fun getSize ()I - public fun iterator ()Ljava/util/Iterator; - public fun set (ILjava/lang/Object;)V -} - public final class space/kscience/kmath/structures/MutableListBuffer : space/kscience/kmath/structures/MutableBuffer { public static final synthetic fun box-impl (Ljava/util/List;)Lspace/kscience/kmath/structures/MutableListBuffer; public static fun constructor-impl (ILkotlin/jvm/functions/Function1;)Ljava/util/List; diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt index d987d8cf4..28ae07a3c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt @@ -8,7 +8,7 @@ package space.kscience.kmath.nd import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.VirtualBuffer -import space.kscience.kmath.structures.MutableBufferFromGenerator +import space.kscience.kmath.structures.MutableListBuffer import kotlin.jvm.JvmInline import kotlin.reflect.KClass @@ -81,13 +81,13 @@ public interface MutableStructure2D : Structure2D, MutableStructureND { * The buffer of rows of this structure. It gets elements from the structure dynamically. */ override val rows: List> - get() = List(rowNum) { i -> MutableBuffer1DWrapper(MutableBufferFromGenerator(colNum) { j -> get(i, j) })} + get() = List(rowNum) { i -> MutableBuffer1DWrapper(MutableListBuffer(colNum) { j -> get(i, j) })} /** * The buffer of columns of this structure. It gets elements from the structure dynamically. */ override val columns: List> - get() = List(colNum) { j -> MutableBuffer1DWrapper(MutableBufferFromGenerator(rowNum) { i -> get(i, j) }) } + get() = List(colNum) { j -> MutableBuffer1DWrapper(MutableListBuffer(rowNum) { i -> get(i, j) }) } } /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt index 19018ffb5..be5dfb359 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt @@ -292,24 +292,6 @@ public class VirtualBuffer(override val size: Int, private val generator: (In override operator fun iterator(): Iterator = (0 until size).asSequence().map(generator).iterator() } -public class MutableBufferFromGenerator(override val size: Int, private val generator: (Int) -> T) : MutableBuffer { - - private val bufferHolder: MutableListBuffer = (0 until size).map(generator).toMutableList().asMutableBuffer() - - override operator fun get(index: Int): T { - if (index < 0 || index >= size) throw IndexOutOfBoundsException("Expected index from 0 to ${size - 1}, but found $index") - return bufferHolder[index] - } - - override operator fun iterator(): Iterator = bufferHolder.iterator() - - override fun set(index: Int, value: T) { - bufferHolder[index] = value - } - - override fun copy(): MutableBuffer = bufferHolder.copy() -} - /** * Convert this buffer to read-only buffer. */ From b7cac3a015d235d81d02d3bb4b8834dda2b48b95 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Sat, 1 May 2021 13:32:50 +0300 Subject: [PATCH 142/178] fix sequences + array casting --- .../kmath/tensors/core/BufferedTensor.kt | 38 ++++++++++++++++++- .../kscience/kmath/tensors/core/linUtils.kt | 4 +- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 4e286b489..867b4fb7a 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -49,6 +49,7 @@ public class DoubleTensor internal constructor( internal fun BufferedTensor.asTensor(): IntTensor = IntTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) + internal fun BufferedTensor.asTensor(): DoubleTensor = DoubleTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) @@ -78,4 +79,39 @@ internal val TensorStructure.tensor: IntTensor } public fun TensorStructure.toDoubleTensor(): DoubleTensor = this.tensor -public fun TensorStructure.toIntTensor(): IntTensor = this.tensor \ No newline at end of file +public fun TensorStructure.toIntTensor(): IntTensor = this.tensor + +public fun Array.toDoubleTensor(): DoubleTensor { + val n = size + check(n > 0) { "An empty array cannot be casted to tensor" } + val m = first().size + check(m > 0) { "Inner arrays must have at least 1 argument" } + check(all { size == m }) { "Inner arrays must be the same size" } + + val shape = intArrayOf(n, m) + val buffer = this.flatMap { arr -> arr.map { it } }.toDoubleArray() + + return DoubleTensor(shape, buffer, 0) +} + + +public fun Array.toIntTensor(): IntTensor { + val n = size + check(n > 0) { "An empty array cannot be casted to tensor" } + val m = first().size + check(m > 0) { "Inner arrays must have at least 1 argument" } + check(all { size == m }) { "Inner arrays must be the same size" } + + val shape = intArrayOf(n, m) + val buffer = this.flatMap { arr -> arr.map { it } }.toIntArray() + + return IntTensor(shape, buffer, 0) +} + +public fun DoubleTensor.toDoubleArray(): DoubleArray { + return tensor.mutableBuffer.array().drop(bufferStart).take(numElements).toDoubleArray() +} + +public fun IntTensor.toIntArray(): IntArray { + return tensor.mutableBuffer.array().drop(bufferStart).take(numElements).toIntArray() +} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt index a152b3a17..e54cc4d26 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt @@ -18,7 +18,7 @@ internal fun BufferedTensor.vectorSequence(): Sequence> val vectorOffset = shape[n - 1] val vectorShape = intArrayOf(shape.last()) for (offset in 0 until numElements step vectorOffset) { - val vector = BufferedTensor(vectorShape, mutableBuffer, offset) + val vector = BufferedTensor(vectorShape, mutableBuffer, bufferStart + offset) yield(vector) } } @@ -29,7 +29,7 @@ internal fun BufferedTensor.matrixSequence(): Sequence> val matrixOffset = shape[n - 1] * shape[n - 2] val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) for (offset in 0 until numElements step matrixOffset) { - val matrix = BufferedTensor(matrixShape, mutableBuffer, offset) + val matrix = BufferedTensor(matrixShape, mutableBuffer, bufferStart + offset) yield(matrix) } } From fe81dea243860ad063d5490d13225182ddbfaedc Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Sat, 1 May 2021 14:22:05 +0300 Subject: [PATCH 143/178] stack --- .../core/algebras/DoubleTensorAlgebra.kt | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index f428b9d2e..c6fb301b5 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -382,7 +382,11 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return false } for (i in 0 until n) { - if (!eqFunction(tensor.mutableBuffer[tensor.bufferStart + i], other.tensor.mutableBuffer[other.tensor.bufferStart + i])) { + if (!eqFunction( + tensor.mutableBuffer[tensor.bufferStart + i], + other.tensor.mutableBuffer[other.tensor.bufferStart + i] + ) + ) { return false } } @@ -395,4 +399,20 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { public fun TensorStructure.randNormalLike(seed: Long = 0): DoubleTensor = DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed)) + // stack tensors by axis 0 + public fun stack(tensors: List): DoubleTensor { + val shape = tensors.firstOrNull()?.shape + check(shape != null) { "Collection must have at least 1 element" } + check(tensors.all { it.shape contentEquals shape }) {"Stacking tensors must have same shapes"} + val resShape = intArrayOf(tensors.size) + shape + val resBuffer = tensors.flatMap { + it.tensor.mutableBuffer.array().drop(it.bufferStart).take(it.numElements) + }.toDoubleArray() + return DoubleTensor(resShape, resBuffer, 0) + } + + // build tensor from this rows by given indices + public fun TensorStructure.rowsByIndices(indices: IntArray): DoubleTensor { + return stack(indices.map { this[it] }) + } } From bfba653904793b74be89ea9f46461ad8c20a2b8e Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Sat, 1 May 2021 17:47:12 +0300 Subject: [PATCH 144/178] refactor --- .../kscience/kmath/tensors/OLSWithSVD.kt | 6 ++--- .../algebras/DoubleLinearOpsTensorAlgebra.kt | 8 ++++--- .../core/algebras/DoubleTensorAlgebra.kt | 18 +++++++------- .../kmath/tensors/core/broadcastUtils.kt | 24 +++++++++---------- .../kscience/kmath/tensors/core/utils.kt | 3 +-- .../core/TestDoubleLinearOpsAlgebra.kt | 6 ++--- 6 files changed, 32 insertions(+), 33 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt index 0408bba63..095905f05 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt @@ -21,7 +21,7 @@ fun main() { // work in context with linear operations DoubleLinearOpsTensorAlgebra.invoke { // take coefficient vector from normal distribution - val alpha = randNormal( + val alpha = randomNormal( intArrayOf(5), randSeed ) + fromArray( @@ -32,14 +32,14 @@ fun main() { println("Real alpha:\n$alpha") // also take sample of size 20 from normal distribution for x - val x = randNormal( + val x = randomNormal( intArrayOf(20, 5), randSeed ) // calculate y and add gaussian noise (N(0, 0.05)) val y = x dot alpha - y += y.randNormalLike(randSeed) * 0.05 + y += y.randomNormalLike(randSeed) * 0.05 // now restore the coefficient vector with OSL estimator with SVD val (u, singValues, v) = x.svd() diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt index 700fafbeb..dd5ad5a61 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt @@ -31,7 +31,7 @@ public object DoubleLinearOpsTensorAlgebra : public fun TensorStructure.luFactor(epsilon: Double): Pair = computeLU(tensor, epsilon) - ?: throw RuntimeException("Tensor contains matrices which are singular at precision $epsilon") + ?: throw IllegalArgumentException("Tensor contains matrices which are singular at precision $epsilon") public fun TensorStructure.luFactor(): Pair = luFactor(1e-9) @@ -47,8 +47,10 @@ public object DoubleLinearOpsTensorAlgebra : val n = luTensor.shape.last() val pTensor = luTensor.zeroesLike() - for ((p, pivot) in pTensor.matrixSequence().zip(pivotsTensor.tensor.vectorSequence())) - pivInit(p.as2D(), pivot.as1D(), n) + pTensor + .matrixSequence() + .zip(pivotsTensor.tensor.vectorSequence()) + .forEach { (p, pivot) -> pivInit(p.as2D(), pivot.as1D(), n) } val lTensor = luTensor.zeroesLike() val uTensor = luTensor.zeroesLike() diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index c6fb301b5..d3e8bf175 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -284,7 +284,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { val m1 = newThis.shape[newThis.shape.size - 1] val m2 = newOther.shape[newOther.shape.size - 2] val n = newOther.shape[newOther.shape.size - 1] - if (m1 != m2) { + check (m1 == m2) { throw RuntimeException("Tensors dot operation dimension mismatch: ($l, $m1) x ($m2, $n)") } @@ -315,11 +315,11 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { val d1 = minusIndexFrom(n + 1, dim1) val d2 = minusIndexFrom(n + 1, dim2) - if (d1 == d2) { - throw RuntimeException("Diagonal dimensions cannot be identical $d1, $d2") + check(d1 != d2) { + "Diagonal dimensions cannot be identical $d1, $d2" } - if (d1 > n || d2 > n) { - throw RuntimeException("Dimension out of range") + check(d1 <= n && d2 <= n) { + "Dimension out of range" } var lessDim = d1 @@ -366,8 +366,8 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { ) } - public fun TensorStructure.eq(other: TensorStructure, delta: Double): Boolean { - return tensor.eq(other) { x, y -> abs(x - y) < delta } + public fun TensorStructure.eq(other: TensorStructure, epsilon: Double): Boolean { + return tensor.eq(other) { x, y -> abs(x - y) < epsilon } } public infix fun TensorStructure.eq(other: TensorStructure): Boolean = tensor.eq(other, 1e-5) @@ -393,10 +393,10 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return true } - public fun randNormal(shape: IntArray, seed: Long = 0): DoubleTensor = + public fun randomNormal(shape: IntArray, seed: Long = 0): DoubleTensor = DoubleTensor(shape, getRandomNormals(shape.reduce(Int::times), seed)) - public fun TensorStructure.randNormalLike(seed: Long = 0): DoubleTensor = + public fun TensorStructure.randomNormalLike(seed: Long = 0): DoubleTensor = DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed)) // stack tensors by axis 0 diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt index e883b7861..dfac054b5 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt @@ -42,8 +42,8 @@ internal fun broadcastShapes(vararg shapes: IntArray): IntArray { for (i in shape.indices) { val curDim = shape[i] val offset = totalDim - shape.size - if (curDim != 1 && totalShape[i + offset] != curDim) { - throw RuntimeException("Shapes are not compatible and cannot be broadcast") + check(curDim == 1 || totalShape[i + offset] == curDim) { + "Shapes are not compatible and cannot be broadcast" } } } @@ -52,8 +52,8 @@ internal fun broadcastShapes(vararg shapes: IntArray): IntArray { } internal fun broadcastTo(tensor: DoubleTensor, newShape: IntArray): DoubleTensor { - if (tensor.shape.size > newShape.size) { - throw RuntimeException("Tensor is not compatible with the new shape") + require(tensor.shape.size <= newShape.size) { + "Tensor is not compatible with the new shape" } val n = newShape.reduce { acc, i -> acc * i } @@ -62,8 +62,8 @@ internal fun broadcastTo(tensor: DoubleTensor, newShape: IntArray): DoubleTensor for (i in tensor.shape.indices) { val curDim = tensor.shape[i] val offset = newShape.size - tensor.shape.size - if (curDim != 1 && newShape[i + offset] != curDim) { - throw RuntimeException("Tensor is not compatible with the new shape and cannot be broadcast") + check(curDim == 1 || newShape[i + offset] == curDim) { + "Tensor is not compatible with the new shape and cannot be broadcast" } } @@ -75,19 +75,17 @@ internal fun broadcastTensors(vararg tensors: DoubleTensor): List val totalShape = broadcastShapes(*(tensors.map { it.shape }).toTypedArray()) val n = totalShape.reduce { acc, i -> acc * i } - return buildList { - for (tensor in tensors) { - val resTensor = DoubleTensor(totalShape, DoubleArray(n)) - multiIndexBroadCasting(tensor, resTensor, n) - add(resTensor) - } + return tensors.map { tensor -> + val resTensor = DoubleTensor(totalShape, DoubleArray(n)) + multiIndexBroadCasting(tensor, resTensor, n) + resTensor } } internal fun broadcastOuterTensors(vararg tensors: DoubleTensor): List { val onlyTwoDims = tensors.asSequence().onEach { require(it.shape.size >= 2) { - throw RuntimeException("Tensors must have at least 2 dimensions") + "Tensors must have at least 2 dimensions" } }.any { it.shape.size != 2 } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index 58d280307..88b9c6c5c 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -69,8 +69,7 @@ internal fun DoubleTensor.toPrettyString(): String = buildString { val shape = this@toPrettyString.shape val linearStructure = this@toPrettyString.linearStructure val vectorSize = shape.last() - val initString = "DoubleTensor(\n" - append(initString) + append("DoubleTensor(\n") var charOffset = 3 for (vector in vectorSequence()) { repeat(charOffset) { append(' ') } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 2282d7fcb..6689e893a 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -135,7 +135,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { @Test fun testCholesky() = DoubleLinearOpsTensorAlgebra.invoke { - val tensor = randNormal(intArrayOf(2, 5, 5), 0) + val tensor = randomNormal(intArrayOf(2, 5, 5), 0) val sigma = (tensor dot tensor.transpose()) + diagonalEmbedding( fromArray(intArrayOf(2, 5), DoubleArray(10) { 0.1 }) ) @@ -163,7 +163,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { @Test fun testBatchedSVD() = DoubleLinearOpsTensorAlgebra.invoke { - val tensor = randNormal(intArrayOf(2, 5, 3), 0) + val tensor = randomNormal(intArrayOf(2, 5, 3), 0) val (tensorU, tensorS, tensorV) = tensor.svd() val tensorSVD = tensorU dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) assertTrue(tensor.eq(tensorSVD)) @@ -171,7 +171,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { @Test fun testBatchedSymEig() = DoubleLinearOpsTensorAlgebra.invoke { - val tensor = randNormal(shape = intArrayOf(2, 3, 3), 0) + val tensor = randomNormal(shape = intArrayOf(2, 3, 3), 0) val tensorSigma = tensor + tensor.transpose() val (tensorS, tensorV) = tensorSigma.symEig() val tensorSigmaCalc = tensorV dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) From ac6608b5b45ed7b59667216ec62b73380f60ef97 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Sat, 1 May 2021 20:45:23 +0300 Subject: [PATCH 145/178] refactor --- .../tensors/LinearSystemSolvingWithLUP.kt | 2 +- .../kscience/kmath/tensors/OLSWithSVD.kt | 2 +- kmath-tensors/build.gradle.kts | 3 ++ .../kmath/tensors/core/BufferedTensor.kt | 8 +++- .../kscience/kmath/tensors/core/checks.kt | 23 ++++------ .../kscience/kmath/tensors/core/linUtils.kt | 12 ----- .../kscience/kmath/tensors/core/utils.kt | 45 +++++++++++-------- 7 files changed, 47 insertions(+), 48 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt index a84224bcf..bd8233ccc 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt @@ -14,7 +14,7 @@ import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra fun main () { // work in context with linear operations - DoubleLinearOpsTensorAlgebra.invoke { + DoubleLinearOpsTensorAlgebra { // set true value of x val trueX = fromArray( diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt index 095905f05..435af35f6 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt @@ -19,7 +19,7 @@ fun main() { val randSeed = 100500L // work in context with linear operations - DoubleLinearOpsTensorAlgebra.invoke { + DoubleLinearOpsTensorAlgebra { // take coefficient vector from normal distribution val alpha = randomNormal( intArrayOf(5), diff --git a/kmath-tensors/build.gradle.kts b/kmath-tensors/build.gradle.kts index af5116022..b7f24dc6a 100644 --- a/kmath-tensors/build.gradle.kts +++ b/kmath-tensors/build.gradle.kts @@ -3,6 +3,9 @@ plugins { } kotlin.sourceSets { + all { + languageSettings.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") + } commonMain { dependencies { api(project(":kmath-core")) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 867b4fb7a..9541a97f9 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -109,9 +109,13 @@ public fun Array.toIntTensor(): IntTensor { } public fun DoubleTensor.toDoubleArray(): DoubleArray { - return tensor.mutableBuffer.array().drop(bufferStart).take(numElements).toDoubleArray() + return DoubleArray(numElements) { i -> + mutableBuffer[bufferStart + i] + } } public fun IntTensor.toIntArray(): IntArray { - return tensor.mutableBuffer.array().drop(bufferStart).take(numElements).toIntArray() + return IntArray(numElements) { i -> + mutableBuffer[bufferStart + i] + } } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt index fd98be8b2..b1c12ccde 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -5,38 +5,35 @@ import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra -internal fun checkEmptyShape(shape: IntArray): Unit = +internal fun checkEmptyShape(shape: IntArray) = check(shape.isNotEmpty()) { "Illegal empty shape provided" } -internal fun checkEmptyDoubleBuffer(buffer: DoubleArray): Unit = +internal fun checkEmptyDoubleBuffer(buffer: DoubleArray) = check(buffer.isNotEmpty()) { "Illegal empty buffer provided" } -internal fun checkBufferShapeConsistency(shape: IntArray, buffer: DoubleArray): Unit = +internal fun checkBufferShapeConsistency(shape: IntArray, buffer: DoubleArray) = check(buffer.size == shape.reduce(Int::times)) { "Inconsistent shape ${shape.toList()} for buffer of size ${buffer.size} provided" } - -internal fun checkShapesCompatible(a: TensorStructure, b: TensorStructure): Unit = +internal fun checkShapesCompatible(a: TensorStructure, b: TensorStructure) = check(a.shape contentEquals b.shape) { "Incompatible shapes ${a.shape.toList()} and ${b.shape.toList()} " } - -internal fun checkTranspose(dim: Int, i: Int, j: Int): Unit = +internal fun checkTranspose(dim: Int, i: Int, j: Int) = check((i < dim) and (j < dim)) { "Cannot transpose $i to $j for a tensor of dim $dim" } -internal fun checkView(a: TensorStructure, shape: IntArray): Unit = +internal fun checkView(a: TensorStructure, shape: IntArray) = check(a.shape.reduce(Int::times) == shape.reduce(Int::times)) - -internal fun checkSquareMatrix(shape: IntArray): Unit { +internal fun checkSquareMatrix(shape: IntArray) { val n = shape.size check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n instead" @@ -48,14 +45,12 @@ internal fun checkSquareMatrix(shape: IntArray): Unit { internal fun DoubleTensorAlgebra.checkSymmetric( tensor: TensorStructure, epsilon: Double = 1e-6 -): Unit = +) = check(tensor.eq(tensor.transpose(), epsilon)) { "Tensor is not symmetric about the last 2 dimensions at precision $epsilon" } -internal fun DoubleLinearOpsTensorAlgebra.checkPositiveDefinite( - tensor: DoubleTensor, epsilon: Double = 1e-6 -): Unit { +internal fun DoubleLinearOpsTensorAlgebra.checkPositiveDefinite(tensor: DoubleTensor, epsilon: Double = 1e-6) { checkSymmetric(tensor, epsilon) for (mat in tensor.matrixSequence()) check(mat.asTensor().detLU().value() > 0.0) { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt index e54cc4d26..ba8b823c9 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt @@ -34,18 +34,6 @@ internal fun BufferedTensor.matrixSequence(): Sequence> } } -internal inline fun BufferedTensor.forEachVector(vectorAction: (BufferedTensor) -> Unit) { - for (vector in vectorSequence()) { - vectorAction(vector) - } -} - -internal inline fun BufferedTensor.forEachMatrix(matrixAction: (BufferedTensor) -> Unit) { - for (matrix in matrixSequence()) { - matrixAction(matrix) - } -} - internal fun dotHelper( a: MutableStructure2D, b: MutableStructure2D, diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt index 88b9c6c5c..0211342bb 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt @@ -14,7 +14,6 @@ internal fun Buffer.array(): IntArray = when (this) { else -> this.toIntArray() } - /** * Returns a reference to [DoubleArray] containing all of the elements of this [Buffer] or copy the data. */ @@ -31,7 +30,7 @@ internal fun getRandomNormals(n: Int, seed: Long): DoubleArray { internal fun getRandomUnitVector(n: Int, seed: Long): DoubleArray { val unnorm = getRandomNormals(n, seed) - val norm = sqrt(unnorm.map { it * it }.sum()) + val norm = sqrt(unnorm.sumOf { it * it }) return unnorm.map { it / norm }.toDoubleArray() } @@ -45,23 +44,33 @@ internal fun minusIndexFrom(n: Int, i: Int): Int = if (i >= 0) i else { internal fun BufferedTensor.minusIndex(i: Int): Int = minusIndexFrom(this.dimension, i) -internal fun format(value: Double, digits: Int = 4): String { - val ten = 10.0 - val approxOrder = if (value == 0.0) 0 else ceil(log10(abs(value))).toInt() - val order = if ( - ((value % ten) == 0.0) or - (value == 1.0) or - ((1 / value) % ten == 0.0) - ) approxOrder else approxOrder - 1 - val lead = value / ten.pow(order) - val leadDisplay = round(lead * ten.pow(digits)) / ten.pow(digits) - val orderDisplay = if (order == 0) "" else if (order > 0) "E+$order" else "E$order" - val valueDisplay = "$leadDisplay$orderDisplay" - val res = if (value < 0.0) valueDisplay else " $valueDisplay" - +internal fun format(value: Double, digits: Int = 4): String = buildString { + val res = buildString { + val ten = 10.0 + val approxOrder = if (value == 0.0) 0 else ceil(log10(abs(value))).toInt() + val order = if ( + ((value % ten) == 0.0) || + (value == 1.0) || + ((1 / value) % ten == 0.0) + ) approxOrder else approxOrder - 1 + val lead = value / ten.pow(order) + if (value >= 0.0) append(' ') + append(round(lead * ten.pow(digits)) / ten.pow(digits)) + when { + order == 0 -> Unit + order > 0 -> { + append("e+") + append(order) + } + else -> { + append('e') + append(order) + } + } + } val fLength = digits + 6 - val endSpace = " ".repeat(fLength - res.length) - return "$res$endSpace" + append(res) + repeat(fLength - res.length) { append(' ') } } internal fun DoubleTensor.toPrettyString(): String = buildString { From 48d86fac5620b5e663a5dc62618f4f2869e86521 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Sat, 1 May 2021 19:55:48 +0100 Subject: [PATCH 146/178] invoke refactor --- .../core/algebras/TensorLinearStructure.kt | 6 ----- .../kscience/kmath/tensors/core/linUtils.kt | 2 +- .../kmath/tensors/core/TestBroadcasting.kt | 10 ++++---- .../core/TestDoubleAnalyticTensorAlgebra.kt | 2 +- .../core/TestDoubleLinearOpsAlgebra.kt | 24 +++++++++---------- .../kmath/tensors/core/TestDoubleTensor.kt | 6 ++--- .../tensors/core/TestDoubleTensorAlgebra.kt | 18 +++++++------- 7 files changed, 31 insertions(+), 37 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt index 08aab5175..5fbc7390f 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt @@ -9,12 +9,6 @@ import space.kscience.kmath.nd.Strides 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 { val nDim = shape.size val res = IntArray(nDim) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt index ba8b823c9..8adbfad39 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt @@ -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) { qM[i, j] = vv[i] / r[j, j] } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt index 1070a1115..1564b85c9 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt @@ -9,7 +9,7 @@ import kotlin.test.assertTrue internal class TestBroadcasting { @Test - fun broadcastShapes() = DoubleTensorAlgebra.invoke { + fun broadcastShapes() = DoubleTensorAlgebra { assertTrue( broadcastShapes( intArrayOf(2, 3), intArrayOf(1, 3), intArrayOf(1, 1, 1) @@ -24,7 +24,7 @@ internal class TestBroadcasting { } @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 tensor2 = fromArray(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) @@ -34,7 +34,7 @@ internal class TestBroadcasting { } @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 tensor2 = fromArray(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) val tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) @@ -51,7 +51,7 @@ internal class TestBroadcasting { } @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 tensor2 = fromArray(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) val tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) @@ -68,7 +68,7 @@ internal class TestBroadcasting { } @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 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)) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt index 66959a0de..835b8a08a 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt @@ -27,7 +27,7 @@ internal class TestDoubleAnalyticTensorAlgebra { } @Test - fun testExp() = DoubleAnalyticTensorAlgebra.invoke { + fun testExp() = DoubleAnalyticTensorAlgebra { tensor.exp().let { assertTrue { shape contentEquals it.shape } assertTrue { buffer.fmap(::exp).epsEqual(it.mutableBuffer.array())} diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 6689e893a..65070af7f 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -10,7 +10,7 @@ import kotlin.test.assertTrue internal class TestDoubleLinearOpsTensorAlgebra { @Test - fun testDetLU() = DoubleLinearOpsTensorAlgebra.invoke { + fun testDetLU() = DoubleLinearOpsTensorAlgebra { val tensor = fromArray( intArrayOf(2, 2, 2), doubleArrayOf( @@ -35,7 +35,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testDet() = DoubleLinearOpsTensorAlgebra.invoke { + fun testDet() = DoubleLinearOpsTensorAlgebra { val expectedValue = 0.019827417 val m = fromArray( intArrayOf(3, 3), doubleArrayOf( @@ -49,7 +49,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testDetSingle() = DoubleLinearOpsTensorAlgebra.invoke { + fun testDetSingle() = DoubleLinearOpsTensorAlgebra { val expectedValue = 48.151623 val m = fromArray( intArrayOf(1, 1), doubleArrayOf( @@ -61,7 +61,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testInvLU() = DoubleLinearOpsTensorAlgebra.invoke { + fun testInvLU() = DoubleLinearOpsTensorAlgebra { val tensor = fromArray( intArrayOf(2, 2, 2), doubleArrayOf( @@ -86,14 +86,14 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testScalarProduct() = DoubleLinearOpsTensorAlgebra.invoke { + fun testScalarProduct() = DoubleLinearOpsTensorAlgebra { val a = fromArray(intArrayOf(3), doubleArrayOf(1.8, 2.5, 6.8)) val b = fromArray(intArrayOf(3), doubleArrayOf(5.5, 2.6, 6.4)) assertEquals(a.dot(b).value(), 59.92) } @Test - fun testQR() = DoubleLinearOpsTensorAlgebra.invoke { + fun testQR() = DoubleLinearOpsTensorAlgebra { val shape = intArrayOf(2, 2, 2) val buffer = doubleArrayOf( 1.0, 3.0, @@ -114,7 +114,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testLU() = DoubleLinearOpsTensorAlgebra.invoke { + fun testLU() = DoubleLinearOpsTensorAlgebra { val shape = intArrayOf(2, 2, 2) val buffer = doubleArrayOf( 1.0, 3.0, @@ -134,7 +134,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testCholesky() = DoubleLinearOpsTensorAlgebra.invoke { + fun testCholesky() = DoubleLinearOpsTensorAlgebra { val tensor = randomNormal(intArrayOf(2, 5, 5), 0) val sigma = (tensor dot tensor.transpose()) + diagonalEmbedding( fromArray(intArrayOf(2, 5), DoubleArray(10) { 0.1 }) @@ -145,7 +145,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @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 res = svd1d(tensor2) @@ -156,13 +156,13 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @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, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0))) } @Test - fun testBatchedSVD() = DoubleLinearOpsTensorAlgebra.invoke { + fun testBatchedSVD() = DoubleLinearOpsTensorAlgebra { val tensor = randomNormal(intArrayOf(2, 5, 3), 0) val (tensorU, tensorS, tensorV) = tensor.svd() val tensorSVD = tensorU dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) @@ -170,7 +170,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testBatchedSymEig() = DoubleLinearOpsTensorAlgebra.invoke { + fun testBatchedSymEig() = DoubleLinearOpsTensorAlgebra { val tensor = randomNormal(shape = intArrayOf(2, 3, 3), 0) val tensorSigma = tensor + tensor.transpose() val (tensorS, tensorV) = tensorSigma.symEig() diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index 333a7bdec..ed5f8e780 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -15,14 +15,14 @@ import kotlin.test.assertTrue internal class TestDoubleTensor { @Test - fun valueTest() = DoubleTensorAlgebra.invoke { + fun valueTest() = DoubleTensorAlgebra { val value = 12.5 val tensor = fromArray(intArrayOf(1), doubleArrayOf(value)) assertEquals(tensor.value(), value) } @Test - fun stridesTest() = DoubleTensorAlgebra.invoke { + fun stridesTest() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4)) assertEquals(tensor[intArrayOf(0, 1)], 5.8) assertTrue( @@ -31,7 +31,7 @@ internal class TestDoubleTensor { } @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 matrix = tensor[0].as2D() assertEquals(matrix[0, 1], 5.8) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index a0efa4573..df2d21b96 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -10,21 +10,21 @@ import kotlin.test.assertTrue internal class TestDoubleTensorAlgebra { @Test - fun doublePlus() = DoubleTensorAlgebra.invoke { + fun doublePlus() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(2), doubleArrayOf(1.0, 2.0)) val res = 10.0 + tensor assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(11.0, 12.0)) } @Test - fun doubleDiv() = DoubleTensorAlgebra.invoke { + fun doubleDiv() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(2), doubleArrayOf(2.0, 4.0)) val res = 2.0/tensor assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 0.5)) } @Test - fun divDouble() = DoubleTensorAlgebra.invoke { + fun divDouble() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(2), doubleArrayOf(10.0, 5.0)) val res = tensor / 2.5 assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(4.0, 2.0)) @@ -40,7 +40,7 @@ internal class TestDoubleTensorAlgebra { } @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 res = tensor.transpose(1, 0) @@ -49,7 +49,7 @@ internal class TestDoubleTensorAlgebra { } @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 res01 = tensor.transpose(0, 1) val res02 = tensor.transpose(-3, 2) @@ -65,7 +65,7 @@ internal class TestDoubleTensorAlgebra { } @Test - fun linearStructure() = DoubleTensorAlgebra.invoke { + fun linearStructure() = DoubleTensorAlgebra { val shape = intArrayOf(3) val tensorA = full(value = -4.5, shape = shape) val tensorB = full(value = 10.9, shape = shape) @@ -97,7 +97,7 @@ internal class TestDoubleTensorAlgebra { } @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 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)) @@ -133,7 +133,7 @@ internal class TestDoubleTensorAlgebra { } @Test - fun diagonalEmbedding() = DoubleTensorAlgebra.invoke { + fun diagonalEmbedding() = DoubleTensorAlgebra { 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 tensor3 = zeros(intArrayOf(2, 3, 4, 5)) @@ -166,7 +166,7 @@ internal class TestDoubleTensorAlgebra { } @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 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)) From 5aaba0dae443605b3dedb4bc4ee7733922b8e41f Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Sun, 2 May 2021 16:19:05 +0100 Subject: [PATCH 147/178] TensorStructure to Tensor --- .../tensors/api/AnalyticTensorAlgebra.kt | 36 ++++----- .../tensors/api/LinearOpsTensorAlgebra.kt | 16 ++-- .../api/{TensorStructure.kt => Tensor.kt} | 2 +- .../kmath/tensors/api/TensorAlgebra.kt | 52 ++++++------ .../api/TensorPartialDivisionAlgebra.kt | 12 +-- .../kmath/tensors/core/BufferedTensor.kt | 16 ++-- .../algebras/BroadcastDoubleTensorAlgebra.kt | 18 ++--- .../algebras/DoubleAnalyticTensorAlgebra.kt | 36 ++++----- .../algebras/DoubleLinearOpsTensorAlgebra.kt | 36 ++++----- .../core/algebras/DoubleTensorAlgebra.kt | 80 +++++++++---------- .../kscience/kmath/tensors/core/checks.kt | 8 +- 11 files changed, 156 insertions(+), 156 deletions(-) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/{TensorStructure.kt => Tensor.kt} (60%) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt index 5c92c56c4..cd13e0752 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.tensors.api /** - * Element-wise analytic operations on [TensorStructure]. + * Element-wise analytic operations on [Tensor]. * * @param T the type of items closed under analytic functions in the tensors. */ @@ -14,54 +14,54 @@ public interface AnalyticTensorAlgebra : TensorPartialDivisionAlgebra { //For information: https://pytorch.org/docs/stable/generated/torch.exp.html - public fun TensorStructure.exp(): TensorStructure + public fun Tensor.exp(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.log.html - public fun TensorStructure.log(): TensorStructure + public fun Tensor.log(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.sqrt.html - public fun TensorStructure.sqrt(): TensorStructure + public fun Tensor.sqrt(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.acos.html#torch.cos - public fun TensorStructure.cos(): TensorStructure + public fun Tensor.cos(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.acos.html#torch.acos - public fun TensorStructure.acos(): TensorStructure + public fun Tensor.acos(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.cosh - public fun TensorStructure.cosh(): TensorStructure + public fun Tensor.cosh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.acosh - public fun TensorStructure.acosh(): TensorStructure + public fun Tensor.acosh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sin - public fun TensorStructure.sin(): TensorStructure + public fun Tensor.sin(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asin - public fun TensorStructure.asin(): TensorStructure + public fun Tensor.asin(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sinh - public fun TensorStructure.sinh(): TensorStructure + public fun Tensor.sinh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asinh - public fun TensorStructure.asinh(): TensorStructure + public fun Tensor.asinh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.atan.html#torch.tan - public fun TensorStructure.tan(): TensorStructure + public fun Tensor.tan(): Tensor //https://pytorch.org/docs/stable/generated/torch.atan.html#torch.atan - public fun TensorStructure.atan(): TensorStructure + public fun Tensor.atan(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.tanh - public fun TensorStructure.tanh(): TensorStructure + public fun Tensor.tanh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.atanh - public fun TensorStructure.atanh(): TensorStructure + public fun Tensor.atanh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.ceil.html#torch.ceil - public fun TensorStructure.ceil(): TensorStructure + public fun Tensor.ceil(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.floor.html#torch.floor - public fun TensorStructure.floor(): TensorStructure + public fun Tensor.floor(): Tensor } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt index bcbb52a1b..527e5d386 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.tensors.api /** - * Common linear algebra operations. Operates on [TensorStructure]. + * Common linear algebra operations. Operates on [Tensor]. * * @param T the type of items closed under division in the tensors. */ @@ -19,7 +19,7 @@ public interface LinearOpsTensorAlgebra : * * @return the determinant. */ - public fun TensorStructure.det(): TensorStructure + public fun Tensor.det(): Tensor /** * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input. @@ -29,7 +29,7 @@ public interface LinearOpsTensorAlgebra : * * @return the multiplicative inverse of a matrix. */ - public fun TensorStructure.inv(): TensorStructure + public fun Tensor.inv(): Tensor /** * Cholesky decomposition. @@ -44,7 +44,7 @@ public interface LinearOpsTensorAlgebra : * * @return the batch of L matrices. */ - public fun TensorStructure.cholesky(): TensorStructure + public fun Tensor.cholesky(): Tensor /** * QR decomposition. @@ -57,7 +57,7 @@ public interface LinearOpsTensorAlgebra : * * @return pair of Q and R tensors. */ - public fun TensorStructure.qr(): Pair, TensorStructure> + public fun Tensor.qr(): Pair, Tensor> /** * LUP decomposition @@ -70,7 +70,7 @@ public interface LinearOpsTensorAlgebra : * * * @return triple of P, L and U tensors */ - public fun TensorStructure.lu(): Triple, TensorStructure, TensorStructure> + public fun Tensor.lu(): Triple, Tensor, Tensor> /** * Singular Value Decomposition. @@ -83,7 +83,7 @@ public interface LinearOpsTensorAlgebra : * * @return the determinant. */ - public fun TensorStructure.svd(): Triple, TensorStructure, TensorStructure> + public fun Tensor.svd(): Triple, Tensor, Tensor> /** * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, @@ -92,6 +92,6 @@ public interface LinearOpsTensorAlgebra : * * @return a pair (eigenvalues, eigenvectors) */ - public fun TensorStructure.symEig(): Pair, TensorStructure> + public fun Tensor.symEig(): Pair, Tensor> } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt similarity index 60% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorStructure.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt index edecd6383..179787684 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt @@ -2,4 +2,4 @@ package space.kscience.kmath.tensors.api import space.kscience.kmath.nd.MutableStructureND -public typealias TensorStructure = MutableStructureND +public typealias Tensor = MutableStructureND diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 96d6985d8..b9c707c0b 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -8,19 +8,19 @@ package space.kscience.kmath.tensors.api import space.kscience.kmath.operations.Algebra /** - * Algebra over a ring on [TensorStructure]. + * Algebra over a ring on [Tensor]. * For more information: https://proofwiki.org/wiki/Definition:Algebra_over_Ring * * @param T the type of items in the tensors. */ -public interface TensorAlgebra: Algebra> { +public interface TensorAlgebra: Algebra> { /** * Returns a single tensor value of unit dimension. The tensor shape must be equal to [1]. * * @return the value of a scalar tensor. */ - public fun TensorStructure.value(): T + public fun Tensor.value(): T /** * Each element of the tensor [other] is added to this value. @@ -29,7 +29,7 @@ public interface TensorAlgebra: Algebra> { * @param other tensor to be added. * @return the sum of this value and tensor [other]. */ - public operator fun T.plus(other: TensorStructure): TensorStructure + public operator fun T.plus(other: Tensor): Tensor /** * Adds the scalar [value] to each element of this tensor and returns a new resulting tensor. @@ -37,7 +37,7 @@ public interface TensorAlgebra: Algebra> { * @param value the number to be added to each element of this tensor. * @return the sum of this tensor and [value]. */ - public operator fun TensorStructure.plus(value: T): TensorStructure + public operator fun Tensor.plus(value: T): Tensor /** * Each element of the tensor [other] is added to each element of this tensor. @@ -46,21 +46,21 @@ public interface TensorAlgebra: Algebra> { * @param other tensor to be added. * @return the sum of this tensor and [other]. */ - public operator fun TensorStructure.plus(other: TensorStructure): TensorStructure + public operator fun Tensor.plus(other: Tensor): Tensor /** * Adds the scalar [value] to each element of this tensor. * * @param value the number to be added to each element of this tensor. */ - public operator fun TensorStructure.plusAssign(value: T): Unit + public operator fun Tensor.plusAssign(value: T): Unit /** * Each element of the tensor [other] is added to each element of this tensor. * * @param other tensor to be added. */ - public operator fun TensorStructure.plusAssign(other: TensorStructure): Unit + public operator fun Tensor.plusAssign(other: Tensor): Unit /** @@ -70,7 +70,7 @@ public interface TensorAlgebra: Algebra> { * @param other tensor to be subtracted. * @return the difference between this value and tensor [other]. */ - public operator fun T.minus(other: TensorStructure): TensorStructure + public operator fun T.minus(other: Tensor): Tensor /** * Subtracts the scalar [value] from each element of this tensor and returns a new resulting tensor. @@ -78,7 +78,7 @@ public interface TensorAlgebra: Algebra> { * @param value the number to be subtracted from each element of this tensor. * @return the difference between this tensor and [value]. */ - public operator fun TensorStructure.minus(value: T): TensorStructure + public operator fun Tensor.minus(value: T): Tensor /** * Each element of the tensor [other] is subtracted from each element of this tensor. @@ -87,21 +87,21 @@ public interface TensorAlgebra: Algebra> { * @param other tensor to be subtracted. * @return the difference between this tensor and [other]. */ - public operator fun TensorStructure.minus(other: TensorStructure): TensorStructure + public operator fun Tensor.minus(other: Tensor): Tensor /** * Subtracts the scalar [value] from each element of this tensor. * * @param value the number to be subtracted from each element of this tensor. */ - public operator fun TensorStructure.minusAssign(value: T): Unit + public operator fun Tensor.minusAssign(value: T): Unit /** * Each element of the tensor [other] is subtracted from each element of this tensor. * * @param other tensor to be subtracted. */ - public operator fun TensorStructure.minusAssign(other: TensorStructure): Unit + public operator fun Tensor.minusAssign(other: Tensor): Unit /** @@ -111,7 +111,7 @@ public interface TensorAlgebra: Algebra> { * @param other tensor to be multiplied. * @return the product of this value and tensor [other]. */ - public operator fun T.times(other: TensorStructure): TensorStructure + public operator fun T.times(other: Tensor): Tensor /** * Multiplies the scalar [value] by each element of this tensor and returns a new resulting tensor. @@ -119,7 +119,7 @@ public interface TensorAlgebra: Algebra> { * @param value the number to be multiplied by each element of this tensor. * @return the product of this tensor and [value]. */ - public operator fun TensorStructure.times(value: T): TensorStructure + public operator fun Tensor.times(value: T): Tensor /** * Each element of the tensor [other] is multiplied by each element of this tensor. @@ -128,28 +128,28 @@ public interface TensorAlgebra: Algebra> { * @param other tensor to be multiplied. * @return the product of this tensor and [other]. */ - public operator fun TensorStructure.times(other: TensorStructure): TensorStructure + public operator fun Tensor.times(other: Tensor): Tensor /** * Multiplies the scalar [value] by each element of this tensor. * * @param value the number to be multiplied by each element of this tensor. */ - public operator fun TensorStructure.timesAssign(value: T): Unit + public operator fun Tensor.timesAssign(value: T): Unit /** * Each element of the tensor [other] is multiplied by each element of this tensor. * * @param other tensor to be multiplied. */ - public operator fun TensorStructure.timesAssign(other: TensorStructure): Unit + public operator fun Tensor.timesAssign(other: Tensor): Unit /** * Numerical negative, element-wise. * * @return tensor negation of the original tensor. */ - public operator fun TensorStructure.unaryMinus(): TensorStructure + public operator fun Tensor.unaryMinus(): Tensor /** * Returns the tensor at index i @@ -158,7 +158,7 @@ public interface TensorAlgebra: Algebra> { * @param i index of the extractable tensor * @return subtensor of the original tensor with index [i] */ - public operator fun TensorStructure.get(i: Int): TensorStructure + public operator fun Tensor.get(i: Int): Tensor /** * Returns a tensor that is a transposed version of this tensor. The given dimensions [i] and [j] are swapped. @@ -168,7 +168,7 @@ public interface TensorAlgebra: Algebra> { * @param j the second dimension to be transposed * @return transposed tensor */ - public fun TensorStructure.transpose(i: Int = -2, j: Int = -1): TensorStructure + public fun Tensor.transpose(i: Int = -2, j: Int = -1): Tensor /** * Returns a new tensor with the same data as the self tensor but of a different shape. @@ -178,7 +178,7 @@ public interface TensorAlgebra: Algebra> { * @param shape the desired size * @return tensor with new shape */ - public fun TensorStructure.view(shape: IntArray): TensorStructure + public fun Tensor.view(shape: IntArray): Tensor /** * View this tensor as the same size as [other]. @@ -188,7 +188,7 @@ public interface TensorAlgebra: Algebra> { * @param other the result tensor has the same size as other. * @return the result tensor with the same size as other. */ - public fun TensorStructure.viewAs(other: TensorStructure): TensorStructure + public fun Tensor.viewAs(other: Tensor): Tensor /** * Matrix product of two tensors. @@ -219,7 +219,7 @@ public interface TensorAlgebra: Algebra> { * @param other tensor to be multiplied * @return mathematical product of two tensors */ - public infix fun TensorStructure.dot(other: TensorStructure): TensorStructure + public infix fun Tensor.dot(other: Tensor): Tensor /** * Creates a tensor whose diagonals of certain 2D planes (specified by [dim1] and [dim2]) @@ -245,10 +245,10 @@ public interface TensorAlgebra: Algebra> { * are filled by [diagonalEntries] */ public fun diagonalEmbedding( - diagonalEntries: TensorStructure, + diagonalEntries: Tensor, offset: Int = 0, dim1: Int = -2, dim2: Int = -1 - ): TensorStructure + ): Tensor } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt index eccc6fa0d..921157963 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.tensors.api /** - * Algebra over a field with partial division on [TensorStructure]. + * Algebra over a field with partial division on [Tensor]. * For more information: https://proofwiki.org/wiki/Definition:Division_Algebra * * @param T the type of items closed under division in the tensors. @@ -21,7 +21,7 @@ public interface TensorPartialDivisionAlgebra : * @param other tensor to divide by. * @return the division of this value by the tensor [other]. */ - public operator fun T.div(other: TensorStructure): TensorStructure + public operator fun T.div(other: Tensor): Tensor /** * Divide by the scalar [value] each element of this tensor returns a new resulting tensor. @@ -29,7 +29,7 @@ public interface TensorPartialDivisionAlgebra : * @param value the number to divide by each element of this tensor. * @return the division of this tensor by the [value]. */ - public operator fun TensorStructure.div(value: T): TensorStructure + public operator fun Tensor.div(value: T): Tensor /** * Each element of the tensor [other] is divided by each element of this tensor. @@ -38,19 +38,19 @@ public interface TensorPartialDivisionAlgebra : * @param other tensor to be divided by. * @return the division of this tensor by [other]. */ - public operator fun TensorStructure.div(other: TensorStructure): TensorStructure + public operator fun Tensor.div(other: Tensor): Tensor /** * Divides by the scalar [value] each element of this tensor. * * @param value the number to divide by each element of this tensor. */ - public operator fun TensorStructure.divAssign(value: T) + public operator fun Tensor.divAssign(value: T) /** * Each element of this tensor is divided by each element of the [other] tensor. * * @param other tensor to be divide by. */ - public operator fun TensorStructure.divAssign(other: TensorStructure) + public operator fun Tensor.divAssign(other: Tensor) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 9541a97f9..d0882efb8 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -2,7 +2,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.nd.MutableBufferND import space.kscience.kmath.structures.* -import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.algebras.TensorLinearStructure @@ -10,7 +10,7 @@ public open class BufferedTensor( override val shape: IntArray, internal val mutableBuffer: MutableBuffer, internal val bufferStart: Int -) : TensorStructure { +) : Tensor { public val linearStructure: TensorLinearStructure get() = TensorLinearStructure(shape) @@ -53,33 +53,33 @@ internal fun BufferedTensor.asTensor(): IntTensor = internal fun BufferedTensor.asTensor(): DoubleTensor = DoubleTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) -internal fun TensorStructure.copyToBufferedTensor(): BufferedTensor = +internal fun Tensor.copyToBufferedTensor(): BufferedTensor = BufferedTensor( this.shape, TensorLinearStructure(this.shape).indices().map(this::get).toMutableList().asMutableBuffer(), 0 ) -internal fun TensorStructure.toBufferedTensor(): BufferedTensor = when (this) { +internal fun Tensor.toBufferedTensor(): BufferedTensor = when (this) { is BufferedTensor -> this is MutableBufferND -> if (this.strides.strides contentEquals TensorLinearStructure(this.shape).strides) BufferedTensor(this.shape, this.mutableBuffer, 0) else this.copyToBufferedTensor() else -> this.copyToBufferedTensor() } -internal val TensorStructure.tensor: DoubleTensor +internal val Tensor.tensor: DoubleTensor get() = when (this) { is DoubleTensor -> this else -> this.toBufferedTensor().asTensor() } -internal val TensorStructure.tensor: IntTensor +internal val Tensor.tensor: IntTensor get() = when (this) { is IntTensor -> this else -> this.toBufferedTensor().asTensor() } -public fun TensorStructure.toDoubleTensor(): DoubleTensor = this.tensor -public fun TensorStructure.toIntTensor(): IntTensor = this.tensor +public fun Tensor.toDoubleTensor(): DoubleTensor = this.tensor +public fun Tensor.toIntTensor(): IntTensor = this.tensor public fun Array.toDoubleTensor(): DoubleTensor { val n = size diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt index 9b97d5ef2..873ec9027 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.tensors.core.algebras -import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.* import space.kscience.kmath.tensors.core.broadcastTensors import space.kscience.kmath.tensors.core.broadcastTo @@ -16,7 +16,7 @@ import space.kscience.kmath.tensors.core.broadcastTo */ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { - override fun TensorStructure.plus(other: TensorStructure): DoubleTensor { + override fun Tensor.plus(other: Tensor): DoubleTensor { val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] @@ -26,7 +26,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun TensorStructure.plusAssign(other: TensorStructure) { + override fun Tensor.plusAssign(other: Tensor) { val newOther = broadcastTo(other.tensor, tensor.shape) for (i in 0 until tensor.linearStructure.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] += @@ -34,7 +34,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { } } - override fun TensorStructure.minus(other: TensorStructure): DoubleTensor { + override fun Tensor.minus(other: Tensor): DoubleTensor { val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] @@ -44,7 +44,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun TensorStructure.minusAssign(other: TensorStructure) { + override fun Tensor.minusAssign(other: Tensor) { val newOther = broadcastTo(other.tensor, tensor.shape) for (i in 0 until tensor.linearStructure.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] -= @@ -52,7 +52,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { } } - override fun TensorStructure.times(other: TensorStructure): DoubleTensor { + override fun Tensor.times(other: Tensor): DoubleTensor { val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] @@ -63,7 +63,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun TensorStructure.timesAssign(other: TensorStructure) { + override fun Tensor.timesAssign(other: Tensor) { val newOther = broadcastTo(other.tensor, tensor.shape) for (i in 0 until tensor.linearStructure.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] *= @@ -71,7 +71,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { } } - override fun TensorStructure.div(other: TensorStructure): DoubleTensor { + override fun Tensor.div(other: Tensor): DoubleTensor { val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] @@ -82,7 +82,7 @@ public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { return DoubleTensor(newThis.shape, resBuffer) } - override fun TensorStructure.divAssign(other: TensorStructure) { + override fun Tensor.divAssign(other: Tensor) { val newOther = broadcastTo(other.tensor, tensor.shape) for (i in 0 until tensor.linearStructure.linearSize) { tensor.mutableBuffer.array()[tensor.bufferStart + i] /= diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt index 4a942df84..9aa6f093e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.tensors.core.algebras import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra -import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.tensor import kotlin.math.* @@ -14,38 +14,38 @@ import kotlin.math.* public object DoubleAnalyticTensorAlgebra : AnalyticTensorAlgebra, DoubleTensorAlgebra() { - override fun TensorStructure.exp(): DoubleTensor = tensor.map(::exp) + override fun Tensor.exp(): DoubleTensor = tensor.map(::exp) - override fun TensorStructure.log(): DoubleTensor = tensor.map(::ln) + override fun Tensor.log(): DoubleTensor = tensor.map(::ln) - override fun TensorStructure.sqrt(): DoubleTensor = tensor.map(::sqrt) + override fun Tensor.sqrt(): DoubleTensor = tensor.map(::sqrt) - override fun TensorStructure.cos(): DoubleTensor = tensor.map(::cos) + override fun Tensor.cos(): DoubleTensor = tensor.map(::cos) - override fun TensorStructure.acos(): DoubleTensor = tensor.map(::acos) + override fun Tensor.acos(): DoubleTensor = tensor.map(::acos) - override fun TensorStructure.cosh(): DoubleTensor = tensor.map(::cosh) + override fun Tensor.cosh(): DoubleTensor = tensor.map(::cosh) - override fun TensorStructure.acosh(): DoubleTensor = tensor.map(::acosh) + override fun Tensor.acosh(): DoubleTensor = tensor.map(::acosh) - override fun TensorStructure.sin(): DoubleTensor = tensor.map(::sin) + override fun Tensor.sin(): DoubleTensor = tensor.map(::sin) - override fun TensorStructure.asin(): DoubleTensor = tensor.map(::asin) + override fun Tensor.asin(): DoubleTensor = tensor.map(::asin) - override fun TensorStructure.sinh(): DoubleTensor = tensor.map(::sinh) + override fun Tensor.sinh(): DoubleTensor = tensor.map(::sinh) - override fun TensorStructure.asinh(): DoubleTensor = tensor.map(::asinh) + override fun Tensor.asinh(): DoubleTensor = tensor.map(::asinh) - override fun TensorStructure.tan(): DoubleTensor = tensor.map(::tan) + override fun Tensor.tan(): DoubleTensor = tensor.map(::tan) - override fun TensorStructure.atan(): DoubleTensor = tensor.map(::atan) + override fun Tensor.atan(): DoubleTensor = tensor.map(::atan) - override fun TensorStructure.tanh(): DoubleTensor = tensor.map(::tanh) + override fun Tensor.tanh(): DoubleTensor = tensor.map(::tanh) - override fun TensorStructure.atanh(): DoubleTensor = tensor.map(::atanh) + override fun Tensor.atanh(): DoubleTensor = tensor.map(::atanh) - override fun TensorStructure.ceil(): DoubleTensor = tensor.map(::ceil) + override fun Tensor.ceil(): DoubleTensor = tensor.map(::ceil) - override fun TensorStructure.floor(): DoubleTensor = tensor.map(::floor) + override fun Tensor.floor(): DoubleTensor = tensor.map(::floor) } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt index dd5ad5a61..89345e315 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt @@ -8,7 +8,7 @@ package space.kscience.kmath.tensors.core.algebras import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D -import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.* import space.kscience.kmath.tensors.core.checkSquareMatrix import space.kscience.kmath.tensors.core.choleskyHelper @@ -25,19 +25,19 @@ public object DoubleLinearOpsTensorAlgebra : LinearOpsTensorAlgebra, DoubleTensorAlgebra() { - override fun TensorStructure.inv(): DoubleTensor = invLU(1e-9) + override fun Tensor.inv(): DoubleTensor = invLU(1e-9) - override fun TensorStructure.det(): DoubleTensor = detLU(1e-9) + override fun Tensor.det(): DoubleTensor = detLU(1e-9) - public fun TensorStructure.luFactor(epsilon: Double): Pair = + public fun Tensor.luFactor(epsilon: Double): Pair = computeLU(tensor, epsilon) ?: throw IllegalArgumentException("Tensor contains matrices which are singular at precision $epsilon") - public fun TensorStructure.luFactor(): Pair = luFactor(1e-9) + public fun Tensor.luFactor(): Pair = luFactor(1e-9) public fun luPivot( - luTensor: TensorStructure, - pivotsTensor: TensorStructure + luTensor: Tensor, + pivotsTensor: Tensor ): Triple { checkSquareMatrix(luTensor.shape) check( @@ -66,7 +66,7 @@ public object DoubleLinearOpsTensorAlgebra : return Triple(pTensor, lTensor, uTensor) } - public fun TensorStructure.cholesky(epsilon: Double): DoubleTensor { + public fun Tensor.cholesky(epsilon: Double): DoubleTensor { checkSquareMatrix(shape) checkPositiveDefinite(tensor, epsilon) @@ -79,9 +79,9 @@ public object DoubleLinearOpsTensorAlgebra : return lTensor } - override fun TensorStructure.cholesky(): DoubleTensor = cholesky(1e-6) + override fun Tensor.cholesky(): DoubleTensor = cholesky(1e-6) - override fun TensorStructure.qr(): Pair { + override fun Tensor.qr(): Pair { checkSquareMatrix(shape) val qTensor = zeroesLike() val rTensor = zeroesLike() @@ -95,10 +95,10 @@ public object DoubleLinearOpsTensorAlgebra : return qTensor to rTensor } - override fun TensorStructure.svd(): Triple = + override fun Tensor.svd(): Triple = svd(epsilon = 1e-10) - public fun TensorStructure.svd(epsilon: Double): Triple { + public fun Tensor.svd(epsilon: Double): Triple { val size = tensor.linearStructure.dim val commonShape = tensor.shape.sliceArray(0 until size - 2) val (n, m) = tensor.shape.sliceArray(size - 2 until size) @@ -122,11 +122,11 @@ public object DoubleLinearOpsTensorAlgebra : return Triple(uTensor.transpose(), sTensor, vTensor.transpose()) } - override fun TensorStructure.symEig(): Pair = + override fun Tensor.symEig(): Pair = symEig(epsilon = 1e-15) //For information: http://hua-zhou.github.io/teaching/biostatm280-2017spring/slides/16-eigsvd/eigsvd.html - public fun TensorStructure.symEig(epsilon: Double): Pair { + public fun Tensor.symEig(epsilon: Double): Pair { checkSymmetric(tensor, epsilon) val (u, s, v) = tensor.svd(epsilon) val shp = s.shape + intArrayOf(1) @@ -139,7 +139,7 @@ public object DoubleLinearOpsTensorAlgebra : return eig to v } - public fun TensorStructure.detLU(epsilon: Double = 1e-9): DoubleTensor { + public fun Tensor.detLU(epsilon: Double = 1e-9): DoubleTensor { checkSquareMatrix(tensor.shape) val luTensor = tensor.copy() @@ -164,7 +164,7 @@ public object DoubleLinearOpsTensorAlgebra : return detTensor } - public fun TensorStructure.invLU(epsilon: Double = 1e-9): DoubleTensor { + public fun Tensor.invLU(epsilon: Double = 1e-9): DoubleTensor { val (luTensor, pivotsTensor) = luFactor(epsilon) val invTensor = luTensor.zeroesLike() @@ -177,11 +177,11 @@ public object DoubleLinearOpsTensorAlgebra : return invTensor } - public fun TensorStructure.lu(epsilon: Double = 1e-9): Triple { + public fun Tensor.lu(epsilon: Double = 1e-9): Triple { val (lu, pivots) = this.luFactor(epsilon) return luPivot(lu, pivots) } - override fun TensorStructure.lu(): Triple = lu(1e-9) + override fun Tensor.lu(): Triple = lu(1e-9) } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index d3e8bf175..4009f7b45 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.tensors.core.algebras import space.kscience.kmath.nd.as2D import space.kscience.kmath.tensors.api.TensorPartialDivisionAlgebra -import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.* import space.kscience.kmath.tensors.core.broadcastOuterTensors import space.kscience.kmath.tensors.core.checkBufferShapeConsistency @@ -25,7 +25,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { public companion object : DoubleTensorAlgebra() - override fun TensorStructure.value(): Double { + override fun Tensor.value(): Double { check(tensor.shape contentEquals intArrayOf(1)) { "Inconsistent value for tensor of shape ${shape.toList()}" } @@ -39,7 +39,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return DoubleTensor(shape, buffer, 0) } - override operator fun TensorStructure.get(i: Int): DoubleTensor { + override operator fun Tensor.get(i: Int): DoubleTensor { val lastShape = tensor.shape.drop(1).toIntArray() val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) val newStart = newShape.reduce(Int::times) * i + tensor.bufferStart @@ -52,7 +52,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return DoubleTensor(shape, buffer) } - public fun TensorStructure.fullLike(value: Double): DoubleTensor { + public fun Tensor.fullLike(value: Double): DoubleTensor { val shape = tensor.shape val buffer = DoubleArray(tensor.numElements) { value } return DoubleTensor(shape, buffer) @@ -60,11 +60,11 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { public fun zeros(shape: IntArray): DoubleTensor = full(0.0, shape) - public fun TensorStructure.zeroesLike(): DoubleTensor = tensor.fullLike(0.0) + public fun Tensor.zeroesLike(): DoubleTensor = tensor.fullLike(0.0) public fun ones(shape: IntArray): DoubleTensor = full(1.0, shape) - public fun TensorStructure.onesLike(): DoubleTensor = tensor.fullLike(1.0) + public fun Tensor.onesLike(): DoubleTensor = tensor.fullLike(1.0) public fun eye(n: Int): DoubleTensor { val shape = intArrayOf(n, n) @@ -76,20 +76,20 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return res } - public fun TensorStructure.copy(): DoubleTensor { + public fun Tensor.copy(): DoubleTensor { return DoubleTensor(tensor.shape, tensor.mutableBuffer.array().copyOf(), tensor.bufferStart) } - override fun Double.plus(other: TensorStructure): DoubleTensor { + override fun Double.plus(other: Tensor): DoubleTensor { val resBuffer = DoubleArray(other.tensor.numElements) { i -> other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] + this } return DoubleTensor(other.shape, resBuffer) } - override fun TensorStructure.plus(value: Double): DoubleTensor = value + tensor + override fun Tensor.plus(value: Double): DoubleTensor = value + tensor - override fun TensorStructure.plus(other: TensorStructure): DoubleTensor { + override fun Tensor.plus(other: Tensor): DoubleTensor { checkShapesCompatible(tensor, other.tensor) val resBuffer = DoubleArray(tensor.numElements) { i -> tensor.mutableBuffer.array()[i] + other.tensor.mutableBuffer.array()[i] @@ -97,13 +97,13 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return DoubleTensor(tensor.shape, resBuffer) } - override fun TensorStructure.plusAssign(value: Double) { + override fun Tensor.plusAssign(value: Double) { for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] += value } } - override fun TensorStructure.plusAssign(other: TensorStructure) { + override fun Tensor.plusAssign(other: Tensor) { checkShapesCompatible(tensor, other.tensor) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] += @@ -111,21 +111,21 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { } } - override fun Double.minus(other: TensorStructure): DoubleTensor { + override fun Double.minus(other: Tensor): DoubleTensor { val resBuffer = DoubleArray(other.tensor.numElements) { i -> this - other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] } return DoubleTensor(other.shape, resBuffer) } - override fun TensorStructure.minus(value: Double): DoubleTensor { + override fun Tensor.minus(value: Double): DoubleTensor { val resBuffer = DoubleArray(tensor.numElements) { i -> tensor.mutableBuffer.array()[tensor.bufferStart + i] - value } return DoubleTensor(tensor.shape, resBuffer) } - override fun TensorStructure.minus(other: TensorStructure): DoubleTensor { + override fun Tensor.minus(other: Tensor): DoubleTensor { checkShapesCompatible(tensor, other) val resBuffer = DoubleArray(tensor.numElements) { i -> tensor.mutableBuffer.array()[i] - other.tensor.mutableBuffer.array()[i] @@ -133,13 +133,13 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return DoubleTensor(tensor.shape, resBuffer) } - override fun TensorStructure.minusAssign(value: Double) { + override fun Tensor.minusAssign(value: Double) { for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] -= value } } - override fun TensorStructure.minusAssign(other: TensorStructure) { + override fun Tensor.minusAssign(other: Tensor) { checkShapesCompatible(tensor, other) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] -= @@ -147,16 +147,16 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { } } - override fun Double.times(other: TensorStructure): DoubleTensor { + override fun Double.times(other: Tensor): DoubleTensor { val resBuffer = DoubleArray(other.tensor.numElements) { i -> other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] * this } return DoubleTensor(other.shape, resBuffer) } - override fun TensorStructure.times(value: Double): DoubleTensor = value * tensor + override fun Tensor.times(value: Double): DoubleTensor = value * tensor - override fun TensorStructure.times(other: TensorStructure): DoubleTensor { + override fun Tensor.times(other: Tensor): DoubleTensor { checkShapesCompatible(tensor, other) val resBuffer = DoubleArray(tensor.numElements) { i -> tensor.mutableBuffer.array()[tensor.bufferStart + i] * @@ -165,13 +165,13 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return DoubleTensor(tensor.shape, resBuffer) } - override fun TensorStructure.timesAssign(value: Double) { + override fun Tensor.timesAssign(value: Double) { for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] *= value } } - override fun TensorStructure.timesAssign(other: TensorStructure) { + override fun Tensor.timesAssign(other: Tensor) { checkShapesCompatible(tensor, other) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] *= @@ -179,21 +179,21 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { } } - override fun Double.div(other: TensorStructure): DoubleTensor { + override fun Double.div(other: Tensor): DoubleTensor { val resBuffer = DoubleArray(other.tensor.numElements) { i -> this / other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] } return DoubleTensor(other.shape, resBuffer) } - override fun TensorStructure.div(value: Double): DoubleTensor { + override fun Tensor.div(value: Double): DoubleTensor { val resBuffer = DoubleArray(tensor.numElements) { i -> tensor.mutableBuffer.array()[tensor.bufferStart + i] / value } return DoubleTensor(shape, resBuffer) } - override fun TensorStructure.div(other: TensorStructure): DoubleTensor { + override fun Tensor.div(other: Tensor): DoubleTensor { checkShapesCompatible(tensor, other) val resBuffer = DoubleArray(tensor.numElements) { i -> tensor.mutableBuffer.array()[other.tensor.bufferStart + i] / @@ -202,13 +202,13 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return DoubleTensor(tensor.shape, resBuffer) } - override fun TensorStructure.divAssign(value: Double) { + override fun Tensor.divAssign(value: Double) { for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] /= value } } - override fun TensorStructure.divAssign(other: TensorStructure) { + override fun Tensor.divAssign(other: Tensor) { checkShapesCompatible(tensor, other) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] /= @@ -216,14 +216,14 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { } } - override fun TensorStructure.unaryMinus(): DoubleTensor { + override fun Tensor.unaryMinus(): DoubleTensor { val resBuffer = DoubleArray(tensor.numElements) { i -> tensor.mutableBuffer.array()[tensor.bufferStart + i].unaryMinus() } return DoubleTensor(tensor.shape, resBuffer) } - override fun TensorStructure.transpose(i: Int, j: Int): DoubleTensor { + override fun Tensor.transpose(i: Int, j: Int): DoubleTensor { val ii = tensor.minusIndex(i) val jj = tensor.minusIndex(j) checkTranspose(tensor.dimension, ii, jj) @@ -248,16 +248,16 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { } - override fun TensorStructure.view(shape: IntArray): DoubleTensor { + override fun Tensor.view(shape: IntArray): DoubleTensor { checkView(tensor, shape) return DoubleTensor(shape, tensor.mutableBuffer.array(), tensor.bufferStart) } - override fun TensorStructure.viewAs(other: TensorStructure): DoubleTensor { + override fun Tensor.viewAs(other: Tensor): DoubleTensor { return tensor.view(other.shape) } - override infix fun TensorStructure.dot(other: TensorStructure): DoubleTensor { + override infix fun Tensor.dot(other: Tensor): DoubleTensor { if (tensor.shape.size == 1 && other.shape.size == 1) { return DoubleTensor(intArrayOf(1), doubleArrayOf(tensor.times(other).tensor.mutableBuffer.array().sum())) } @@ -309,7 +309,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return resTensor } - override fun diagonalEmbedding(diagonalEntries: TensorStructure, offset: Int, dim1: Int, dim2: Int): + override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): DoubleTensor { val n = diagonalEntries.shape.size val d1 = minusIndexFrom(n + 1, dim1) @@ -358,7 +358,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { } - public fun TensorStructure.map(transform: (Double) -> Double): DoubleTensor { + public fun Tensor.map(transform: (Double) -> Double): DoubleTensor { return DoubleTensor( tensor.shape, tensor.mutableBuffer.array().map { transform(it) }.toDoubleArray(), @@ -366,14 +366,14 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { ) } - public fun TensorStructure.eq(other: TensorStructure, epsilon: Double): Boolean { + public fun Tensor.eq(other: Tensor, epsilon: Double): Boolean { return tensor.eq(other) { x, y -> abs(x - y) < epsilon } } - public infix fun TensorStructure.eq(other: TensorStructure): Boolean = tensor.eq(other, 1e-5) + public infix fun Tensor.eq(other: Tensor): Boolean = tensor.eq(other, 1e-5) - private fun TensorStructure.eq( - other: TensorStructure, + private fun Tensor.eq( + other: Tensor, eqFunction: (Double, Double) -> Boolean ): Boolean { checkShapesCompatible(tensor, other) @@ -396,7 +396,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { public fun randomNormal(shape: IntArray, seed: Long = 0): DoubleTensor = DoubleTensor(shape, getRandomNormals(shape.reduce(Int::times), seed)) - public fun TensorStructure.randomNormalLike(seed: Long = 0): DoubleTensor = + public fun Tensor.randomNormalLike(seed: Long = 0): DoubleTensor = DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed)) // stack tensors by axis 0 @@ -412,7 +412,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { } // build tensor from this rows by given indices - public fun TensorStructure.rowsByIndices(indices: IntArray): DoubleTensor { + public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor { return stack(indices.map { this[it] }) } } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt index b1c12ccde..f8bd5027a 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt @@ -1,6 +1,6 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.tensors.api.TensorStructure +import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra @@ -20,7 +20,7 @@ internal fun checkBufferShapeConsistency(shape: IntArray, buffer: DoubleArray) = "Inconsistent shape ${shape.toList()} for buffer of size ${buffer.size} provided" } -internal fun checkShapesCompatible(a: TensorStructure, b: TensorStructure) = +internal fun checkShapesCompatible(a: Tensor, b: Tensor) = check(a.shape contentEquals b.shape) { "Incompatible shapes ${a.shape.toList()} and ${b.shape.toList()} " } @@ -30,7 +30,7 @@ internal fun checkTranspose(dim: Int, i: Int, j: Int) = "Cannot transpose $i to $j for a tensor of dim $dim" } -internal fun checkView(a: TensorStructure, shape: IntArray) = +internal fun checkView(a: Tensor, shape: IntArray) = check(a.shape.reduce(Int::times) == shape.reduce(Int::times)) internal fun checkSquareMatrix(shape: IntArray) { @@ -44,7 +44,7 @@ internal fun checkSquareMatrix(shape: IntArray) { } internal fun DoubleTensorAlgebra.checkSymmetric( - tensor: TensorStructure, epsilon: Double = 1e-6 + tensor: Tensor, epsilon: Double = 1e-6 ) = check(tensor.eq(tensor.transpose(), epsilon)) { "Tensor is not symmetric about the last 2 dimensions at precision $epsilon" From 8898f908ef6cd6a3ce9458af13cc9abe160e8649 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Mon, 3 May 2021 18:45:18 +0300 Subject: [PATCH 148/178] statistic algebra --- .../tensors/api/StatisticTensorAlgebra.kt | 137 ++++++++++++++++++ .../algebras/DoubleStatisticTensorAlgebra.kt | 105 ++++++++++++++ 2 files changed, 242 insertions(+) create mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/StatisticTensorAlgebra.kt create mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleStatisticTensorAlgebra.kt diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/StatisticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/StatisticTensorAlgebra.kt new file mode 100644 index 000000000..e3a2a1124 --- /dev/null +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/StatisticTensorAlgebra.kt @@ -0,0 +1,137 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.api + +import space.kscience.kmath.tensors.core.DoubleTensor + +/** + * Common algebra with statistics methods. Operates on [Tensor]. + * + * @param T the type of items closed under division in the tensors. + */ + +public interface StatisticTensorAlgebra: TensorAlgebra { + + /** + * Returns the minimum value of all elements in the input tensor. + * + * @return the minimum value of all elements in the input tensor. + */ + public fun Tensor.min(): Double + + /** + * Returns the minimum value of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the minimum value of each row of the input tensor in the given dimension [dim]. + */ + public fun Tensor.min(dim: Int, keepDim: Boolean): DoubleTensor + + /** + * Returns the maximum value of all elements in the input tensor. + * + * @return the maximum value of all elements in the input tensor. + */ + public fun Tensor.max(): Double + + /** + * Returns the maximum value of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the maximum value of each row of the input tensor in the given dimension [dim]. + */ + public fun Tensor.max(dim: Int, keepDim: Boolean): DoubleTensor + + /** + * Returns the sum of all elements in the input tensor. + * + * @return the sum of all elements in the input tensor. + */ + public fun Tensor.sum(): Double + + /** + * Returns the sum of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the sum of each row of the input tensor in the given dimension [dim]. + */ + public fun Tensor.sum(dim: Int, keepDim: Boolean): DoubleTensor + + /** + * Returns the mean of all elements in the input tensor. + * + * @return the mean of all elements in the input tensor. + */ + public fun Tensor.mean(): Double + + /** + * Returns the mean of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the mean of each row of the input tensor in the given dimension [dim]. + */ + public fun Tensor.mean(dim: Int, keepDim: Boolean): DoubleTensor + + /** + * Returns the standard deviation of all elements in the input tensor. + * + * @return the standard deviation of all elements in the input tensor. + */ + public fun Tensor.std(): Double + + /** + * Returns the standard deviation of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the standard deviation of each row of the input tensor in the given dimension [dim]. + */ + public fun Tensor.std(dim: Int, keepDim: Boolean): DoubleTensor + + /** + * Returns the variance of all elements in the input tensor. + * + * @return the variance of all elements in the input tensor. + */ + public fun Tensor.variance(): Double + + /** + * Returns the variance of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the variance of each row of the input tensor in the given dimension [dim]. + */ + public fun Tensor.variance(dim: Int, keepDim: Boolean): DoubleTensor +} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleStatisticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleStatisticTensorAlgebra.kt new file mode 100644 index 000000000..3914a0dfb --- /dev/null +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleStatisticTensorAlgebra.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.core.algebras + +import kotlin.math.sqrt + +import space.kscience.kmath.tensors.api.* +import space.kscience.kmath.tensors.core.* +import space.kscience.kmath.tensors.core.algebras.DoubleStatisticTensorAlgebra.max +import space.kscience.kmath.tensors.core.algebras.DoubleStatisticTensorAlgebra.mean +import space.kscience.kmath.tensors.core.algebras.DoubleStatisticTensorAlgebra.min +import space.kscience.kmath.tensors.core.algebras.DoubleStatisticTensorAlgebra.sum +import space.kscience.kmath.tensors.core.algebras.DoubleStatisticTensorAlgebra.variance + +public object DoubleStatisticTensorAlgebra : StatisticTensorAlgebra, DoubleTensorAlgebra() { + + private fun Tensor.fold(foldFunction: (DoubleArray) -> Double): Double { + return foldFunction(this.tensor.toDoubleArray()) + } + + private fun Tensor.foldDim( + foldFunction: (DoubleArray) -> Double, + dim: Int, + keepDim: Boolean + ): DoubleTensor { + check(dim < dimension) { "Dimension $dim out of range $dimension" } + val resShape = if (keepDim) { + shape.take(dim).toIntArray() + intArrayOf(1) + shape.takeLast(dimension - dim - 1).toIntArray() + } else { + shape.take(dim).toIntArray() + shape.takeLast(dimension - dim - 1).toIntArray() + } + val resNumElements = resShape.reduce(Int::times) + val resTensor = DoubleTensor(resShape, DoubleArray(resNumElements) { 0.0 }, 0) + for (index in resTensor.linearStructure.indices()) { + val prefix = index.take(dim).toIntArray() + val suffix = index.takeLast(dimension - dim - 1).toIntArray() + resTensor[index] = foldFunction(DoubleArray(shape[dim]) { i -> + this[prefix + intArrayOf(i) + suffix] + }) + } + + return resTensor + } + + override fun Tensor.min(): Double = this.fold { it.minOrNull()!! } + + override fun Tensor.min(dim: Int, keepDim: Boolean): DoubleTensor = + foldDim({ x -> x.minOrNull()!! }, dim, keepDim) + + override fun Tensor.max(): Double = this.fold { it.maxOrNull()!! } + + override fun Tensor.max(dim: Int, keepDim: Boolean): DoubleTensor = + foldDim({ x -> x.maxOrNull()!! }, dim, keepDim) + + override fun Tensor.sum(): Double = this.fold { it.sum() } + + override fun Tensor.sum(dim: Int, keepDim: Boolean): DoubleTensor = + foldDim({ x -> x.sum() }, dim, keepDim) + + override fun Tensor.mean(): Double = this.fold { it.sum() / tensor.numElements } + + override fun Tensor.mean(dim: Int, keepDim: Boolean): DoubleTensor = + foldDim( + { arr -> + check(dim < dimension) { "Dimension $dim out of range $dimension" } + arr.sum() / shape[dim] + }, + dim, + keepDim + ) + + override fun Tensor.std(): Double = this.fold { arr -> + val mean = arr.sum() / tensor.numElements + sqrt(arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1)) + } + + override fun Tensor.std(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( + { arr -> + check(dim < dimension) { "Dimension $dim out of range $dimension" } + val mean = arr.sum() / shape[dim] + sqrt(arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1)) + }, + dim, + keepDim + ) + + override fun Tensor.variance(): Double = this.fold { arr -> + val mean = arr.sum() / tensor.numElements + arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1) + } + + override fun Tensor.variance(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( + { arr -> + check(dim < dimension) { "Dimension $dim out of range $dimension" } + val mean = arr.sum() / shape[dim] + arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1) + }, + dim, + keepDim + ) + +} \ No newline at end of file From 7f8914d8eacb6fb09469fa18b7328fa16bfc2208 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Mon, 3 May 2021 20:42:18 +0300 Subject: [PATCH 149/178] fixes --- .../kmath/tensors/api/StatisticTensorAlgebra.kt | 17 ++--------------- .../algebras/DoubleStatisticTensorAlgebra.kt | 7 +++---- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/StatisticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/StatisticTensorAlgebra.kt index e3a2a1124..d0b17af97 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/StatisticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/StatisticTensorAlgebra.kt @@ -9,16 +9,12 @@ import space.kscience.kmath.tensors.core.DoubleTensor /** * Common algebra with statistics methods. Operates on [Tensor]. - * - * @param T the type of items closed under division in the tensors. */ public interface StatisticTensorAlgebra: TensorAlgebra { /** * Returns the minimum value of all elements in the input tensor. - * - * @return the minimum value of all elements in the input tensor. */ public fun Tensor.min(): Double @@ -37,8 +33,6 @@ public interface StatisticTensorAlgebra: TensorAlgebra { /** * Returns the maximum value of all elements in the input tensor. - * - * @return the maximum value of all elements in the input tensor. */ public fun Tensor.max(): Double @@ -57,8 +51,6 @@ public interface StatisticTensorAlgebra: TensorAlgebra { /** * Returns the sum of all elements in the input tensor. - * - * @return the sum of all elements in the input tensor. */ public fun Tensor.sum(): Double @@ -77,8 +69,6 @@ public interface StatisticTensorAlgebra: TensorAlgebra { /** * Returns the mean of all elements in the input tensor. - * - * @return the mean of all elements in the input tensor. */ public fun Tensor.mean(): Double @@ -97,8 +87,6 @@ public interface StatisticTensorAlgebra: TensorAlgebra { /** * Returns the standard deviation of all elements in the input tensor. - * - * @return the standard deviation of all elements in the input tensor. */ public fun Tensor.std(): Double @@ -117,8 +105,6 @@ public interface StatisticTensorAlgebra: TensorAlgebra { /** * Returns the variance of all elements in the input tensor. - * - * @return the variance of all elements in the input tensor. */ public fun Tensor.variance(): Double @@ -134,4 +120,5 @@ public interface StatisticTensorAlgebra: TensorAlgebra { * @return the variance of each row of the input tensor in the given dimension [dim]. */ public fun Tensor.variance(dim: Int, keepDim: Boolean): DoubleTensor -} \ No newline at end of file + +} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleStatisticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleStatisticTensorAlgebra.kt index 3914a0dfb..b455aff48 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleStatisticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleStatisticTensorAlgebra.kt @@ -17,9 +17,8 @@ import space.kscience.kmath.tensors.core.algebras.DoubleStatisticTensorAlgebra.v public object DoubleStatisticTensorAlgebra : StatisticTensorAlgebra, DoubleTensorAlgebra() { - private fun Tensor.fold(foldFunction: (DoubleArray) -> Double): Double { - return foldFunction(this.tensor.toDoubleArray()) - } + private fun Tensor.fold(foldFunction: (DoubleArray) -> Double): Double = + foldFunction(this.tensor.toDoubleArray()) private fun Tensor.foldDim( foldFunction: (DoubleArray) -> Double, @@ -102,4 +101,4 @@ public object DoubleStatisticTensorAlgebra : StatisticTensorAlgebra, Dou keepDim ) -} \ No newline at end of file +} From b59e48410f07ad203820b9c581b5e9997bff9784 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Mon, 3 May 2021 19:49:23 +0100 Subject: [PATCH 150/178] More basic functionality, tests to come --- .../tensors/api/AnalyticTensorAlgebra.kt | 95 +++++++++++++- .../tensors/api/StatisticTensorAlgebra.kt | 124 ------------------ .../kmath/tensors/api/TensorAlgebra.kt | 20 +++ .../algebras/DoubleAnalyticTensorAlgebra.kt | 54 ++++++++ .../algebras/DoubleStatisticTensorAlgebra.kt | 104 --------------- .../core/algebras/DoubleTensorAlgebra.kt | 36 ++++- 6 files changed, 202 insertions(+), 231 deletions(-) delete mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/StatisticTensorAlgebra.kt delete mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleStatisticTensorAlgebra.kt diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt index cd13e0752..f9b2df45c 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt @@ -5,14 +5,107 @@ package space.kscience.kmath.tensors.api + /** - * Element-wise analytic operations on [Tensor]. + * Analytic operations on [Tensor]. * * @param T the type of items closed under analytic functions in the tensors. */ public interface AnalyticTensorAlgebra : TensorPartialDivisionAlgebra { + + /** + * @return the minimum value of all elements in the input tensor. + */ + public fun Tensor.min(): T + + /** + * Returns the minimum value of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the minimum value of each row of the input tensor in the given dimension [dim]. + */ + public fun Tensor.min(dim: Int, keepDim: Boolean): Tensor + + /** + * @return the maximum value of all elements in the input tensor. + */ + public fun Tensor.max(): T + + /** + * Returns the maximum value of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the maximum value of each row of the input tensor in the given dimension [dim]. + */ + public fun Tensor.max(dim: Int, keepDim: Boolean): Tensor + + + /** + * @return the mean of all elements in the input tensor. + */ + public fun Tensor.mean(): T + + /** + * Returns the mean of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the mean of each row of the input tensor in the given dimension [dim]. + */ + public fun Tensor.mean(dim: Int, keepDim: Boolean): Tensor + + /** + * @return the standard deviation of all elements in the input tensor. + */ + public fun Tensor.std(): T + + /** + * Returns the standard deviation of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the standard deviation of each row of the input tensor in the given dimension [dim]. + */ + public fun Tensor.std(dim: Int, keepDim: Boolean): Tensor + + /** + * @return the variance of all elements in the input tensor. + */ + public fun Tensor.variance(): T + + /** + * Returns the variance of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the variance of each row of the input tensor in the given dimension [dim]. + */ + public fun Tensor.variance(dim: Int, keepDim: Boolean): Tensor + //For information: https://pytorch.org/docs/stable/generated/torch.exp.html public fun Tensor.exp(): Tensor diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/StatisticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/StatisticTensorAlgebra.kt deleted file mode 100644 index d0b17af97..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/StatisticTensorAlgebra.kt +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.api - -import space.kscience.kmath.tensors.core.DoubleTensor - -/** - * Common algebra with statistics methods. Operates on [Tensor]. - */ - -public interface StatisticTensorAlgebra: TensorAlgebra { - - /** - * Returns the minimum value of all elements in the input tensor. - */ - public fun Tensor.min(): Double - - /** - * Returns the minimum value of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the minimum value of each row of the input tensor in the given dimension [dim]. - */ - public fun Tensor.min(dim: Int, keepDim: Boolean): DoubleTensor - - /** - * Returns the maximum value of all elements in the input tensor. - */ - public fun Tensor.max(): Double - - /** - * Returns the maximum value of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the maximum value of each row of the input tensor in the given dimension [dim]. - */ - public fun Tensor.max(dim: Int, keepDim: Boolean): DoubleTensor - - /** - * Returns the sum of all elements in the input tensor. - */ - public fun Tensor.sum(): Double - - /** - * Returns the sum of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the sum of each row of the input tensor in the given dimension [dim]. - */ - public fun Tensor.sum(dim: Int, keepDim: Boolean): DoubleTensor - - /** - * Returns the mean of all elements in the input tensor. - */ - public fun Tensor.mean(): Double - - /** - * Returns the mean of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the mean of each row of the input tensor in the given dimension [dim]. - */ - public fun Tensor.mean(dim: Int, keepDim: Boolean): DoubleTensor - - /** - * Returns the standard deviation of all elements in the input tensor. - */ - public fun Tensor.std(): Double - - /** - * Returns the standard deviation of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the standard deviation of each row of the input tensor in the given dimension [dim]. - */ - public fun Tensor.std(dim: Int, keepDim: Boolean): DoubleTensor - - /** - * Returns the variance of all elements in the input tensor. - */ - public fun Tensor.variance(): Double - - /** - * Returns the variance of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the variance of each row of the input tensor in the given dimension [dim]. - */ - public fun Tensor.variance(dim: Int, keepDim: Boolean): DoubleTensor - -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index b9c707c0b..b99f79e9a 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -251,4 +251,24 @@ public interface TensorAlgebra: Algebra> { dim2: Int = -1 ): Tensor + /** + * @return the sum of all elements in the input tensor. + */ + public fun Tensor.sum(): T + + /** + * Returns the sum of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the sum of each row of the input tensor in the given dimension [dim]. + */ + public fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor + + + } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt index 9aa6f093e..547018498 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt @@ -14,6 +14,60 @@ import kotlin.math.* public object DoubleAnalyticTensorAlgebra : AnalyticTensorAlgebra, DoubleTensorAlgebra() { + + override fun Tensor.min(): Double = this.fold { it.minOrNull()!! } + + override fun Tensor.min(dim: Int, keepDim: Boolean): DoubleTensor = + foldDim({ x -> x.minOrNull()!! }, dim, keepDim) + + override fun Tensor.max(): Double = this.fold { it.maxOrNull()!! } + + override fun Tensor.max(dim: Int, keepDim: Boolean): DoubleTensor = + foldDim({ x -> x.maxOrNull()!! }, dim, keepDim) + + + override fun Tensor.mean(): Double = this.fold { it.sum() / tensor.numElements } + + override fun Tensor.mean(dim: Int, keepDim: Boolean): DoubleTensor = + foldDim( + { arr -> + check(dim < dimension) { "Dimension $dim out of range $dimension" } + arr.sum() / shape[dim] + }, + dim, + keepDim + ) + + override fun Tensor.std(): Double = this.fold { arr -> + val mean = arr.sum() / tensor.numElements + sqrt(arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1)) + } + + override fun Tensor.std(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( + { arr -> + check(dim < dimension) { "Dimension $dim out of range $dimension" } + val mean = arr.sum() / shape[dim] + sqrt(arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1)) + }, + dim, + keepDim + ) + + override fun Tensor.variance(): Double = this.fold { arr -> + val mean = arr.sum() / tensor.numElements + arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1) + } + + override fun Tensor.variance(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( + { arr -> + check(dim < dimension) { "Dimension $dim out of range $dimension" } + val mean = arr.sum() / shape[dim] + arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1) + }, + dim, + keepDim + ) + override fun Tensor.exp(): DoubleTensor = tensor.map(::exp) override fun Tensor.log(): DoubleTensor = tensor.map(::ln) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleStatisticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleStatisticTensorAlgebra.kt deleted file mode 100644 index b455aff48..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleStatisticTensorAlgebra.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core.algebras - -import kotlin.math.sqrt - -import space.kscience.kmath.tensors.api.* -import space.kscience.kmath.tensors.core.* -import space.kscience.kmath.tensors.core.algebras.DoubleStatisticTensorAlgebra.max -import space.kscience.kmath.tensors.core.algebras.DoubleStatisticTensorAlgebra.mean -import space.kscience.kmath.tensors.core.algebras.DoubleStatisticTensorAlgebra.min -import space.kscience.kmath.tensors.core.algebras.DoubleStatisticTensorAlgebra.sum -import space.kscience.kmath.tensors.core.algebras.DoubleStatisticTensorAlgebra.variance - -public object DoubleStatisticTensorAlgebra : StatisticTensorAlgebra, DoubleTensorAlgebra() { - - private fun Tensor.fold(foldFunction: (DoubleArray) -> Double): Double = - foldFunction(this.tensor.toDoubleArray()) - - private fun Tensor.foldDim( - foldFunction: (DoubleArray) -> Double, - dim: Int, - keepDim: Boolean - ): DoubleTensor { - check(dim < dimension) { "Dimension $dim out of range $dimension" } - val resShape = if (keepDim) { - shape.take(dim).toIntArray() + intArrayOf(1) + shape.takeLast(dimension - dim - 1).toIntArray() - } else { - shape.take(dim).toIntArray() + shape.takeLast(dimension - dim - 1).toIntArray() - } - val resNumElements = resShape.reduce(Int::times) - val resTensor = DoubleTensor(resShape, DoubleArray(resNumElements) { 0.0 }, 0) - for (index in resTensor.linearStructure.indices()) { - val prefix = index.take(dim).toIntArray() - val suffix = index.takeLast(dimension - dim - 1).toIntArray() - resTensor[index] = foldFunction(DoubleArray(shape[dim]) { i -> - this[prefix + intArrayOf(i) + suffix] - }) - } - - return resTensor - } - - override fun Tensor.min(): Double = this.fold { it.minOrNull()!! } - - override fun Tensor.min(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim({ x -> x.minOrNull()!! }, dim, keepDim) - - override fun Tensor.max(): Double = this.fold { it.maxOrNull()!! } - - override fun Tensor.max(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim({ x -> x.maxOrNull()!! }, dim, keepDim) - - override fun Tensor.sum(): Double = this.fold { it.sum() } - - override fun Tensor.sum(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim({ x -> x.sum() }, dim, keepDim) - - override fun Tensor.mean(): Double = this.fold { it.sum() / tensor.numElements } - - override fun Tensor.mean(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim( - { arr -> - check(dim < dimension) { "Dimension $dim out of range $dimension" } - arr.sum() / shape[dim] - }, - dim, - keepDim - ) - - override fun Tensor.std(): Double = this.fold { arr -> - val mean = arr.sum() / tensor.numElements - sqrt(arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1)) - } - - override fun Tensor.std(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( - { arr -> - check(dim < dimension) { "Dimension $dim out of range $dimension" } - val mean = arr.sum() / shape[dim] - sqrt(arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1)) - }, - dim, - keepDim - ) - - override fun Tensor.variance(): Double = this.fold { arr -> - val mean = arr.sum() / tensor.numElements - arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1) - } - - override fun Tensor.variance(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( - { arr -> - check(dim < dimension) { "Dimension $dim out of range $dimension" } - val mean = arr.sum() / shape[dim] - arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1) - }, - dim, - keepDim - ) - -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index 4009f7b45..c0a6312a9 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -284,7 +284,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { val m1 = newThis.shape[newThis.shape.size - 1] val m2 = newOther.shape[newOther.shape.size - 2] val n = newOther.shape[newOther.shape.size - 1] - check (m1 == m2) { + check(m1 == m2) { throw RuntimeException("Tensors dot operation dimension mismatch: ($l, $m1) x ($m2, $n)") } @@ -403,7 +403,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { public fun stack(tensors: List): DoubleTensor { val shape = tensors.firstOrNull()?.shape check(shape != null) { "Collection must have at least 1 element" } - check(tensors.all { it.shape contentEquals shape }) {"Stacking tensors must have same shapes"} + check(tensors.all { it.shape contentEquals shape }) { "Stacking tensors must have same shapes" } val resShape = intArrayOf(tensors.size) + shape val resBuffer = tensors.flatMap { it.tensor.mutableBuffer.array().drop(it.bufferStart).take(it.numElements) @@ -415,4 +415,36 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor { return stack(indices.map { this[it] }) } + + internal fun Tensor.fold(foldFunction: (DoubleArray) -> Double): Double = + foldFunction(tensor.toDoubleArray()) + + internal fun Tensor.foldDim( + foldFunction: (DoubleArray) -> Double, + dim: Int, + keepDim: Boolean + ): DoubleTensor { + check(dim < dimension) { "Dimension $dim out of range $dimension" } + val resShape = if (keepDim) { + shape.take(dim).toIntArray() + intArrayOf(1) + shape.takeLast(dimension - dim - 1).toIntArray() + } else { + shape.take(dim).toIntArray() + shape.takeLast(dimension - dim - 1).toIntArray() + } + val resNumElements = resShape.reduce(Int::times) + val resTensor = DoubleTensor(resShape, DoubleArray(resNumElements) { 0.0 }, 0) + for (index in resTensor.linearStructure.indices()) { + val prefix = index.take(dim).toIntArray() + val suffix = index.takeLast(dimension - dim - 1).toIntArray() + resTensor[index] = foldFunction(DoubleArray(shape[dim]) { i -> + tensor[prefix + intArrayOf(i) + suffix] + }) + } + + return resTensor + } + + override fun Tensor.sum(): Double = tensor.fold { it.sum() } + + override fun Tensor.sum(dim: Int, keepDim: Boolean): DoubleTensor = + foldDim({ x -> x.sum() }, dim, keepDim) } From d0281871fac1f59f4218ea1e4440f1991e742bb1 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Wed, 5 May 2021 14:27:01 +0300 Subject: [PATCH 151/178] analytic tests and examples --- .../kmath/tensors/DataSetNormalization.kt | 46 ++++++ .../tensors/api/AnalyticTensorAlgebra.kt | 3 +- .../algebras/DoubleAnalyticTensorAlgebra.kt | 3 +- .../core/TestDoubleAnalyticTensorAlgebra.kt | 152 ++++++++++++++++-- 4 files changed, 186 insertions(+), 18 deletions(-) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt new file mode 100644 index 000000000..4d53d940b --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors + +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra +import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra + +// Dataset normalization + +fun main() { + + // work in context with analytic methods + DoubleAnalyticTensorAlgebra { + // take dataset of 5-element vectors from normal distribution + val dataset = randomNormal(intArrayOf(100, 5)) * 1.5 // all elements from N(0, 1.5) + BroadcastDoubleTensorAlgebra { + dataset += fromArray( + intArrayOf(5), + doubleArrayOf(0.0, 1.0, 1.5, 3.0, 5.0) // rows means + ) + } + + // find out mean and standard deviation of each column + val mean = dataset.mean(0, false) + val std = dataset.std(0, false) + + println("Mean:\n$mean") + println("Standard deviation:\n$std") + + // also we can calculate other statistic as minimum and maximum of rows + println("Minimum:\n${dataset.min(0, false)}") + println("Maximum:\n${dataset.max(0, false)}") + + // now we can scale dataset with mean normalization + val datasetScaled = BroadcastDoubleTensorAlgebra { (dataset - mean) / std } + + // find out mean and std of scaled dataset + + println("Mean of scaled:\n${datasetScaled.mean(0, false)}") + println("Mean of scaled:\n${datasetScaled.std(0, false)}") + } +} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt index f9b2df45c..7784bfa45 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt @@ -51,7 +51,6 @@ public interface AnalyticTensorAlgebra : */ public fun Tensor.max(dim: Int, keepDim: Boolean): Tensor - /** * @return the mean of all elements in the input tensor. */ @@ -110,7 +109,7 @@ public interface AnalyticTensorAlgebra : public fun Tensor.exp(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.log.html - public fun Tensor.log(): Tensor + public fun Tensor.ln(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.sqrt.html public fun Tensor.sqrt(): Tensor diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt index 547018498..5580f845f 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt @@ -25,7 +25,6 @@ public object DoubleAnalyticTensorAlgebra : override fun Tensor.max(dim: Int, keepDim: Boolean): DoubleTensor = foldDim({ x -> x.maxOrNull()!! }, dim, keepDim) - override fun Tensor.mean(): Double = this.fold { it.sum() / tensor.numElements } override fun Tensor.mean(dim: Int, keepDim: Boolean): DoubleTensor = @@ -70,7 +69,7 @@ public object DoubleAnalyticTensorAlgebra : override fun Tensor.exp(): DoubleTensor = tensor.map(::exp) - override fun Tensor.log(): DoubleTensor = tensor.map(::ln) + override fun Tensor.ln(): DoubleTensor = tensor.map(::ln) override fun Tensor.sqrt(): DoubleTensor = tensor.map(::sqrt) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt index 835b8a08a..bebd65dc5 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt @@ -2,35 +2,159 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra -import kotlin.math.abs -import kotlin.math.exp +import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra.tan +import kotlin.math.* import kotlin.test.Test import kotlin.test.assertTrue internal class TestDoubleAnalyticTensorAlgebra { val shape = intArrayOf(2, 1, 3, 2) - val buffer = doubleArrayOf(27.1, 20.0, 19.84, 23.123, 0.0, 1.0, 3.23, 133.7, 25.3, 100.3, 11.0, 12.012) + val buffer = doubleArrayOf( + 27.1, 20.0, 19.84, + 23.123, 3.0, 2.0, + + 3.23, 133.7, 25.3, + 100.3, 11.0, 12.012 + ) val tensor = DoubleTensor(shape, buffer) fun DoubleArray.fmap(transform: (Double) -> Double): DoubleArray { return this.map(transform).toDoubleArray() } - fun DoubleArray.epsEqual(other: DoubleArray, eps: Double = 1e-5): Boolean { - for ((elem1, elem2) in this.asSequence().zip(other.asSequence())) { - if (abs(elem1 - elem2) > eps) { - return false - } - } - return true + fun expectedTensor(transform: (Double) -> Double): DoubleTensor { + return DoubleTensor(shape, buffer.fmap(transform)) } @Test fun testExp() = DoubleAnalyticTensorAlgebra { - tensor.exp().let { - assertTrue { shape contentEquals it.shape } - assertTrue { buffer.fmap(::exp).epsEqual(it.mutableBuffer.array())} - } + assertTrue { tensor.exp() eq expectedTensor(::exp) } } + + @Test + fun testLog() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor.ln() eq expectedTensor(::ln) } + } + + @Test + fun testSqrt() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor.sqrt() eq expectedTensor(::sqrt) } + } + + @Test + fun testCos() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor.cos() eq expectedTensor(::cos) } + } + + + @Test + fun testCosh() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor.cosh() eq expectedTensor(::cosh) } + } + + @Test + fun testAcosh() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor.acosh() eq expectedTensor(::acosh) } + } + + @Test + fun testSin() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor.sin() eq expectedTensor(::sin) } + } + + @Test + fun testSinh() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor.sinh() eq expectedTensor(::sinh) } + } + + @Test + fun testAsinh() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor.asinh() eq expectedTensor(::asinh) } + } + + @Test + fun testTan() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor.tan() eq expectedTensor(::tan) } + } + + @Test + fun testAtan() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor.atan() eq expectedTensor(::atan) } + } + + @Test + fun testTanh() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor.tanh() eq expectedTensor(::tanh) } + } + + @Test + fun testCeil() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor.ceil() eq expectedTensor(::ceil) } + } + + @Test + fun testFloor() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor.floor() eq expectedTensor(::floor) } + } + + val shape2 = intArrayOf(2, 2) + val buffer2 = doubleArrayOf( + 1.0, 2.0, + -3.0, 4.0 + ) + val tensor2 = DoubleTensor(shape2, buffer2) + + @Test + fun testMin() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor2.min() == -3.0 } + assertTrue { tensor2.min(0, true) eq fromArray( + intArrayOf(1, 2), + doubleArrayOf(-3.0, 2.0) + )} + assertTrue { tensor2.min(1, false) eq fromArray( + intArrayOf(2), + doubleArrayOf(1.0, -3.0) + )} + } + + @Test + fun testMax() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor2.max() == 4.0 } + assertTrue { tensor2.max(0, true) eq fromArray( + intArrayOf(1, 2), + doubleArrayOf(1.0, 4.0) + )} + assertTrue { tensor2.max(1, false) eq fromArray( + intArrayOf(2), + doubleArrayOf(2.0, 4.0) + )} + } + + @Test + fun testSum() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor2.sum() == 4.0 } + assertTrue { tensor2.sum(0, true) eq fromArray( + intArrayOf(1, 2), + doubleArrayOf(-2.0, 6.0) + )} + assertTrue { tensor2.sum(1, false) eq fromArray( + intArrayOf(2), + doubleArrayOf(3.0, 1.0) + )} + } + + @Test + fun testMean() = DoubleAnalyticTensorAlgebra { + assertTrue { tensor2.mean() == 1.0 } + assertTrue { tensor2.mean(0, true) eq fromArray( + intArrayOf(1, 2), + doubleArrayOf(-1.0, 3.0) + )} + assertTrue { tensor2.mean(1, false) eq fromArray( + intArrayOf(2), + doubleArrayOf(1.5, 0.5) + )} + } + } \ No newline at end of file From 218b81a242b79baba4cb8db82887e4fa90556b05 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 5 May 2021 16:11:46 +0100 Subject: [PATCH 152/178] Min max refactor --- .../tensors/api/AnalyticTensorAlgebra.kt | 37 ------------------- .../kmath/tensors/api/TensorAlgebra.kt | 35 ++++++++++++++++++ .../algebras/DoubleAnalyticTensorAlgebra.kt | 10 ----- .../core/algebras/DoubleTensorAlgebra.kt | 14 +++++++ .../core/TestDoubleAnalyticTensorAlgebra.kt | 8 ++-- 5 files changed, 53 insertions(+), 51 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt index 7784bfa45..aa5678b31 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt @@ -14,43 +14,6 @@ package space.kscience.kmath.tensors.api public interface AnalyticTensorAlgebra : TensorPartialDivisionAlgebra { - - /** - * @return the minimum value of all elements in the input tensor. - */ - public fun Tensor.min(): T - - /** - * Returns the minimum value of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the minimum value of each row of the input tensor in the given dimension [dim]. - */ - public fun Tensor.min(dim: Int, keepDim: Boolean): Tensor - - /** - * @return the maximum value of all elements in the input tensor. - */ - public fun Tensor.max(): T - - /** - * Returns the maximum value of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the maximum value of each row of the input tensor in the given dimension [dim]. - */ - public fun Tensor.max(dim: Int, keepDim: Boolean): Tensor - /** * @return the mean of all elements in the input tensor. */ diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index b99f79e9a..b0a0f9618 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -269,6 +269,41 @@ public interface TensorAlgebra: Algebra> { */ public fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor + /** + * @return the minimum value of all elements in the input tensor. + */ + public fun Tensor.min(): T + + /** + * Returns the minimum value of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the minimum value of each row of the input tensor in the given dimension [dim]. + */ + public fun Tensor.min(dim: Int, keepDim: Boolean): Tensor + + /** + * @return the maximum value of all elements in the input tensor. + */ + public fun Tensor.max(): T + + /** + * Returns the maximum value of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the maximum value of each row of the input tensor in the given dimension [dim]. + */ + public fun Tensor.max(dim: Int, keepDim: Boolean): Tensor } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt index 5580f845f..4a1f360e3 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt @@ -15,16 +15,6 @@ public object DoubleAnalyticTensorAlgebra : AnalyticTensorAlgebra, DoubleTensorAlgebra() { - override fun Tensor.min(): Double = this.fold { it.minOrNull()!! } - - override fun Tensor.min(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim({ x -> x.minOrNull()!! }, dim, keepDim) - - override fun Tensor.max(): Double = this.fold { it.maxOrNull()!! } - - override fun Tensor.max(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim({ x -> x.maxOrNull()!! }, dim, keepDim) - override fun Tensor.mean(): Double = this.fold { it.sum() / tensor.numElements } override fun Tensor.mean(dim: Int, keepDim: Boolean): DoubleTensor = diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index c0a6312a9..d220bdd9a 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -9,6 +9,8 @@ import space.kscience.kmath.nd.as2D import space.kscience.kmath.tensors.api.TensorPartialDivisionAlgebra import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.* +import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra.fold +import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra.foldDim import space.kscience.kmath.tensors.core.broadcastOuterTensors import space.kscience.kmath.tensors.core.checkBufferShapeConsistency import space.kscience.kmath.tensors.core.checkEmptyDoubleBuffer @@ -447,4 +449,16 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { override fun Tensor.sum(dim: Int, keepDim: Boolean): DoubleTensor = foldDim({ x -> x.sum() }, dim, keepDim) + + + override fun Tensor.min(): Double = this.fold { it.minOrNull()!! } + + override fun Tensor.min(dim: Int, keepDim: Boolean): DoubleTensor = + foldDim({ x -> x.minOrNull()!! }, dim, keepDim) + + override fun Tensor.max(): Double = this.fold { it.maxOrNull()!! } + + override fun Tensor.max(dim: Int, keepDim: Boolean): DoubleTensor = + foldDim({ x -> x.maxOrNull()!! }, dim, keepDim) + } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt index bebd65dc5..3ea19da26 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt @@ -2,7 +2,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra -import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra.tan +import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import kotlin.math.* import kotlin.test.Test import kotlin.test.assertTrue @@ -106,7 +106,7 @@ internal class TestDoubleAnalyticTensorAlgebra { val tensor2 = DoubleTensor(shape2, buffer2) @Test - fun testMin() = DoubleAnalyticTensorAlgebra { + fun testMin() = DoubleTensorAlgebra { assertTrue { tensor2.min() == -3.0 } assertTrue { tensor2.min(0, true) eq fromArray( intArrayOf(1, 2), @@ -119,7 +119,7 @@ internal class TestDoubleAnalyticTensorAlgebra { } @Test - fun testMax() = DoubleAnalyticTensorAlgebra { + fun testMax() = DoubleTensorAlgebra { assertTrue { tensor2.max() == 4.0 } assertTrue { tensor2.max(0, true) eq fromArray( intArrayOf(1, 2), @@ -132,7 +132,7 @@ internal class TestDoubleAnalyticTensorAlgebra { } @Test - fun testSum() = DoubleAnalyticTensorAlgebra { + fun testSum() = DoubleTensorAlgebra { assertTrue { tensor2.sum() == 4.0 } assertTrue { tensor2.sum(0, true) eq fromArray( intArrayOf(1, 2), From 431db00f1ac9da54b65d00a09fa6f7b33c150942 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Wed, 5 May 2021 16:35:26 +0100 Subject: [PATCH 153/178] refactor tests --- .../kmath/tensors/core/TestBroadcasting.kt | 12 ++++---- .../kmath/tensors/core/TestDoubleTensor.kt | 8 ++--- .../tensors/core/TestDoubleTensorAlgebra.kt | 30 ++++++------------- 3 files changed, 19 insertions(+), 31 deletions(-) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt index 1564b85c9..6e3b4df60 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt @@ -9,7 +9,7 @@ import kotlin.test.assertTrue internal class TestBroadcasting { @Test - fun broadcastShapes() = DoubleTensorAlgebra { + fun testBroadcastShapes() = DoubleTensorAlgebra { assertTrue( broadcastShapes( intArrayOf(2, 3), intArrayOf(1, 3), intArrayOf(1, 1, 1) @@ -24,7 +24,7 @@ internal class TestBroadcasting { } @Test - fun broadcastTo() = DoubleTensorAlgebra { + fun testBroadcastTo() = DoubleTensorAlgebra { 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)) @@ -34,7 +34,7 @@ internal class TestBroadcasting { } @Test - fun broadcastTensors() = DoubleTensorAlgebra { + fun testBroadcastTensors() = DoubleTensorAlgebra { 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 tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) @@ -51,7 +51,7 @@ internal class TestBroadcasting { } @Test - fun broadcastOuterTensors() = DoubleTensorAlgebra { + fun testBroadcastOuterTensors() = DoubleTensorAlgebra { 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 tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) @@ -68,7 +68,7 @@ internal class TestBroadcasting { } @Test - fun broadcastOuterTensorsShapes() = DoubleTensorAlgebra { + fun testBroadcastOuterTensorsShapes() = DoubleTensorAlgebra { 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 tensor3 = fromArray(intArrayOf(1, 1), doubleArrayOf(500.0)) @@ -81,7 +81,7 @@ internal class TestBroadcasting { } @Test - fun minusTensor() = BroadcastDoubleTensorAlgebra.invoke { + fun testMinusTensor() = BroadcastDoubleTensorAlgebra.invoke { 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 tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index ed5f8e780..132735cc7 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -15,14 +15,14 @@ import kotlin.test.assertTrue internal class TestDoubleTensor { @Test - fun valueTest() = DoubleTensorAlgebra { + fun testValue() = DoubleTensorAlgebra { val value = 12.5 val tensor = fromArray(intArrayOf(1), doubleArrayOf(value)) assertEquals(tensor.value(), value) } @Test - fun stridesTest() = DoubleTensorAlgebra { + fun testStrides() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4)) assertEquals(tensor[intArrayOf(0, 1)], 5.8) assertTrue( @@ -31,7 +31,7 @@ internal class TestDoubleTensor { } @Test - fun getTest() = DoubleTensorAlgebra { + fun testGet() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(1, 2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4)) val matrix = tensor[0].as2D() assertEquals(matrix[0, 1], 5.8) @@ -55,7 +55,7 @@ internal class TestDoubleTensor { } @Test - fun noBufferProtocol() { + fun testNoBufferProtocol() { // create buffer val doubleArray = DoubleBuffer(doubleArrayOf(1.0, 2.0, 3.0)) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index df2d21b96..d782d78d9 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -10,28 +10,28 @@ import kotlin.test.assertTrue internal class TestDoubleTensorAlgebra { @Test - fun doublePlus() = DoubleTensorAlgebra { + fun testDoublePlus() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(2), doubleArrayOf(1.0, 2.0)) val res = 10.0 + tensor assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(11.0, 12.0)) } @Test - fun doubleDiv() = DoubleTensorAlgebra { + fun TestDoubleDiv() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(2), doubleArrayOf(2.0, 4.0)) val res = 2.0/tensor assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 0.5)) } @Test - fun divDouble() = DoubleTensorAlgebra { + fun testDivDouble() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(2), doubleArrayOf(10.0, 5.0)) val res = tensor / 2.5 assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(4.0, 2.0)) } @Test - fun transpose1x1() = DoubleTensorAlgebra { + fun testTranspose1x1() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(1), doubleArrayOf(0.0)) val res = tensor.transpose(0, 0) @@ -40,7 +40,7 @@ internal class TestDoubleTensorAlgebra { } @Test - fun transpose3x2() = DoubleTensorAlgebra { + fun testTranspose3x2() = DoubleTensorAlgebra { 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) @@ -49,7 +49,7 @@ internal class TestDoubleTensorAlgebra { } @Test - fun transpose1x2x3() = DoubleTensorAlgebra { + fun testTranspose1x2x3() = DoubleTensorAlgebra { 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 res02 = tensor.transpose(-3, 2) @@ -65,7 +65,7 @@ internal class TestDoubleTensorAlgebra { } @Test - fun linearStructure() = DoubleTensorAlgebra { + fun testLinearStructure() = DoubleTensorAlgebra { val shape = intArrayOf(3) val tensorA = full(value = -4.5, shape = shape) val tensorB = full(value = 10.9, shape = shape) @@ -97,7 +97,7 @@ internal class TestDoubleTensorAlgebra { } @Test - fun dot() = DoubleTensorAlgebra { + fun testDot() = DoubleTensorAlgebra { 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 tensor2 = fromArray(intArrayOf(3), doubleArrayOf(10.0, 20.0, 30.0)) @@ -118,22 +118,10 @@ internal class TestDoubleTensorAlgebra { val res11 = tensor1.dot(tensor11) assertTrue(res11.mutableBuffer.array() contentEquals doubleArrayOf(22.0, 28.0, 49.0, 64.0)) assertTrue(res11.shape contentEquals intArrayOf(2, 2)) - - var tensor4 = fromArray(intArrayOf(10, 3, 4), DoubleArray(10 * 3 * 4) {0.0}) - var tensor5 = fromArray(intArrayOf(10, 4, 5), DoubleArray(10 * 4 * 5) {0.0}) - assertTrue(tensor4.dot(tensor5).shape contentEquals intArrayOf(10, 3, 5)) - - tensor4 = fromArray(intArrayOf(10, 3, 4), DoubleArray(10 * 3 * 4) {0.0}) - tensor5 = fromArray(intArrayOf(4, 5), DoubleArray(4 * 5) {0.0}) - assertTrue(tensor4.dot(tensor5).shape contentEquals intArrayOf(10, 3, 5)) - - tensor4 = fromArray(intArrayOf(4, 2, 1, 3, 8, 1), DoubleArray(4 * 2 * 1 * 3 * 8 * 1) {0.0}) - tensor5 = fromArray(intArrayOf(5, 1, 2, 8, 3, 1, 5), DoubleArray(5 * 1 * 2 * 8 * 3 * 1 * 5) {0.0}) - assertTrue(tensor4.dot(tensor5).shape contentEquals intArrayOf(5, 4, 2, 8, 3, 8, 5)) } @Test - fun diagonalEmbedding() = DoubleTensorAlgebra { + fun testDiagonalEmbedding() = DoubleTensorAlgebra { 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 tensor3 = zeros(intArrayOf(2, 3, 4, 5)) From 229c1b57daa3727a6e59d16c6ed04786a83ae220 Mon Sep 17 00:00:00 2001 From: AlyaNovikova Date: Thu, 6 May 2021 10:27:47 +0300 Subject: [PATCH 154/178] add documentation to DoubleLinearOpsTensorAlgebra --- .../tensors/api/LinearOpsTensorAlgebra.kt | 2 +- .../algebras/DoubleLinearOpsTensorAlgebra.kt | 95 ++++++++++++++++++- 2 files changed, 94 insertions(+), 3 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt index 527e5d386..ec070b6bd 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -81,7 +81,7 @@ public interface LinearOpsTensorAlgebra : * If input is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as input. * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd * - * @return the determinant. + * @return triple `(U, S, V)`. */ public fun Tensor.svd(): Triple, Tensor, Tensor> diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt index 89345e315..d17dc70fe 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt @@ -20,7 +20,10 @@ import space.kscience.kmath.tensors.core.luPivotHelper import space.kscience.kmath.tensors.core.pivInit import kotlin.math.min - +/** + * Implementation of common linear algebra operations on double numbers. + * Implements the LinearOpsTensorAlgebra interface. + */ public object DoubleLinearOpsTensorAlgebra : LinearOpsTensorAlgebra, DoubleTensorAlgebra() { @@ -29,12 +32,41 @@ public object DoubleLinearOpsTensorAlgebra : override fun Tensor.det(): DoubleTensor = detLU(1e-9) + /** + * Computes the LU factorization of a matrix or batches of matrices `input`. + * Returns a tuple containing the LU factorization and pivots of `input`. + * + * @param epsilon permissible error when comparing the determinant of a matrix with zero + * @return pair of `factorization` and `pivots`. + * The `factorization` has the shape ``(*, m, n)``, where``(*, m, n)`` is the shape of the `input` tensor. + * The `pivots` has the shape ``(∗, min(m, n))``. `pivots` stores all the intermediate transpositions of rows. + */ public fun Tensor.luFactor(epsilon: Double): Pair = computeLU(tensor, epsilon) ?: throw IllegalArgumentException("Tensor contains matrices which are singular at precision $epsilon") + /** + * Computes the LU factorization of a matrix or batches of matrices `input`. + * Returns a tuple containing the LU factorization and pivots of `input`. + * Uses an error of ``1e-9`` when calculating whether a matrix is degenerate. + * + * @return pair of `factorization` and `pivots`. + * The `factorization` has the shape ``(*, m, n)``, where``(*, m, n)`` is the shape of the `input` tensor. + * The `pivots` has the shape ``(∗, min(m, n))``. `pivots` stores all the intermediate transpositions of rows. + */ public fun Tensor.luFactor(): Pair = luFactor(1e-9) + /** + * Unpacks the data and pivots from a LU factorization of a tensor. + * Given a tensor [luTensor], return tensors (P, L, U) satisfying ``P * luTensor = L * U``, + * with `P` being a permutation matrix or batch of matrices, + * `L` being a lower triangular matrix or batch of matrices, + * `U` being an upper triangular matrix or batch of matrices. + * + * @param luTensor the packed LU factorization data + * @param pivotsTensor the packed LU factorization pivots + * @return triple of P, L and U tensors + */ public fun luPivot( luTensor: Tensor, pivotsTensor: Tensor @@ -66,6 +98,18 @@ public object DoubleLinearOpsTensorAlgebra : return Triple(pTensor, lTensor, uTensor) } + /** + * QR decomposition. + * + * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `(Q, R)` of tensors. + * Given a tensor `input`, return tensors (Q, R) satisfying ``input = Q * R``, + * with `Q` being an orthogonal matrix or batch of orthogonal matrices + * and `R` being an upper triangular matrix or batch of upper triangular matrices. + * + * @param epsilon permissible error when comparing tensors for equality. + * Used when checking the positive definiteness of the input matrix or matrices. + * @return pair of Q and R tensors. + */ public fun Tensor.cholesky(epsilon: Double): DoubleTensor { checkSquareMatrix(shape) checkPositiveDefinite(tensor, epsilon) @@ -98,6 +142,18 @@ public object DoubleLinearOpsTensorAlgebra : override fun Tensor.svd(): Triple = svd(epsilon = 1e-10) + /** + * Singular Value Decomposition. + * + * Computes the singular value decomposition of either a matrix or batch of matrices `input`. + * The singular value decomposition is represented as a triple `(U, S, V)`, + * such that ``input = U.dot(diagonalEmbedding(S).dot(V.T))``. + * If input is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as input. + * + * @param epsilon permissible error when calculating the dot product of vectors, + * i.e. the precision with which the cosine approaches 1 in an iterative algorithm. + * @return triple `(U, S, V)`. + */ public fun Tensor.svd(epsilon: Double): Triple { val size = tensor.linearStructure.dim val commonShape = tensor.shape.sliceArray(0 until size - 2) @@ -125,7 +181,14 @@ public object DoubleLinearOpsTensorAlgebra : override fun Tensor.symEig(): Pair = symEig(epsilon = 1e-15) - //For information: http://hua-zhou.github.io/teaching/biostatm280-2017spring/slides/16-eigsvd/eigsvd.html + /** + * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, + * represented by a pair (eigenvalues, eigenvectors). + * + * @param epsilon permissible error when comparing tensors for equality + * and when the cosine approaches 1 in the SVD algorithm. + * @return a pair (eigenvalues, eigenvectors) + */ public fun Tensor.symEig(epsilon: Double): Pair { checkSymmetric(tensor, epsilon) val (u, s, v) = tensor.svd(epsilon) @@ -139,6 +202,13 @@ public object DoubleLinearOpsTensorAlgebra : return eig to v } + /** + * Computes the determinant of a square matrix input, or of each square matrix in a batched input + * using LU factorization algorithm. + * + * @param epsilon error in the LU algorithm - permissible error when comparing the determinant of a matrix with zero + * @return the determinant. + */ public fun Tensor.detLU(epsilon: Double = 1e-9): DoubleTensor { checkSquareMatrix(tensor.shape) @@ -164,6 +234,15 @@ public object DoubleLinearOpsTensorAlgebra : return detTensor } + /** + * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input + * using LU factorization algorithm. + * Given a square matrix `a`, return the matrix `aInv` satisfying + * ``a.dot(aInv) = aInv.dot(a) = eye(a.shape[0])``. + * + * @param epsilon error in the LU algorithm - permissible error when comparing the determinant of a matrix with zero + * @return the multiplicative inverse of a matrix. + */ public fun Tensor.invLU(epsilon: Double = 1e-9): DoubleTensor { val (luTensor, pivotsTensor) = luFactor(epsilon) val invTensor = luTensor.zeroesLike() @@ -177,6 +256,18 @@ public object DoubleLinearOpsTensorAlgebra : return invTensor } + /** + * LUP decomposition + * + * Computes the LUP decomposition of a matrix or a batch of matrices. + * Given a tensor `input`, return tensors (P, L, U) satisfying ``P * input = L * U``, + * with `P` being a permutation matrix or batch of matrices, + * `L` being a lower triangular matrix or batch of matrices, + * `U` being an upper triangular matrix or batch of matrices. + * + * @param epsilon permissible error when comparing the determinant of a matrix with zero + * @return triple of P, L and U tensors + */ public fun Tensor.lu(epsilon: Double = 1e-9): Triple { val (lu, pivots) = this.luFactor(epsilon) return luPivot(lu, pivots) From a1cbd7a457a93619ad3033c66248b522137e4c46 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Thu, 6 May 2021 09:48:43 +0100 Subject: [PATCH 155/178] TensorLinearStructure doc --- .../kmath/tensors/core/algebras/TensorLinearStructure.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt index 5fbc7390f..d69d342ad 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt @@ -56,7 +56,12 @@ internal fun stepIndex(index: IntArray, shape: IntArray, nDim: Int): IntArray { return res } - +/** + * This [Strides] implemetation follow the last dimension first convention + * For more information: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.strides.html + * + * @param shape the shape of the tensor. + */ public class TensorLinearStructure(override val shape: IntArray) : Strides { override val strides: IntArray @@ -65,6 +70,7 @@ public class TensorLinearStructure(override val shape: IntArray) : Strides override fun index(offset: Int): IntArray = indexFromOffset(offset, strides, shape.size) + // TODO: documentation (Alya) public fun stepIndex(index: IntArray): IntArray = stepIndex(index, shape, shape.size) From 477e64e4d396ebff3a66f487b2b0cab7f507e6bd Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Thu, 6 May 2021 09:51:59 +0100 Subject: [PATCH 156/178] Typos corrected --- .../kmath/tensors/core/algebras/TensorLinearStructure.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt index d69d342ad..a5c01af55 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt @@ -57,7 +57,7 @@ internal fun stepIndex(index: IntArray, shape: IntArray, nDim: Int): IntArray { } /** - * This [Strides] implemetation follow the last dimension first convention + * This [Strides] implementation follows the last dimension first convention * For more information: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.strides.html * * @param shape the shape of the tensor. From 16bed539977c516645d0a980f4f22578a6fbec11 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Thu, 6 May 2021 09:59:58 +0100 Subject: [PATCH 157/178] Drop unused functionality in TensorLinearStructure --- .../algebras/DoubleLinearOpsTensorAlgebra.kt | 2 +- .../core/algebras/TensorLinearStructure.kt | 27 +------------------ 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt index d17dc70fe..430482613 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt @@ -155,7 +155,7 @@ public object DoubleLinearOpsTensorAlgebra : * @return triple `(U, S, V)`. */ public fun Tensor.svd(epsilon: Double): Triple { - val size = tensor.linearStructure.dim + val size = tensor.dimension val commonShape = tensor.shape.sliceArray(0 until size - 2) val (n, m) = tensor.shape.sliceArray(size - 2 until size) val uTensor = zeros(commonShape + intArrayOf(min(n, m), n)) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt index a5c01af55..68aa03311 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt @@ -39,45 +39,20 @@ internal fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): IntArra return res } -internal fun stepIndex(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 -} - /** * This [Strides] implementation follows the last dimension first convention * For more information: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.strides.html * * @param shape the shape of the tensor. */ -public class TensorLinearStructure(override val shape: IntArray) : Strides -{ +public class TensorLinearStructure(override val shape: IntArray) : Strides { override val strides: IntArray get() = stridesFromShape(shape) override fun index(offset: Int): IntArray = indexFromOffset(offset, strides, shape.size) - // TODO: documentation (Alya) - public fun stepIndex(index: IntArray): IntArray = - stepIndex(index, shape, shape.size) - override val linearSize: Int get() = shape.reduce(Int::times) - public val dim: Int - get() = shape.size - } \ No newline at end of file From 499cf85ff08ac65e7343e33af2f4f65cd9967b3f Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Thu, 6 May 2021 12:30:13 +0300 Subject: [PATCH 158/178] refactor BT + docs --- .../kmath/tensors/core/BufferedTensor.kt | 112 ++++-------------- .../kmath/tensors/core/DoubleTensor.kt | 19 +++ .../kscience/kmath/tensors/core/IntTensor.kt | 17 +++ .../kmath/tensors/core/tensorCasts.kt | 36 ++++++ .../kmath/tensors/core/tensorCastsUtils.kt | 42 +++++++ 5 files changed, 136 insertions(+), 90 deletions(-) create mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt create mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt create mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt create mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCastsUtils.kt diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 22a1ef1bf..e4ffccd96 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -1,116 +1,48 @@ package space.kscience.kmath.tensors.core -import space.kscience.kmath.nd.MutableBufferND import space.kscience.kmath.structures.* import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.algebras.TensorLinearStructure - -public open class BufferedTensor( +/** + * [Tensor] implementation provided with [MutableBuffer] + */ +public open class BufferedTensor internal constructor( override val shape: IntArray, internal val mutableBuffer: MutableBuffer, internal val bufferStart: Int ) : Tensor { + + /** + * [TensorLinearStructure] with the same shape + */ public val linearStructure: TensorLinearStructure get() = TensorLinearStructure(shape) + /** + * Number of elements in tensor + */ public val numElements: Int get() = linearStructure.linearSize + /** + * @param index [IntArray] with size equal to tensor dimension + * @return the element by multidimensional index + */ override fun get(index: IntArray): T = mutableBuffer[bufferStart + linearStructure.offset(index)] + /** + * @param index the [IntArray] with size equal to tensor dimension + * @param value the value to set + */ override fun set(index: IntArray, value: T) { mutableBuffer[bufferStart + linearStructure.offset(index)] = value } + /** + * @return the sequence of pairs multidimensional indices and values + */ override fun elements(): Sequence> = linearStructure.indices().map { it to this[it] } } - -public class IntTensor internal constructor( - shape: IntArray, - buffer: IntArray, - offset: Int = 0 -) : BufferedTensor(shape, IntBuffer(buffer), offset) - -public class DoubleTensor internal constructor( - shape: IntArray, - buffer: DoubleArray, - offset: Int = 0 -) : BufferedTensor(shape, DoubleBuffer(buffer), offset) { - override fun toString(): String = toPrettyString() -} - -internal fun BufferedTensor.asTensor(): IntTensor = - IntTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) - -internal fun BufferedTensor.asTensor(): DoubleTensor = - DoubleTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) - -internal fun Tensor.copyToBufferedTensor(): BufferedTensor = - BufferedTensor( - this.shape, - TensorLinearStructure(this.shape).indices().map(this::get).toMutableList().asMutableBuffer(), 0 - ) - -internal fun Tensor.toBufferedTensor(): BufferedTensor = when (this) { - is BufferedTensor -> this - is MutableBufferND -> if (this.strides.strides contentEquals TensorLinearStructure(this.shape).strides) - BufferedTensor(this.shape, this.mutableBuffer, 0) else this.copyToBufferedTensor() - else -> this.copyToBufferedTensor() -} - -internal val Tensor.tensor: DoubleTensor - get() = when (this) { - is DoubleTensor -> this - else -> this.toBufferedTensor().asTensor() - } - -internal val Tensor.tensor: IntTensor - get() = when (this) { - is IntTensor -> this - else -> this.toBufferedTensor().asTensor() - } - -public fun Tensor.toDoubleTensor(): DoubleTensor = this.tensor -public fun Tensor.toIntTensor(): IntTensor = this.tensor - -public fun Array.toDoubleTensor(): DoubleTensor { - val n = size - check(n > 0) { "An empty array cannot be casted to tensor" } - val m = first().size - check(m > 0) { "Inner arrays must have at least 1 argument" } - check(all { size == m }) { "Inner arrays must be the same size" } - - val shape = intArrayOf(n, m) - val buffer = this.flatMap { arr -> arr.map { it } }.toDoubleArray() - - return DoubleTensor(shape, buffer, 0) -} - - -public fun Array.toIntTensor(): IntTensor { - val n = size - check(n > 0) { "An empty array cannot be casted to tensor" } - val m = first().size - check(m > 0) { "Inner arrays must have at least 1 argument" } - check(all { size == m }) { "Inner arrays must be the same size" } - - val shape = intArrayOf(n, m) - val buffer = this.flatMap { arr -> arr.map { it } }.toIntArray() - - return IntTensor(shape, buffer, 0) -} - -public fun DoubleTensor.toDoubleArray(): DoubleArray { - return DoubleArray(numElements) { i -> - mutableBuffer[bufferStart + i] - } -} - -public fun IntTensor.toIntArray(): IntArray { - return IntArray(numElements) { i -> - mutableBuffer[bufferStart + i] - } -} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt new file mode 100644 index 000000000..e3143f5a7 --- /dev/null +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.core + +import space.kscience.kmath.structures.DoubleBuffer + +/** + * Default [BufferedTensor] implementation for [Double] values + */ +public class DoubleTensor internal constructor( + shape: IntArray, + buffer: DoubleArray, + offset: Int = 0 +) : BufferedTensor(shape, DoubleBuffer(buffer), offset) { + override fun toString(): String = toPrettyString() +} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt new file mode 100644 index 000000000..ae1e6c8c8 --- /dev/null +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.core + +import space.kscience.kmath.structures.IntBuffer + +/** + * Default [BufferedTensor] implementation for [Int] values + */ +public class IntTensor internal constructor( + shape: IntArray, + buffer: IntArray, + offset: Int = 0 +) : BufferedTensor(shape, IntBuffer(buffer), offset) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt new file mode 100644 index 000000000..6254ce751 --- /dev/null +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.core + +import space.kscience.kmath.tensors.api.Tensor + +/** + * Casts [Tensor] to [DoubleTensor] + */ +public fun Tensor.toDoubleTensor(): DoubleTensor = this.tensor + +/** + * Casts [Tensor] to [IntTensor] + */ +public fun Tensor.toIntTensor(): IntTensor = this.tensor + +/** + * @return [DoubleArray] of tensor elements + */ +public fun DoubleTensor.toDoubleArray(): DoubleArray { + return DoubleArray(numElements) { i -> + mutableBuffer[bufferStart + i] + } +} + +/** + * @return [IntArray] of tensor elements + */ +public fun IntTensor.toIntArray(): IntArray { + return IntArray(numElements) { i -> + mutableBuffer[bufferStart + i] + } +} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCastsUtils.kt new file mode 100644 index 000000000..31de6919f --- /dev/null +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCastsUtils.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.core + +import space.kscience.kmath.nd.MutableBufferND +import space.kscience.kmath.structures.asMutableBuffer +import space.kscience.kmath.tensors.api.Tensor +import space.kscience.kmath.tensors.core.algebras.TensorLinearStructure + +internal fun BufferedTensor.asTensor(): IntTensor = + IntTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) + +internal fun BufferedTensor.asTensor(): DoubleTensor = + DoubleTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) + +internal fun Tensor.copyToBufferedTensor(): BufferedTensor = + BufferedTensor( + this.shape, + TensorLinearStructure(this.shape).indices().map(this::get).toMutableList().asMutableBuffer(), 0 + ) + +internal fun Tensor.toBufferedTensor(): BufferedTensor = when (this) { + is BufferedTensor -> this + is MutableBufferND -> if (this.strides.strides contentEquals TensorLinearStructure(this.shape).strides) + BufferedTensor(this.shape, this.mutableBuffer, 0) else this.copyToBufferedTensor() + else -> this.copyToBufferedTensor() +} + +internal val Tensor.tensor: DoubleTensor + get() = when (this) { + is DoubleTensor -> this + else -> this.toBufferedTensor().asTensor() + } + +internal val Tensor.tensor: IntTensor + get() = when (this) { + is IntTensor -> this + else -> this.toBufferedTensor().asTensor() + } \ No newline at end of file From 35928e7960bd5676820b751490be057fa62409ff Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Thu, 6 May 2021 10:52:37 +0100 Subject: [PATCH 159/178] minor corrections --- .../kscience/kmath/tensors/core/BufferedTensor.kt | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index e4ffccd96..e8c0556c2 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -5,7 +5,7 @@ import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.algebras.TensorLinearStructure /** - * [Tensor] implementation provided with [MutableBuffer] + * Represents [Tensor] over a [MutableBuffer] intended to be used through [DoubleTensor] and [IntTensor] */ public open class BufferedTensor internal constructor( override val shape: IntArray, @@ -14,7 +14,7 @@ public open class BufferedTensor internal constructor( ) : Tensor { /** - * [TensorLinearStructure] with the same shape + * Buffer strides based on [TensorLinearStructure] implementation */ public val linearStructure: TensorLinearStructure get() = TensorLinearStructure(shape) @@ -25,23 +25,12 @@ public open class BufferedTensor internal constructor( public val numElements: Int get() = linearStructure.linearSize - /** - * @param index [IntArray] with size equal to tensor dimension - * @return the element by multidimensional index - */ override fun get(index: IntArray): T = mutableBuffer[bufferStart + linearStructure.offset(index)] - /** - * @param index the [IntArray] with size equal to tensor dimension - * @param value the value to set - */ override fun set(index: IntArray, value: T) { mutableBuffer[bufferStart + linearStructure.offset(index)] = value } - /** - * @return the sequence of pairs multidimensional indices and values - */ override fun elements(): Sequence> = linearStructure.indices().map { it to this[it] } From 8ac253b9fe112bfe64d467c07db9dc9b9ed74e52 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Thu, 6 May 2021 14:09:47 +0300 Subject: [PATCH 160/178] cov + docs --- .../tensors/api/AnalyticTensorAlgebra.kt | 10 +++++++ .../algebras/DoubleAnalyticTensorAlgebra.kt | 24 ++++++++++++++++- .../core/algebras/DoubleTensorAlgebra.kt | 27 +++++++++++++------ 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt index aa5678b31..69e88c28f 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt @@ -68,6 +68,16 @@ public interface AnalyticTensorAlgebra : */ public fun Tensor.variance(dim: Int, keepDim: Boolean): Tensor + /** + * Returns the covariance matrix M of given vectors. + * + * M[i, j] contains covariance of i-th and j-th given vectors + * + * @param tensors the [List] of 1-dimensional tensors with same shape + * @return the covariance matrix + */ + public fun cov(tensors: List>): Tensor + //For information: https://pytorch.org/docs/stable/generated/torch.exp.html public fun Tensor.exp(): Tensor diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt index 4a1f360e3..23a2fa282 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt @@ -57,6 +57,28 @@ public object DoubleAnalyticTensorAlgebra : keepDim ) + private fun cov(x: DoubleTensor, y:DoubleTensor): Double{ + val n = x.shape[0] + return ((x - x.mean()) * (y - y.mean())).mean() * n / (n - 1) + } + + override fun cov(tensors: List>): DoubleTensor { + check(tensors.isNotEmpty()) { "List must have at least 1 element" } + val n = tensors.size + val m = tensors[0].shape[0] + check(tensors.all { it.shape contentEquals intArrayOf(m) }) { "Tensors must have same shapes" } + val resTensor = DoubleTensor( + intArrayOf(n, n), + DoubleArray(n * n) {0.0} + ) + for (i in 0 until n){ + for (j in 0 until n){ + resTensor[intArrayOf(i, j)] = cov(tensors[i].tensor, tensors[j].tensor) + } + } + return resTensor + } + override fun Tensor.exp(): DoubleTensor = tensor.map(::exp) override fun Tensor.ln(): DoubleTensor = tensor.map(::ln) @@ -91,4 +113,4 @@ public object DoubleAnalyticTensorAlgebra : override fun Tensor.floor(): DoubleTensor = tensor.map(::floor) -} \ No newline at end of file +} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index d220bdd9a..74ef63ab7 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -401,19 +401,31 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { public fun Tensor.randomNormalLike(seed: Long = 0): DoubleTensor = DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed)) - // stack tensors by axis 0 - public fun stack(tensors: List): DoubleTensor { - val shape = tensors.firstOrNull()?.shape - check(shape != null) { "Collection must have at least 1 element" } - check(tensors.all { it.shape contentEquals shape }) { "Stacking tensors must have same shapes" } + /** + * Concatenates a sequence of tensors along a new dimension. + * + * @param tensors the [List] of tensors with same shapes to concatenate + * @param dim the dimension to insert + * @return tensor with concatenation result + */ + public fun stack(tensors: List>, dim: Int = 0): DoubleTensor { + check(dim == 0) { "Stack by non-zero dimension not implemented yet" } + check(tensors.isNotEmpty()) { "List must have at least 1 element" } + val shape = tensors[0].shape + check(tensors.all { it.shape contentEquals shape }) { "Tensors must have same shapes" } val resShape = intArrayOf(tensors.size) + shape val resBuffer = tensors.flatMap { - it.tensor.mutableBuffer.array().drop(it.bufferStart).take(it.numElements) + it.tensor.mutableBuffer.array().drop(it.tensor.bufferStart).take(it.tensor.numElements) }.toDoubleArray() return DoubleTensor(resShape, resBuffer, 0) } - // build tensor from this rows by given indices + /** + * Build tensor from rows of input tensor + * + * @param indices the [IntArray] of 1-dimensional indices + * @return tensor with rows corresponding to rows by [indices] + */ public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor { return stack(indices.map { this[it] }) } @@ -450,7 +462,6 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { override fun Tensor.sum(dim: Int, keepDim: Boolean): DoubleTensor = foldDim({ x -> x.sum() }, dim, keepDim) - override fun Tensor.min(): Double = this.fold { it.minOrNull()!! } override fun Tensor.min(dim: Int, keepDim: Boolean): DoubleTensor = From dc22bd84986d14f6d82209a106d6413e3bd609e2 Mon Sep 17 00:00:00 2001 From: AlyaNovikova Date: Thu, 6 May 2021 14:23:57 +0300 Subject: [PATCH 161/178] add documentation to DoubleTensorAlgebra --- .../core/algebras/DoubleTensorAlgebra.kt | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index d220bdd9a..2cad85a09 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -23,6 +23,9 @@ import space.kscience.kmath.tensors.core.getRandomNormals import space.kscience.kmath.tensors.core.minusIndexFrom import kotlin.math.abs +/** + * Implementation of basic operations over double tensors and basic algebra operations on them. + */ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { public companion object : DoubleTensorAlgebra() @@ -34,6 +37,13 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return tensor.mutableBuffer.array()[tensor.bufferStart] } + /** + * Constructs a tensor with the specified shape and data. + * + * @param shape the desired shape for the tensor. + * @param buffer one-dimensional data array. + * @return tensor with the [shape] shape and [buffer] data. + */ public fun fromArray(shape: IntArray, buffer: DoubleArray): DoubleTensor { checkEmptyShape(shape) checkEmptyDoubleBuffer(buffer) @@ -48,26 +58,67 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return DoubleTensor(newShape, tensor.mutableBuffer.array(), newStart) } + /** + * Creates a tensor of a given shape and fills all elements with a given value. + * + * @param value the value to fill the output tensor with. + * @param shape array of integers defining the shape of the output tensor. + * @return tensor with the [shape] shape and filled with [value]. + */ public fun full(value: Double, shape: IntArray): DoubleTensor { checkEmptyShape(shape) val buffer = DoubleArray(shape.reduce(Int::times)) { value } return DoubleTensor(shape, buffer) } + /** + * Returns a tensor with the same shape as `input` filled with [value]. + * + * @param value the value to fill the output tensor with. + * @return tensor with the `input` tensor shape and filled with [value]. + */ public fun Tensor.fullLike(value: Double): DoubleTensor { val shape = tensor.shape val buffer = DoubleArray(tensor.numElements) { value } return DoubleTensor(shape, buffer) } + /** + * Returns a tensor filled with the scalar value 0.0, with the shape defined by the variable argument [shape]. + * + * @param shape array of integers defining the shape of the output tensor. + * @return tensor filled with the scalar value 0.0, with the [shape] shape. + */ public fun zeros(shape: IntArray): DoubleTensor = full(0.0, shape) + /** + * Returns a tensor filled with the scalar value 0.0, with the same shape as a given array. + * + * @return tensor filled with the scalar value 0.0, with the same shape as `input` tensor. + */ public fun Tensor.zeroesLike(): DoubleTensor = tensor.fullLike(0.0) + /** + * Returns a tensor filled with the scalar value 1.0, with the shape defined by the variable argument [shape]. + * + * @param shape array of integers defining the shape of the output tensor. + * @return tensor filled with the scalar value 1.0, with the [shape] shape. + */ public fun ones(shape: IntArray): DoubleTensor = full(1.0, shape) + /** + * Returns a tensor filled with the scalar value 1.0, with the same shape as a given array. + * + * @return tensor filled with the scalar value 1.0, with the same shape as `input` tensor. + */ public fun Tensor.onesLike(): DoubleTensor = tensor.fullLike(1.0) + /** + * Returns a 2-D tensor with shape ([n], [n]), with ones on the diagonal and zeros elsewhere. + * + * @param n the number of rows and columns + * @return a 2-D tensor with ones on the diagonal and zeros elsewhere. + */ public fun eye(n: Int): DoubleTensor { val shape = intArrayOf(n, n) val buffer = DoubleArray(n * n) { 0.0 } @@ -78,6 +129,11 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return res } + /** + * Return a copy of the tensor. + * + * @return a copy of the `input` tensor with a copied buffer. + */ public fun Tensor.copy(): DoubleTensor { return DoubleTensor(tensor.shape, tensor.mutableBuffer.array().copyOf(), tensor.bufferStart) } @@ -359,7 +415,6 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return resTensor.tensor } - public fun Tensor.map(transform: (Double) -> Double): DoubleTensor { return DoubleTensor( tensor.shape, From 90149e396561004e781b390f87c51361e6a9e82f Mon Sep 17 00:00:00 2001 From: AlyaNovikova Date: Thu, 6 May 2021 14:42:15 +0300 Subject: [PATCH 162/178] add documentation to map and randomNormal function --- .../core/algebras/DoubleTensorAlgebra.kt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index d8b59daa7..8c76de0de 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -415,6 +415,12 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return resTensor.tensor } + /** + * Applies the [transform] function to each element of the tensor and returns the resulting modified tensor. + * + * @param transform the function to be applied to each element of the tensor. + * @return the resulting tensor after applying the function. + */ public fun Tensor.map(transform: (Double) -> Double): DoubleTensor { return DoubleTensor( tensor.shape, @@ -423,10 +429,24 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { ) } + /** + * Compares element-wise two tensors with a specified precision. + * + * @param other the tensor to compare with `input` tensor. + * @param epsilon permissible error when comparing two Double values. + * @return true if two tensors have the same shape and elements, false otherwise. + */ public fun Tensor.eq(other: Tensor, epsilon: Double): Boolean { return tensor.eq(other) { x, y -> abs(x - y) < epsilon } } + /** + * Compares element-wise two tensors. + * Comparison of two Double values occurs with 1e-5 precision. + * + * @param other the tensor to compare with `input` tensor. + * @return true if two tensors have the same shape and elements, false otherwise. + */ public infix fun Tensor.eq(other: Tensor): Boolean = tensor.eq(other, 1e-5) private fun Tensor.eq( @@ -450,9 +470,25 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return true } + /** + * Returns a tensor of random numbers drawn from normal distributions with 0.0 mean and 1.0 standard deviation. + * + * @param shape the desired shape for the output tensor. + * @param seed the random seed of the pseudo-random number generator. + * @return tensor of a given shape filled with numbers from the normal distribution + * with 0.0 mean and 1.0 standard deviation. + */ public fun randomNormal(shape: IntArray, seed: Long = 0): DoubleTensor = DoubleTensor(shape, getRandomNormals(shape.reduce(Int::times), seed)) + /** + * Returns a tensor with the same shape as `input` of random numbers drawn from normal distributions + * with 0.0 mean and 1.0 standard deviation. + * + * @param seed the random seed of the pseudo-random number generator. + * @return tensor with the same shape as `input` filled with numbers from the normal distribution + * with 0.0 mean and 1.0 standard deviation. + */ public fun Tensor.randomNormalLike(seed: Long = 0): DoubleTensor = DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed)) From 5fe1320855941167afba93fb0f3d0beb855c834e Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Thu, 6 May 2021 12:59:21 +0100 Subject: [PATCH 163/178] minor corrections --- .../kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index 8c76de0de..1c8eacf66 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -493,7 +493,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed)) /** - * Concatenates a sequence of tensors along a new dimension. + * Concatenates a sequence of tensors along the first dimension. * * @param tensors the [List] of tensors with same shapes to concatenate * @param dim the dimension to insert From db5378c9f4ab3ff4e84d815d9db4686015330bf9 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Thu, 6 May 2021 16:29:21 +0300 Subject: [PATCH 164/178] PCA example --- .../space/kscience/kmath/tensors/PCA.kt | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt new file mode 100644 index 000000000..1d72b2326 --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors + +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra +import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra +import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra + +const val seed = 100500L + +// simple PCA + +fun main(){ + DoubleAnalyticTensorAlgebra { + + // assume x is range from 0 until 10 + val x = fromArray( + intArrayOf(10), + (0 until 10).toList().map { it.toDouble() }.toDoubleArray() + ) + + // take y dependent on x with noise + val y = 2.0 * x + (3.0 + x.randomNormalLike(seed) * 1.5) + + println("x:\n$x") + println("y:\n$y") + + // stack them into single dataset + val dataset = stack(listOf(x, y)).transpose() + + // normalize both x and y + val xMean = x.mean() + val yMean = y.mean() + + val xStd = x.std() + val yStd = y.std() + + val xScaled = (x - xMean) / xStd + val yScaled = (y - yMean) / yStd + + // save means ans standard deviations for further recovery + val mean = fromArray( + intArrayOf(2), + doubleArrayOf(xMean, yMean) + ) + println("Means:\n$mean") + + val std = fromArray( + intArrayOf(2), + doubleArrayOf(xStd, yStd) + ) + println("Standard deviations:\n$std") + + // calculate the covariance matrix of scaled x and y + val covMatrix = cov(listOf(xScaled, yScaled)) + println("Covariance matrix:\n$covMatrix") + + // and find out eigenvector of it + val (_, evecs) = DoubleLinearOpsTensorAlgebra {covMatrix.symEig()} + val v = evecs[0] + println("Eigenvector:\n$v") + + // reduce dimension of dataset + val datasetReduced = v dot stack(listOf(xScaled, yScaled)) + println("Reduced data:\n$datasetReduced") + + // we can restore original data from reduced data. + // for example, find 7th element of dataset + val n = 7 + val restored = BroadcastDoubleTensorAlgebra{(datasetReduced[n] dot v.view(intArrayOf(1, 2))) * std + mean} + println("Original value:\n${dataset[n]}") + println("Restored value:\n$restored") + } +} From febe526325150c2b716f233956a12e69fcb44804 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Thu, 6 May 2021 14:50:05 +0100 Subject: [PATCH 165/178] Update stack docs --- .../kmath/tensors/core/algebras/DoubleTensorAlgebra.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index 1c8eacf66..9500fbdec 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -493,14 +493,12 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed)) /** - * Concatenates a sequence of tensors along the first dimension. + * Concatenates a sequence of tensors with equal shapes along the first dimension. * * @param tensors the [List] of tensors with same shapes to concatenate - * @param dim the dimension to insert * @return tensor with concatenation result */ - public fun stack(tensors: List>, dim: Int = 0): DoubleTensor { - check(dim == 0) { "Stack by non-zero dimension not implemented yet" } + public fun stack(tensors: List>): DoubleTensor { check(tensors.isNotEmpty()) { "List must have at least 1 element" } val shape = tensors[0].shape check(tensors.all { it.shape contentEquals shape }) { "Tensors must have same shapes" } From 1b1a078deaee681c99603737d11eecefe0411db4 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Fri, 7 May 2021 03:22:34 +0300 Subject: [PATCH 166/178] neural network! --- .../kscience/kmath/tensors/NeuralNetwork.kt | 245 ++++++++++++++++++ .../space/kscience/kmath/tensors/PCA.kt | 5 +- .../kmath/tensors/api/TensorAlgebra.kt | 13 +- .../core/algebras/DoubleTensorAlgebra.kt | 5 + 4 files changed, 266 insertions(+), 2 deletions(-) create mode 100644 examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt new file mode 100644 index 000000000..ea863988c --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt @@ -0,0 +1,245 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors + +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.tensors.core.DoubleTensor +import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra +import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra +import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra +import space.kscience.kmath.tensors.core.toDoubleArray +import kotlin.math.sqrt + +const val seed = 100500L + +// Simple feedforward neural network with backpropagation training + +// interface of network layer +interface Layer { + fun forward(input: DoubleTensor): DoubleTensor + fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor +} + +// activation layer +open class Activation( + val activation: (DoubleTensor) -> DoubleTensor, + val activationDer: (DoubleTensor) -> DoubleTensor +) : Layer { + override fun forward(input: DoubleTensor): DoubleTensor { + return activation(input) + } + + override fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor { + return DoubleTensorAlgebra { outputError * activationDer(input) } + } +} + +fun relu(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { + x.map { if (it > 0) it else 0.0 } +} + +fun reluDer(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { + x.map { if (it > 0) 1.0 else 0.0 } +} + +// activation layer with relu activator +class ReLU : Activation(::relu, ::reluDer) + +fun sigmoid(x: DoubleTensor): DoubleTensor = DoubleAnalyticTensorAlgebra { + 1.0 / (1.0 + (-x).exp()) +} + +fun sigmoidDer(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { + sigmoid(x) * (1.0 - sigmoid(x)) +} + +// activation layer with sigmoid activator +class Sigmoid : Activation(::sigmoid, ::sigmoidDer) + +// dense layer +class Dense( + private val inputUnits: Int, + private val outputUnits: Int, + private val learningRate: Double = 0.1 +) : Layer { + + private val weights: DoubleTensor = DoubleTensorAlgebra { + randomNormal( + intArrayOf(inputUnits, outputUnits), + seed + ) * sqrt(2.0 / (inputUnits + outputUnits)) + } + + private val bias: DoubleTensor = DoubleTensorAlgebra { zeros(intArrayOf(outputUnits)) } + + override fun forward(input: DoubleTensor): DoubleTensor { + return BroadcastDoubleTensorAlgebra { (input dot weights) + bias } + } + + override fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { + val gradInput = outputError dot weights.transpose() + + val gradW = input.transpose() dot outputError + val gradBias = DoubleAnalyticTensorAlgebra { + outputError.mean(dim = 0, keepDim = false) * input.shape[0].toDouble() + } + + weights -= learningRate * gradW + bias -= learningRate * gradBias + + gradInput + } + +} + +// simple accuracy equal to the proportion of correct answers +fun accuracy(yPred: DoubleTensor, yTrue: DoubleTensor): Double { + check(yPred.shape contentEquals yTrue.shape) + val n = yPred.shape[0] + var correctCnt = 0 + for (i in 0 until n) { + if (yPred[intArrayOf(i, 0)] == yTrue[intArrayOf(i, 0)]) { + correctCnt += 1 + } + } + return correctCnt.toDouble() / n.toDouble() +} + +// neural network class +class NeuralNetwork(private val layers: List) { + private fun softMaxLoss(yPred: DoubleTensor, yTrue: DoubleTensor): DoubleTensor = DoubleAnalyticTensorAlgebra { + + val onesForAnswers = yPred.zeroesLike() + yTrue.toDoubleArray().forEachIndexed { index, labelDouble -> + val label = labelDouble.toInt() + onesForAnswers[intArrayOf(index, label)] = 1.0 + } + + val softmaxValue = BroadcastDoubleTensorAlgebra { yPred.exp() / yPred.exp().sum(dim = 1, keepDim = true) } + + (-onesForAnswers + softmaxValue) / (yPred.shape[0].toDouble()) + } + + @OptIn(ExperimentalStdlibApi::class) + private fun forward(x: DoubleTensor): List { + var input = x + + return buildList { + layers.forEach { layer -> + val output = layer.forward(input) + add(output) + input = output + } + } + } + + @OptIn(ExperimentalStdlibApi::class) + private fun train(xTrain: DoubleTensor, yTrain: DoubleTensor) { + val layerInputs = buildList { + add(xTrain) + addAll(forward(xTrain)) + } + + var lossGrad = softMaxLoss(layerInputs.last(), yTrain) + + layers.zip(layerInputs).reversed().forEach { (layer, input) -> + lossGrad = layer.backward(input, lossGrad) + } + } + + fun fit(xTrain: DoubleTensor, yTrain: DoubleTensor, batchSize: Int, epochs: Int) = DoubleTensorAlgebra { + fun iterBatch(x: DoubleTensor, y: DoubleTensor): Sequence> = sequence { + val n = x.shape[0] + val shuffledIndices = (0 until n).shuffled() + for (i in 0 until n step batchSize) { + val excerptIndices = shuffledIndices.drop(i).take(batchSize).toIntArray() + val batch = x.rowsByIndices(excerptIndices) to y.rowsByIndices(excerptIndices) + yield(batch) + } + } + + for (epoch in 0 until epochs) { + println("Epoch ${epoch + 1}/$epochs") + for ((xBatch, yBatch) in iterBatch(xTrain, yTrain)) { + train(xBatch, yBatch) + } + println("Accuracy:${accuracy(yTrain, predict(xTrain).argMax(1, true))}") + } + } + + fun predict(x: DoubleTensor): DoubleTensor { + return forward(x).last() + } + +} + + + +@OptIn(ExperimentalStdlibApi::class) +fun main() { + DoubleTensorAlgebra { + val features = 5 + val sampleSize = 250 + val trainSize = 180 + val testSize = sampleSize - trainSize + + // take sample of features from normal distribution + val x = randomNormal(intArrayOf(sampleSize, features), seed) * 2.5 + BroadcastDoubleTensorAlgebra { + x += fromArray( + intArrayOf(5), + doubleArrayOf(0.0, -1.0, -2.5, -3.0, 5.5) // rows means + ) + } + + // define class like '1' if the sum of features > 0 and '0' otherwise + val y = fromArray( + intArrayOf(sampleSize, 1), + DoubleArray(sampleSize) { i -> + if (x[i].sum() > 0.0) { + 1.0 + } else { + 0.0 + } + } + ) + + // split train ans test + val trainIndices = (0 until trainSize).toList().toIntArray() + val testIndices = (trainSize until sampleSize).toList().toIntArray() + + val xTrain = x.rowsByIndices(trainIndices) + val yTrain = y.rowsByIndices(trainIndices) + + val xTest = x.rowsByIndices(testIndices) + val yTest = y.rowsByIndices(testIndices) + + // build model + val layers = buildList { + add(Dense(features, 64)) + add(ReLU()) + add(Dense(64, 16)) + add(ReLU()) + add(Dense(16, 2)) + add(Sigmoid()) + } + val model = NeuralNetwork(layers) + + // fit it with train data + model.fit(xTrain, yTrain, batchSize = 20, epochs = 10) + + // make prediction + val prediction = model.predict(xTest) + + // process raw prediction via argMax + val predictionLabels = prediction.argMax(1, true) + + // find out accuracy + val acc = accuracy(yTest, predictionLabels) + println("Test accuracy:$acc") + + } +} diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt index 1d72b2326..ee25b63a3 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt @@ -10,11 +10,14 @@ import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra -const val seed = 100500L + // simple PCA fun main(){ + val seed = 100500L + + // work in context with analytic methods DoubleAnalyticTensorAlgebra { // assume x is range from 0 until 10 diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index b0a0f9618..417cff87f 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -305,5 +305,16 @@ public interface TensorAlgebra: Algebra> { */ public fun Tensor.max(dim: Int, keepDim: Boolean): Tensor - + /** + * Returns the index of maximum value of each row of the input tensor in the given dimension [dim]. + * + * If [keepDim] is true, the output tensor is of the same size as + * input except in the dimension [dim] where it is of size 1. + * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. + * + * @param dim the dimension to reduce. + * @param keepDim whether the output tensor has [dim] retained or not. + * @return the the index of maximum value of each row of the input tensor in the given dimension [dim]. + */ + public fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index 9500fbdec..6fac0a0ec 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -561,4 +561,9 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { override fun Tensor.max(dim: Int, keepDim: Boolean): DoubleTensor = foldDim({ x -> x.maxOrNull()!! }, dim, keepDim) + override fun Tensor.argMax(dim: Int, keepDim: Boolean): DoubleTensor = + foldDim({ x -> + x.withIndex().maxByOrNull { it.value }?.index!!.toDouble() + }, dim, keepDim) + } From 14ca7cdd31e14855c95a51b8143bf80aae02feb9 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Fri, 7 May 2021 13:00:20 +0300 Subject: [PATCH 167/178] fixes --- .../kmath/tensors/api/LinearOpsTensorAlgebra.kt | 15 ++++++++------- .../kscience/kmath/tensors/api/TensorAlgebra.kt | 2 +- .../tensors/core/algebras/DoubleTensorAlgebra.kt | 9 ++++----- .../core/algebras/TensorLinearStructure.kt | 3 +-- .../kscience/kmath/tensors/core/tensorCasts.kt | 2 +- .../kmath/tensors/core/tensorCastsUtils.kt | 2 +- 6 files changed, 16 insertions(+), 17 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt index ec070b6bd..4a325ab4e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -23,8 +23,8 @@ public interface LinearOpsTensorAlgebra : /** * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input. - * Given a square matrix `a`, return the matrix `aInv` satisfying - * ``a.dot(aInv) = aInv.dot(a) = eye(a.shape[0])``. + * Given a square matrix `A`, return the matrix `AInv` satisfying + * `A dot AInv = AInv dot A = eye(a.shape[0])`. * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.inv * * @return the multiplicative inverse of a matrix. @@ -37,7 +37,7 @@ public interface LinearOpsTensorAlgebra : * Computes the Cholesky decomposition of a Hermitian (or symmetric for real-valued matrices) * positive-definite matrix or the Cholesky decompositions for a batch of such matrices. * Each decomposition has the form: - * Given a tensor `input`, return the tensor `L` satisfying ``input = L * L.H``, + * Given a tensor `input`, return the tensor `L` satisfying `input = L dot L.H`, * where L is a lower-triangular matrix and L.H is the conjugate transpose of L, * which is just a transpose for the case of real-valued input matrices. * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.cholesky @@ -50,7 +50,7 @@ public interface LinearOpsTensorAlgebra : * QR decomposition. * * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `(Q, R)` of tensors. - * Given a tensor `input`, return tensors (Q, R) satisfying ``input = Q * R``, + * Given a tensor `input`, return tensors (Q, R) satisfying ``input = Q dot R``, * with `Q` being an orthogonal matrix or batch of orthogonal matrices * and `R` being an upper triangular matrix or batch of upper triangular matrices. * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.qr @@ -63,7 +63,7 @@ public interface LinearOpsTensorAlgebra : * LUP decomposition * * Computes the LUP decomposition of a matrix or a batch of matrices. - * Given a tensor `input`, return tensors (P, L, U) satisfying ``P * input = L * U``, + * Given a tensor `input`, return tensors (P, L, U) satisfying `P dot input = L dot U`, * with `P` being a permutation matrix or batch of matrices, * `L` being a lower triangular matrix or batch of matrices, * `U` being an upper triangular matrix or batch of matrices. @@ -77,7 +77,8 @@ public interface LinearOpsTensorAlgebra : * * Computes the singular value decomposition of either a matrix or batch of matrices `input`. * The singular value decomposition is represented as a triple `(U, S, V)`, - * such that ``input = U.dot(diagonalEmbedding(S).dot(V.T))``. + * such that `input = U dot diagonalEmbedding(S) dot V.H`, + * where V.H is the conjugate transpose of V. * If input is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as input. * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd * @@ -94,4 +95,4 @@ public interface LinearOpsTensorAlgebra : */ public fun Tensor.symEig(): Pair, Tensor> -} \ No newline at end of file +} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 417cff87f..e7f8dc7ae 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -288,7 +288,7 @@ public interface TensorAlgebra: Algebra> { public fun Tensor.min(dim: Int, keepDim: Boolean): Tensor /** - * @return the maximum value of all elements in the input tensor. + * Returns the maximum value of all elements in the input tensor. */ public fun Tensor.max(): T diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index 6fac0a0ec..e5d41f856 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -343,7 +343,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { val m2 = newOther.shape[newOther.shape.size - 2] val n = newOther.shape[newOther.shape.size - 1] check(m1 == m2) { - throw RuntimeException("Tensors dot operation dimension mismatch: ($l, $m1) x ($m2, $n)") + "Tensors dot operation dimension mismatch: ($l, $m1) x ($m2, $n)" } val resShape = newThis.shape.sliceArray(0..(newThis.shape.size - 2)) + intArrayOf(newOther.shape.last()) @@ -436,9 +436,8 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { * @param epsilon permissible error when comparing two Double values. * @return true if two tensors have the same shape and elements, false otherwise. */ - public fun Tensor.eq(other: Tensor, epsilon: Double): Boolean { - return tensor.eq(other) { x, y -> abs(x - y) < epsilon } - } + public fun Tensor.eq(other: Tensor, epsilon: Double): Boolean = + tensor.eq(other) { x, y -> abs(x - y) < epsilon } /** * Compares element-wise two tensors. @@ -510,7 +509,7 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { } /** - * Build tensor from rows of input tensor + * Builds tensor from rows of input tensor * * @param indices the [IntArray] of 1-dimensional indices * @return tensor with rows corresponding to rows by [indices] diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt index 68aa03311..f65e2b955 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt @@ -23,7 +23,6 @@ internal fun stridesFromShape(shape: IntArray): IntArray { current-- } return res - } internal fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): IntArray { @@ -55,4 +54,4 @@ public class TensorLinearStructure(override val shape: IntArray) : Strides { override val linearSize: Int get() = shape.reduce(Int::times) -} \ No newline at end of file +} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt index 6254ce751..2743a5218 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt @@ -33,4 +33,4 @@ public fun IntTensor.toIntArray(): IntArray { return IntArray(numElements) { i -> mutableBuffer[bufferStart + i] } -} \ No newline at end of file +} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCastsUtils.kt index 31de6919f..70e3b9c61 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCastsUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCastsUtils.kt @@ -39,4 +39,4 @@ internal val Tensor.tensor: IntTensor get() = when (this) { is IntTensor -> this else -> this.toBufferedTensor().asTensor() - } \ No newline at end of file + } From 0920e21d622e85e95e25b6d28d906309dab8d875 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 7 May 2021 12:52:17 +0100 Subject: [PATCH 168/178] Merging implementations together --- .../kmath/tensors/DataSetNormalization.kt | 20 +- .../tensors/LinearSystemSolvingWithLUP.kt | 4 +- .../kscience/kmath/tensors/NeuralNetwork.kt | 26 +- .../kscience/kmath/tensors/OLSWithSVD.kt | 9 +- .../space/kscience/kmath/tensors/PCA.kt | 11 +- .../tensors/api/AnalyticTensorAlgebra.kt | 3 +- .../tensors/api/LinearOpsTensorAlgebra.kt | 3 +- .../api/TensorPartialDivisionAlgebra.kt | 3 +- .../kmath/tensors/core/DoubleTensor.kt | 1 + .../algebras/BroadcastDoubleTensorAlgebra.kt | 6 +- .../algebras/DoubleAnalyticTensorAlgebra.kt | 116 ------ .../algebras/DoubleLinearOpsTensorAlgebra.kt | 278 ------------- .../core/algebras/DoubleTensorAlgebra.kt | 385 +++++++++++++++++- .../core/{ => internal}/broadcastUtils.kt | 8 +- .../tensors/core/{ => internal}/checks.kt | 11 +- .../tensors/core/{ => internal}/linUtils.kt | 27 +- .../core/{ => internal}/tensorCastsUtils.kt | 5 +- .../tensors/core/{ => internal}/utils.kt | 9 +- .../kmath/tensors/core/tensorCasts.kt | 1 + .../kmath/tensors/core/TestBroadcasting.kt | 1 + .../core/TestDoubleAnalyticTensorAlgebra.kt | 31 +- .../core/TestDoubleLinearOpsAlgebra.kt | 30 +- .../kmath/tensors/core/TestDoubleTensor.kt | 4 + .../tensors/core/TestDoubleTensorAlgebra.kt | 1 + 24 files changed, 488 insertions(+), 505 deletions(-) delete mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt delete mode 100644 kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{ => internal}/broadcastUtils.kt (94%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{ => internal}/checks.kt (83%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{ => internal}/linUtils.kt (91%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{ => internal}/tensorCastsUtils.kt (88%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{ => internal}/utils.kt (91%) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt index 4d53d940b..d029348f2 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt @@ -7,22 +7,22 @@ package space.kscience.kmath.tensors import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra -import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra + // Dataset normalization fun main() { - // work in context with analytic methods - DoubleAnalyticTensorAlgebra { + // work in context with broadcast methods + BroadcastDoubleTensorAlgebra { // take dataset of 5-element vectors from normal distribution val dataset = randomNormal(intArrayOf(100, 5)) * 1.5 // all elements from N(0, 1.5) - BroadcastDoubleTensorAlgebra { - dataset += fromArray( - intArrayOf(5), - doubleArrayOf(0.0, 1.0, 1.5, 3.0, 5.0) // rows means - ) - } + + dataset += fromArray( + intArrayOf(5), + doubleArrayOf(0.0, 1.0, 1.5, 3.0, 5.0) // rows means + ) + // find out mean and standard deviation of each column val mean = dataset.mean(0, false) @@ -36,7 +36,7 @@ fun main() { println("Maximum:\n${dataset.max(0, false)}") // now we can scale dataset with mean normalization - val datasetScaled = BroadcastDoubleTensorAlgebra { (dataset - mean) / std } + val datasetScaled = (dataset - mean) / std // find out mean and std of scaled dataset diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt index bd8233ccc..c0ece04ca 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt @@ -7,14 +7,14 @@ package space.kscience.kmath.tensors import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra +import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra // solving linear system with LUP decomposition fun main () { // work in context with linear operations - DoubleLinearOpsTensorAlgebra { + BroadcastDoubleTensorAlgebra { // set true value of x val trueX = fromArray( diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt index ea863988c..1998b8d16 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt @@ -8,7 +8,6 @@ package space.kscience.kmath.tensors import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra -import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.toDoubleArray import kotlin.math.sqrt @@ -48,7 +47,7 @@ fun reluDer(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { // activation layer with relu activator class ReLU : Activation(::relu, ::reluDer) -fun sigmoid(x: DoubleTensor): DoubleTensor = DoubleAnalyticTensorAlgebra { +fun sigmoid(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { 1.0 / (1.0 + (-x).exp()) } @@ -83,9 +82,7 @@ class Dense( val gradInput = outputError dot weights.transpose() val gradW = input.transpose() dot outputError - val gradBias = DoubleAnalyticTensorAlgebra { - outputError.mean(dim = 0, keepDim = false) * input.shape[0].toDouble() - } + val gradBias = outputError.mean(dim = 0, keepDim = false) * input.shape[0].toDouble() weights -= learningRate * gradW bias -= learningRate * gradBias @@ -110,7 +107,7 @@ fun accuracy(yPred: DoubleTensor, yTrue: DoubleTensor): Double { // neural network class class NeuralNetwork(private val layers: List) { - private fun softMaxLoss(yPred: DoubleTensor, yTrue: DoubleTensor): DoubleTensor = DoubleAnalyticTensorAlgebra { + private fun softMaxLoss(yPred: DoubleTensor, yTrue: DoubleTensor): DoubleTensor = BroadcastDoubleTensorAlgebra { val onesForAnswers = yPred.zeroesLike() yTrue.toDoubleArray().forEachIndexed { index, labelDouble -> @@ -118,7 +115,7 @@ class NeuralNetwork(private val layers: List) { onesForAnswers[intArrayOf(index, label)] = 1.0 } - val softmaxValue = BroadcastDoubleTensorAlgebra { yPred.exp() / yPred.exp().sum(dim = 1, keepDim = true) } + val softmaxValue = yPred.exp() / yPred.exp().sum(dim = 1, keepDim = true) (-onesForAnswers + softmaxValue) / (yPred.shape[0].toDouble()) } @@ -177,10 +174,9 @@ class NeuralNetwork(private val layers: List) { } - @OptIn(ExperimentalStdlibApi::class) fun main() { - DoubleTensorAlgebra { + BroadcastDoubleTensorAlgebra { val features = 5 val sampleSize = 250 val trainSize = 180 @@ -188,12 +184,12 @@ fun main() { // take sample of features from normal distribution val x = randomNormal(intArrayOf(sampleSize, features), seed) * 2.5 - BroadcastDoubleTensorAlgebra { - x += fromArray( - intArrayOf(5), - doubleArrayOf(0.0, -1.0, -2.5, -3.0, 5.5) // rows means - ) - } + + x += fromArray( + intArrayOf(5), + doubleArrayOf(0.0, -1.0, -2.5, -3.0, 5.5) // rows means + ) + // define class like '1' if the sum of features > 0 and '0' otherwise val y = fromArray( diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt index 435af35f6..497f63b41 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt @@ -7,8 +7,7 @@ package space.kscience.kmath.tensors import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra -import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra +import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import kotlin.math.abs @@ -19,7 +18,7 @@ fun main() { val randSeed = 100500L // work in context with linear operations - DoubleLinearOpsTensorAlgebra { + DoubleTensorAlgebra { // take coefficient vector from normal distribution val alpha = randomNormal( intArrayOf(5), @@ -56,12 +55,12 @@ fun main() { "$alphaOLS") // figure out MSE of approximation - fun mse(yTrue: DoubleTensor, yPred: DoubleTensor): Double = DoubleAnalyticTensorAlgebra{ + fun mse(yTrue: DoubleTensor, yPred: DoubleTensor): Double { require(yTrue.shape.size == 1) require(yTrue.shape contentEquals yPred.shape) val diff = yTrue - yPred - diff.dot(diff).sqrt().value() + return diff.dot(diff).sqrt().value() } println("MSE: ${mse(alpha, alphaOLS)}") diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt index ee25b63a3..d29dbb094 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt @@ -7,9 +7,6 @@ package space.kscience.kmath.tensors import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra -import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra -import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra - // simple PCA @@ -17,8 +14,8 @@ import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra fun main(){ val seed = 100500L - // work in context with analytic methods - DoubleAnalyticTensorAlgebra { + // work in context with broadcast methods + BroadcastDoubleTensorAlgebra { // assume x is range from 0 until 10 val x = fromArray( @@ -63,7 +60,7 @@ fun main(){ println("Covariance matrix:\n$covMatrix") // and find out eigenvector of it - val (_, evecs) = DoubleLinearOpsTensorAlgebra {covMatrix.symEig()} + val (_, evecs) = covMatrix.symEig() val v = evecs[0] println("Eigenvector:\n$v") @@ -74,7 +71,7 @@ fun main(){ // we can restore original data from reduced data. // for example, find 7th element of dataset val n = 7 - val restored = BroadcastDoubleTensorAlgebra{(datasetReduced[n] dot v.view(intArrayOf(1, 2))) * std + mean} + val restored = (datasetReduced[n] dot v.view(intArrayOf(1, 2))) * std + mean println("Original value:\n${dataset[n]}") println("Restored value:\n$restored") } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt index 69e88c28f..1db986e77 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt @@ -11,8 +11,7 @@ package space.kscience.kmath.tensors.api * * @param T the type of items closed under analytic functions in the tensors. */ -public interface AnalyticTensorAlgebra : - TensorPartialDivisionAlgebra { +public interface AnalyticTensorAlgebra : TensorPartialDivisionAlgebra { /** * @return the mean of all elements in the input tensor. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt index 4a325ab4e..6bdecfa85 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -10,8 +10,7 @@ package space.kscience.kmath.tensors.api * * @param T the type of items closed under division in the tensors. */ -public interface LinearOpsTensorAlgebra : - TensorPartialDivisionAlgebra { +public interface LinearOpsTensorAlgebra : TensorPartialDivisionAlgebra { /** * Computes the determinant of a square matrix input, or of each square matrix in a batched input. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt index 921157963..02bf5415d 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt @@ -11,8 +11,7 @@ package space.kscience.kmath.tensors.api * * @param T the type of items closed under division in the tensors. */ -public interface TensorPartialDivisionAlgebra : - TensorAlgebra { +public interface TensorPartialDivisionAlgebra : TensorAlgebra { /** * Each element of the tensor [other] is divided by this value. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt index e3143f5a7..41df50cba 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.tensors.core.internal.toPrettyString /** * Default [BufferedTensor] implementation for [Double] values diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt index 873ec9027..bc7d90c28 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt @@ -7,8 +7,10 @@ package space.kscience.kmath.tensors.core.algebras import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.* -import space.kscience.kmath.tensors.core.broadcastTensors -import space.kscience.kmath.tensors.core.broadcastTo +import space.kscience.kmath.tensors.core.internal.array +import space.kscience.kmath.tensors.core.internal.broadcastTensors +import space.kscience.kmath.tensors.core.internal.broadcastTo +import space.kscience.kmath.tensors.core.internal.tensor /** * Basic linear algebra operations implemented with broadcasting. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt deleted file mode 100644 index 23a2fa282..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleAnalyticTensorAlgebra.kt +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core.algebras - -import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.tensor -import kotlin.math.* - -public object DoubleAnalyticTensorAlgebra : - AnalyticTensorAlgebra, - DoubleTensorAlgebra() { - - override fun Tensor.mean(): Double = this.fold { it.sum() / tensor.numElements } - - override fun Tensor.mean(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim( - { arr -> - check(dim < dimension) { "Dimension $dim out of range $dimension" } - arr.sum() / shape[dim] - }, - dim, - keepDim - ) - - override fun Tensor.std(): Double = this.fold { arr -> - val mean = arr.sum() / tensor.numElements - sqrt(arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1)) - } - - override fun Tensor.std(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( - { arr -> - check(dim < dimension) { "Dimension $dim out of range $dimension" } - val mean = arr.sum() / shape[dim] - sqrt(arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1)) - }, - dim, - keepDim - ) - - override fun Tensor.variance(): Double = this.fold { arr -> - val mean = arr.sum() / tensor.numElements - arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1) - } - - override fun Tensor.variance(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( - { arr -> - check(dim < dimension) { "Dimension $dim out of range $dimension" } - val mean = arr.sum() / shape[dim] - arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1) - }, - dim, - keepDim - ) - - private fun cov(x: DoubleTensor, y:DoubleTensor): Double{ - val n = x.shape[0] - return ((x - x.mean()) * (y - y.mean())).mean() * n / (n - 1) - } - - override fun cov(tensors: List>): DoubleTensor { - check(tensors.isNotEmpty()) { "List must have at least 1 element" } - val n = tensors.size - val m = tensors[0].shape[0] - check(tensors.all { it.shape contentEquals intArrayOf(m) }) { "Tensors must have same shapes" } - val resTensor = DoubleTensor( - intArrayOf(n, n), - DoubleArray(n * n) {0.0} - ) - for (i in 0 until n){ - for (j in 0 until n){ - resTensor[intArrayOf(i, j)] = cov(tensors[i].tensor, tensors[j].tensor) - } - } - return resTensor - } - - override fun Tensor.exp(): DoubleTensor = tensor.map(::exp) - - override fun Tensor.ln(): DoubleTensor = tensor.map(::ln) - - override fun Tensor.sqrt(): DoubleTensor = tensor.map(::sqrt) - - override fun Tensor.cos(): DoubleTensor = tensor.map(::cos) - - override fun Tensor.acos(): DoubleTensor = tensor.map(::acos) - - override fun Tensor.cosh(): DoubleTensor = tensor.map(::cosh) - - override fun Tensor.acosh(): DoubleTensor = tensor.map(::acosh) - - override fun Tensor.sin(): DoubleTensor = tensor.map(::sin) - - override fun Tensor.asin(): DoubleTensor = tensor.map(::asin) - - override fun Tensor.sinh(): DoubleTensor = tensor.map(::sinh) - - override fun Tensor.asinh(): DoubleTensor = tensor.map(::asinh) - - override fun Tensor.tan(): DoubleTensor = tensor.map(::tan) - - override fun Tensor.atan(): DoubleTensor = tensor.map(::atan) - - override fun Tensor.tanh(): DoubleTensor = tensor.map(::tanh) - - override fun Tensor.atanh(): DoubleTensor = tensor.map(::atanh) - - override fun Tensor.ceil(): DoubleTensor = tensor.map(::ceil) - - override fun Tensor.floor(): DoubleTensor = tensor.map(::floor) - -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt deleted file mode 100644 index 430482613..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleLinearOpsTensorAlgebra.kt +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package space.kscience.kmath.tensors.core.algebras - -import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra -import space.kscience.kmath.nd.as1D -import space.kscience.kmath.nd.as2D -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.* -import space.kscience.kmath.tensors.core.checkSquareMatrix -import space.kscience.kmath.tensors.core.choleskyHelper -import space.kscience.kmath.tensors.core.cleanSymHelper -import space.kscience.kmath.tensors.core.luHelper -import space.kscience.kmath.tensors.core.luMatrixDet -import space.kscience.kmath.tensors.core.luMatrixInv -import space.kscience.kmath.tensors.core.luPivotHelper -import space.kscience.kmath.tensors.core.pivInit -import kotlin.math.min - -/** - * Implementation of common linear algebra operations on double numbers. - * Implements the LinearOpsTensorAlgebra interface. - */ -public object DoubleLinearOpsTensorAlgebra : - LinearOpsTensorAlgebra, - DoubleTensorAlgebra() { - - override fun Tensor.inv(): DoubleTensor = invLU(1e-9) - - override fun Tensor.det(): DoubleTensor = detLU(1e-9) - - /** - * Computes the LU factorization of a matrix or batches of matrices `input`. - * Returns a tuple containing the LU factorization and pivots of `input`. - * - * @param epsilon permissible error when comparing the determinant of a matrix with zero - * @return pair of `factorization` and `pivots`. - * The `factorization` has the shape ``(*, m, n)``, where``(*, m, n)`` is the shape of the `input` tensor. - * The `pivots` has the shape ``(∗, min(m, n))``. `pivots` stores all the intermediate transpositions of rows. - */ - public fun Tensor.luFactor(epsilon: Double): Pair = - computeLU(tensor, epsilon) - ?: throw IllegalArgumentException("Tensor contains matrices which are singular at precision $epsilon") - - /** - * Computes the LU factorization of a matrix or batches of matrices `input`. - * Returns a tuple containing the LU factorization and pivots of `input`. - * Uses an error of ``1e-9`` when calculating whether a matrix is degenerate. - * - * @return pair of `factorization` and `pivots`. - * The `factorization` has the shape ``(*, m, n)``, where``(*, m, n)`` is the shape of the `input` tensor. - * The `pivots` has the shape ``(∗, min(m, n))``. `pivots` stores all the intermediate transpositions of rows. - */ - public fun Tensor.luFactor(): Pair = luFactor(1e-9) - - /** - * Unpacks the data and pivots from a LU factorization of a tensor. - * Given a tensor [luTensor], return tensors (P, L, U) satisfying ``P * luTensor = L * U``, - * with `P` being a permutation matrix or batch of matrices, - * `L` being a lower triangular matrix or batch of matrices, - * `U` being an upper triangular matrix or batch of matrices. - * - * @param luTensor the packed LU factorization data - * @param pivotsTensor the packed LU factorization pivots - * @return triple of P, L and U tensors - */ - public fun luPivot( - luTensor: Tensor, - pivotsTensor: Tensor - ): Triple { - checkSquareMatrix(luTensor.shape) - check( - luTensor.shape.dropLast(2).toIntArray() contentEquals pivotsTensor.shape.dropLast(1).toIntArray() || - luTensor.shape.last() == pivotsTensor.shape.last() - 1 - ) { "Inappropriate shapes of input tensors" } - - val n = luTensor.shape.last() - val pTensor = luTensor.zeroesLike() - pTensor - .matrixSequence() - .zip(pivotsTensor.tensor.vectorSequence()) - .forEach { (p, pivot) -> pivInit(p.as2D(), pivot.as1D(), n) } - - val lTensor = luTensor.zeroesLike() - val uTensor = luTensor.zeroesLike() - - lTensor.matrixSequence() - .zip(uTensor.matrixSequence()) - .zip(luTensor.tensor.matrixSequence()) - .forEach { (pairLU, lu) -> - val (l, u) = pairLU - luPivotHelper(l.as2D(), u.as2D(), lu.as2D(), n) - } - - return Triple(pTensor, lTensor, uTensor) - } - - /** - * QR decomposition. - * - * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `(Q, R)` of tensors. - * Given a tensor `input`, return tensors (Q, R) satisfying ``input = Q * R``, - * with `Q` being an orthogonal matrix or batch of orthogonal matrices - * and `R` being an upper triangular matrix or batch of upper triangular matrices. - * - * @param epsilon permissible error when comparing tensors for equality. - * Used when checking the positive definiteness of the input matrix or matrices. - * @return pair of Q and R tensors. - */ - public fun Tensor.cholesky(epsilon: Double): DoubleTensor { - checkSquareMatrix(shape) - checkPositiveDefinite(tensor, epsilon) - - val n = shape.last() - val lTensor = zeroesLike() - - for ((a, l) in tensor.matrixSequence().zip(lTensor.matrixSequence())) - for (i in 0 until n) choleskyHelper(a.as2D(), l.as2D(), n) - - return lTensor - } - - override fun Tensor.cholesky(): DoubleTensor = cholesky(1e-6) - - override fun Tensor.qr(): Pair { - checkSquareMatrix(shape) - val qTensor = zeroesLike() - val rTensor = zeroesLike() - tensor.matrixSequence() - .zip((qTensor.matrixSequence() - .zip(rTensor.matrixSequence()))).forEach { (matrix, qr) -> - val (q, r) = qr - qrHelper(matrix.asTensor(), q.asTensor(), r.as2D()) - } - - return qTensor to rTensor - } - - override fun Tensor.svd(): Triple = - svd(epsilon = 1e-10) - - /** - * Singular Value Decomposition. - * - * Computes the singular value decomposition of either a matrix or batch of matrices `input`. - * The singular value decomposition is represented as a triple `(U, S, V)`, - * such that ``input = U.dot(diagonalEmbedding(S).dot(V.T))``. - * If input is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as input. - * - * @param epsilon permissible error when calculating the dot product of vectors, - * i.e. the precision with which the cosine approaches 1 in an iterative algorithm. - * @return triple `(U, S, V)`. - */ - public fun Tensor.svd(epsilon: Double): Triple { - val size = tensor.dimension - val commonShape = tensor.shape.sliceArray(0 until size - 2) - val (n, m) = tensor.shape.sliceArray(size - 2 until size) - val uTensor = zeros(commonShape + intArrayOf(min(n, m), n)) - val sTensor = zeros(commonShape + intArrayOf(min(n, m))) - val vTensor = zeros(commonShape + intArrayOf(min(n, m), m)) - - tensor.matrixSequence() - .zip(uTensor.matrixSequence() - .zip(sTensor.vectorSequence() - .zip(vTensor.matrixSequence()))).forEach { (matrix, USV) -> - val matrixSize = matrix.shape.reduce { acc, i -> acc * i } - val curMatrix = DoubleTensor( - matrix.shape, - matrix.mutableBuffer.array().slice(matrix.bufferStart until matrix.bufferStart + matrixSize) - .toDoubleArray() - ) - svdHelper(curMatrix, USV, m, n, epsilon) - } - - return Triple(uTensor.transpose(), sTensor, vTensor.transpose()) - } - - override fun Tensor.symEig(): Pair = - symEig(epsilon = 1e-15) - - /** - * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, - * represented by a pair (eigenvalues, eigenvectors). - * - * @param epsilon permissible error when comparing tensors for equality - * and when the cosine approaches 1 in the SVD algorithm. - * @return a pair (eigenvalues, eigenvectors) - */ - public fun Tensor.symEig(epsilon: Double): Pair { - checkSymmetric(tensor, epsilon) - val (u, s, v) = tensor.svd(epsilon) - val shp = s.shape + intArrayOf(1) - val utv = u.transpose() dot v - val n = s.shape.last() - for (matrix in utv.matrixSequence()) - cleanSymHelper(matrix.as2D(), n) - - val eig = (utv dot s.view(shp)).view(s.shape) - return eig to v - } - - /** - * Computes the determinant of a square matrix input, or of each square matrix in a batched input - * using LU factorization algorithm. - * - * @param epsilon error in the LU algorithm - permissible error when comparing the determinant of a matrix with zero - * @return the determinant. - */ - public fun Tensor.detLU(epsilon: Double = 1e-9): DoubleTensor { - - checkSquareMatrix(tensor.shape) - val luTensor = tensor.copy() - val pivotsTensor = tensor.setUpPivots() - - val n = shape.size - - val detTensorShape = IntArray(n - 1) { i -> shape[i] } - detTensorShape[n - 2] = 1 - val resBuffer = DoubleArray(detTensorShape.reduce(Int::times)) { 0.0 } - - val detTensor = DoubleTensor( - detTensorShape, - resBuffer - ) - - luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).forEachIndexed { index, (lu, pivots) -> - resBuffer[index] = if (luHelper(lu.as2D(), pivots.as1D(), epsilon)) - 0.0 else luMatrixDet(lu.as2D(), pivots.as1D()) - } - - return detTensor - } - - /** - * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input - * using LU factorization algorithm. - * Given a square matrix `a`, return the matrix `aInv` satisfying - * ``a.dot(aInv) = aInv.dot(a) = eye(a.shape[0])``. - * - * @param epsilon error in the LU algorithm - permissible error when comparing the determinant of a matrix with zero - * @return the multiplicative inverse of a matrix. - */ - public fun Tensor.invLU(epsilon: Double = 1e-9): DoubleTensor { - val (luTensor, pivotsTensor) = luFactor(epsilon) - val invTensor = luTensor.zeroesLike() - - val seq = luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).zip(invTensor.matrixSequence()) - for ((luP, invMatrix) in seq) { - val (lu, pivots) = luP - luMatrixInv(lu.as2D(), pivots.as1D(), invMatrix.as2D()) - } - - return invTensor - } - - /** - * LUP decomposition - * - * Computes the LUP decomposition of a matrix or a batch of matrices. - * Given a tensor `input`, return tensors (P, L, U) satisfying ``P * input = L * U``, - * with `P` being a permutation matrix or batch of matrices, - * `L` being a lower triangular matrix or batch of matrices, - * `U` being an upper triangular matrix or batch of matrices. - * - * @param epsilon permissible error when comparing the determinant of a matrix with zero - * @return triple of P, L and U tensors - */ - public fun Tensor.lu(epsilon: Double = 1e-9): Triple { - val (lu, pivots) = this.luFactor(epsilon) - return luPivot(lu, pivots) - } - - override fun Tensor.lu(): Triple = lu(1e-9) - -} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt index e5d41f856..cb06432d0 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt @@ -5,28 +5,34 @@ package space.kscience.kmath.tensors.core.algebras +import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D +import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra +import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra import space.kscience.kmath.tensors.api.TensorPartialDivisionAlgebra import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.* -import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra.fold -import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra.foldDim -import space.kscience.kmath.tensors.core.broadcastOuterTensors -import space.kscience.kmath.tensors.core.checkBufferShapeConsistency -import space.kscience.kmath.tensors.core.checkEmptyDoubleBuffer -import space.kscience.kmath.tensors.core.checkEmptyShape -import space.kscience.kmath.tensors.core.checkShapesCompatible -import space.kscience.kmath.tensors.core.checkTranspose -import space.kscience.kmath.tensors.core.checkView -import space.kscience.kmath.tensors.core.dotHelper -import space.kscience.kmath.tensors.core.getRandomNormals -import space.kscience.kmath.tensors.core.minusIndexFrom -import kotlin.math.abs +import space.kscience.kmath.tensors.core.internal.dotHelper +import space.kscience.kmath.tensors.core.internal.getRandomNormals +import space.kscience.kmath.tensors.core.internal.* +import space.kscience.kmath.tensors.core.internal.broadcastOuterTensors +import space.kscience.kmath.tensors.core.internal.checkBufferShapeConsistency +import space.kscience.kmath.tensors.core.internal.checkEmptyDoubleBuffer +import space.kscience.kmath.tensors.core.internal.checkEmptyShape +import space.kscience.kmath.tensors.core.internal.checkShapesCompatible +import space.kscience.kmath.tensors.core.internal.checkSquareMatrix +import space.kscience.kmath.tensors.core.internal.checkTranspose +import space.kscience.kmath.tensors.core.internal.checkView +import space.kscience.kmath.tensors.core.internal.minusIndexFrom +import kotlin.math.* /** * Implementation of basic operations over double tensors and basic algebra operations on them. */ -public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { +public open class DoubleTensorAlgebra : + TensorPartialDivisionAlgebra, + AnalyticTensorAlgebra, + LinearOpsTensorAlgebra { public companion object : DoubleTensorAlgebra() @@ -311,9 +317,8 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { return DoubleTensor(shape, tensor.mutableBuffer.array(), tensor.bufferStart) } - override fun Tensor.viewAs(other: Tensor): DoubleTensor { - return tensor.view(other.shape) - } + override fun Tensor.viewAs(other: Tensor): DoubleTensor = + tensor.view(other.shape) override infix fun Tensor.dot(other: Tensor): DoubleTensor { if (tensor.shape.size == 1 && other.shape.size == 1) { @@ -565,4 +570,350 @@ public open class DoubleTensorAlgebra : TensorPartialDivisionAlgebra { x.withIndex().maxByOrNull { it.value }?.index!!.toDouble() }, dim, keepDim) + + override fun Tensor.mean(): Double = this.fold { it.sum() / tensor.numElements } + + override fun Tensor.mean(dim: Int, keepDim: Boolean): DoubleTensor = + foldDim( + { arr -> + check(dim < dimension) { "Dimension $dim out of range $dimension" } + arr.sum() / shape[dim] + }, + dim, + keepDim + ) + + override fun Tensor.std(): Double = this.fold { arr -> + val mean = arr.sum() / tensor.numElements + sqrt(arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1)) + } + + override fun Tensor.std(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( + { arr -> + check(dim < dimension) { "Dimension $dim out of range $dimension" } + val mean = arr.sum() / shape[dim] + sqrt(arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1)) + }, + dim, + keepDim + ) + + override fun Tensor.variance(): Double = this.fold { arr -> + val mean = arr.sum() / tensor.numElements + arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1) + } + + override fun Tensor.variance(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( + { arr -> + check(dim < dimension) { "Dimension $dim out of range $dimension" } + val mean = arr.sum() / shape[dim] + arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1) + }, + dim, + keepDim + ) + + private fun cov(x: DoubleTensor, y:DoubleTensor): Double{ + val n = x.shape[0] + return ((x - x.mean()) * (y - y.mean())).mean() * n / (n - 1) + } + + override fun cov(tensors: List>): DoubleTensor { + check(tensors.isNotEmpty()) { "List must have at least 1 element" } + val n = tensors.size + val m = tensors[0].shape[0] + check(tensors.all { it.shape contentEquals intArrayOf(m) }) { "Tensors must have same shapes" } + val resTensor = DoubleTensor( + intArrayOf(n, n), + DoubleArray(n * n) {0.0} + ) + for (i in 0 until n){ + for (j in 0 until n){ + resTensor[intArrayOf(i, j)] = cov(tensors[i].tensor, tensors[j].tensor) + } + } + return resTensor + } + + override fun Tensor.exp(): DoubleTensor = tensor.map(::exp) + + override fun Tensor.ln(): DoubleTensor = tensor.map(::ln) + + override fun Tensor.sqrt(): DoubleTensor = tensor.map(::sqrt) + + override fun Tensor.cos(): DoubleTensor = tensor.map(::cos) + + override fun Tensor.acos(): DoubleTensor = tensor.map(::acos) + + override fun Tensor.cosh(): DoubleTensor = tensor.map(::cosh) + + override fun Tensor.acosh(): DoubleTensor = tensor.map(::acosh) + + override fun Tensor.sin(): DoubleTensor = tensor.map(::sin) + + override fun Tensor.asin(): DoubleTensor = tensor.map(::asin) + + override fun Tensor.sinh(): DoubleTensor = tensor.map(::sinh) + + override fun Tensor.asinh(): DoubleTensor = tensor.map(::asinh) + + override fun Tensor.tan(): DoubleTensor = tensor.map(::tan) + + override fun Tensor.atan(): DoubleTensor = tensor.map(::atan) + + override fun Tensor.tanh(): DoubleTensor = tensor.map(::tanh) + + override fun Tensor.atanh(): DoubleTensor = tensor.map(::atanh) + + override fun Tensor.ceil(): DoubleTensor = tensor.map(::ceil) + + override fun Tensor.floor(): DoubleTensor = tensor.map(::floor) + + override fun Tensor.inv(): DoubleTensor = invLU(1e-9) + + override fun Tensor.det(): DoubleTensor = detLU(1e-9) + + /** + * Computes the LU factorization of a matrix or batches of matrices `input`. + * Returns a tuple containing the LU factorization and pivots of `input`. + * + * @param epsilon permissible error when comparing the determinant of a matrix with zero + * @return pair of `factorization` and `pivots`. + * The `factorization` has the shape ``(*, m, n)``, where``(*, m, n)`` is the shape of the `input` tensor. + * The `pivots` has the shape ``(∗, min(m, n))``. `pivots` stores all the intermediate transpositions of rows. + */ + public fun Tensor.luFactor(epsilon: Double): Pair = + computeLU(tensor, epsilon) + ?: throw IllegalArgumentException("Tensor contains matrices which are singular at precision $epsilon") + + /** + * Computes the LU factorization of a matrix or batches of matrices `input`. + * Returns a tuple containing the LU factorization and pivots of `input`. + * Uses an error of ``1e-9`` when calculating whether a matrix is degenerate. + * + * @return pair of `factorization` and `pivots`. + * The `factorization` has the shape ``(*, m, n)``, where``(*, m, n)`` is the shape of the `input` tensor. + * The `pivots` has the shape ``(∗, min(m, n))``. `pivots` stores all the intermediate transpositions of rows. + */ + public fun Tensor.luFactor(): Pair = luFactor(1e-9) + + /** + * Unpacks the data and pivots from a LU factorization of a tensor. + * Given a tensor [luTensor], return tensors (P, L, U) satisfying ``P * luTensor = L * U``, + * with `P` being a permutation matrix or batch of matrices, + * `L` being a lower triangular matrix or batch of matrices, + * `U` being an upper triangular matrix or batch of matrices. + * + * @param luTensor the packed LU factorization data + * @param pivotsTensor the packed LU factorization pivots + * @return triple of P, L and U tensors + */ + public fun luPivot( + luTensor: Tensor, + pivotsTensor: Tensor + ): Triple { + checkSquareMatrix(luTensor.shape) + check( + luTensor.shape.dropLast(2).toIntArray() contentEquals pivotsTensor.shape.dropLast(1).toIntArray() || + luTensor.shape.last() == pivotsTensor.shape.last() - 1 + ) { "Inappropriate shapes of input tensors" } + + val n = luTensor.shape.last() + val pTensor = luTensor.zeroesLike() + pTensor + .matrixSequence() + .zip(pivotsTensor.tensor.vectorSequence()) + .forEach { (p, pivot) -> pivInit(p.as2D(), pivot.as1D(), n) } + + val lTensor = luTensor.zeroesLike() + val uTensor = luTensor.zeroesLike() + + lTensor.matrixSequence() + .zip(uTensor.matrixSequence()) + .zip(luTensor.tensor.matrixSequence()) + .forEach { (pairLU, lu) -> + val (l, u) = pairLU + luPivotHelper(l.as2D(), u.as2D(), lu.as2D(), n) + } + + return Triple(pTensor, lTensor, uTensor) + } + + /** + * QR decomposition. + * + * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `(Q, R)` of tensors. + * Given a tensor `input`, return tensors (Q, R) satisfying ``input = Q * R``, + * with `Q` being an orthogonal matrix or batch of orthogonal matrices + * and `R` being an upper triangular matrix or batch of upper triangular matrices. + * + * @param epsilon permissible error when comparing tensors for equality. + * Used when checking the positive definiteness of the input matrix or matrices. + * @return pair of Q and R tensors. + */ + public fun Tensor.cholesky(epsilon: Double): DoubleTensor { + checkSquareMatrix(shape) + checkPositiveDefinite(tensor, epsilon) + + val n = shape.last() + val lTensor = zeroesLike() + + for ((a, l) in tensor.matrixSequence().zip(lTensor.matrixSequence())) + for (i in 0 until n) choleskyHelper(a.as2D(), l.as2D(), n) + + return lTensor + } + + override fun Tensor.cholesky(): DoubleTensor = cholesky(1e-6) + + override fun Tensor.qr(): Pair { + checkSquareMatrix(shape) + val qTensor = zeroesLike() + val rTensor = zeroesLike() + tensor.matrixSequence() + .zip((qTensor.matrixSequence() + .zip(rTensor.matrixSequence()))).forEach { (matrix, qr) -> + val (q, r) = qr + qrHelper(matrix.asTensor(), q.asTensor(), r.as2D()) + } + + return qTensor to rTensor + } + + override fun Tensor.svd(): Triple = + svd(epsilon = 1e-10) + + /** + * Singular Value Decomposition. + * + * Computes the singular value decomposition of either a matrix or batch of matrices `input`. + * The singular value decomposition is represented as a triple `(U, S, V)`, + * such that ``input = U.dot(diagonalEmbedding(S).dot(V.T))``. + * If input is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as input. + * + * @param epsilon permissible error when calculating the dot product of vectors, + * i.e. the precision with which the cosine approaches 1 in an iterative algorithm. + * @return triple `(U, S, V)`. + */ + public fun Tensor.svd(epsilon: Double): Triple { + val size = tensor.dimension + val commonShape = tensor.shape.sliceArray(0 until size - 2) + val (n, m) = tensor.shape.sliceArray(size - 2 until size) + val uTensor = zeros(commonShape + intArrayOf(min(n, m), n)) + val sTensor = zeros(commonShape + intArrayOf(min(n, m))) + val vTensor = zeros(commonShape + intArrayOf(min(n, m), m)) + + tensor.matrixSequence() + .zip(uTensor.matrixSequence() + .zip(sTensor.vectorSequence() + .zip(vTensor.matrixSequence()))).forEach { (matrix, USV) -> + val matrixSize = matrix.shape.reduce { acc, i -> acc * i } + val curMatrix = DoubleTensor( + matrix.shape, + matrix.mutableBuffer.array().slice(matrix.bufferStart until matrix.bufferStart + matrixSize) + .toDoubleArray() + ) + svdHelper(curMatrix, USV, m, n, epsilon) + } + + return Triple(uTensor.transpose(), sTensor, vTensor.transpose()) + } + + override fun Tensor.symEig(): Pair = + symEig(epsilon = 1e-15) + + /** + * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, + * represented by a pair (eigenvalues, eigenvectors). + * + * @param epsilon permissible error when comparing tensors for equality + * and when the cosine approaches 1 in the SVD algorithm. + * @return a pair (eigenvalues, eigenvectors) + */ + public fun Tensor.symEig(epsilon: Double): Pair { + checkSymmetric(tensor, epsilon) + val (u, s, v) = tensor.svd(epsilon) + val shp = s.shape + intArrayOf(1) + val utv = u.transpose() dot v + val n = s.shape.last() + for (matrix in utv.matrixSequence()) + cleanSymHelper(matrix.as2D(), n) + + val eig = (utv dot s.view(shp)).view(s.shape) + return eig to v + } + + /** + * Computes the determinant of a square matrix input, or of each square matrix in a batched input + * using LU factorization algorithm. + * + * @param epsilon error in the LU algorithm - permissible error when comparing the determinant of a matrix with zero + * @return the determinant. + */ + public fun Tensor.detLU(epsilon: Double = 1e-9): DoubleTensor { + + checkSquareMatrix(tensor.shape) + val luTensor = tensor.copy() + val pivotsTensor = tensor.setUpPivots() + + val n = shape.size + + val detTensorShape = IntArray(n - 1) { i -> shape[i] } + detTensorShape[n - 2] = 1 + val resBuffer = DoubleArray(detTensorShape.reduce(Int::times)) { 0.0 } + + val detTensor = DoubleTensor( + detTensorShape, + resBuffer + ) + + luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).forEachIndexed { index, (lu, pivots) -> + resBuffer[index] = if (luHelper(lu.as2D(), pivots.as1D(), epsilon)) + 0.0 else luMatrixDet(lu.as2D(), pivots.as1D()) + } + + return detTensor + } + + /** + * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input + * using LU factorization algorithm. + * Given a square matrix `a`, return the matrix `aInv` satisfying + * ``a.dot(aInv) = aInv.dot(a) = eye(a.shape[0])``. + * + * @param epsilon error in the LU algorithm - permissible error when comparing the determinant of a matrix with zero + * @return the multiplicative inverse of a matrix. + */ + public fun Tensor.invLU(epsilon: Double = 1e-9): DoubleTensor { + val (luTensor, pivotsTensor) = luFactor(epsilon) + val invTensor = luTensor.zeroesLike() + + val seq = luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).zip(invTensor.matrixSequence()) + for ((luP, invMatrix) in seq) { + val (lu, pivots) = luP + luMatrixInv(lu.as2D(), pivots.as1D(), invMatrix.as2D()) + } + + return invTensor + } + + /** + * LUP decomposition + * + * Computes the LUP decomposition of a matrix or a batch of matrices. + * Given a tensor `input`, return tensors (P, L, U) satisfying ``P * input = L * U``, + * with `P` being a permutation matrix or batch of matrices, + * `L` being a lower triangular matrix or batch of matrices, + * `U` being an upper triangular matrix or batch of matrices. + * + * @param epsilon permissible error when comparing the determinant of a matrix with zero + * @return triple of P, L and U tensors + */ + public fun Tensor.lu(epsilon: Double = 1e-9): Triple { + val (lu, pivots) = this.luFactor(epsilon) + return luPivot(lu, pivots) + } + + override fun Tensor.lu(): Triple = lu(1e-9) + } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt similarity index 94% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt index dfac054b5..6324dc242 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/broadcastUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt @@ -1,5 +1,11 @@ -package space.kscience.kmath.tensors.core +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +package space.kscience.kmath.tensors.core.internal + +import space.kscience.kmath.tensors.core.DoubleTensor import kotlin.math.max internal fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTensor, linearSize: Int) { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt similarity index 83% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt index f8bd5027a..0221c961e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt @@ -1,7 +1,12 @@ -package space.kscience.kmath.tensors.core +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.core.internal import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra +import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra @@ -50,7 +55,7 @@ internal fun DoubleTensorAlgebra.checkSymmetric( "Tensor is not symmetric about the last 2 dimensions at precision $epsilon" } -internal fun DoubleLinearOpsTensorAlgebra.checkPositiveDefinite(tensor: DoubleTensor, epsilon: Double = 1e-6) { +internal fun DoubleTensorAlgebra.checkPositiveDefinite(tensor: DoubleTensor, epsilon: Double = 1e-6) { checkSymmetric(tensor, epsilon) for (mat in tensor.matrixSequence()) check(mat.asTensor().detLU().value() > 0.0) { diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt similarity index 91% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt index 8adbfad39..23909f81e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt @@ -1,12 +1,17 @@ -package space.kscience.kmath.tensors.core +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.core.internal import space.kscience.kmath.nd.MutableStructure1D import space.kscience.kmath.nd.MutableStructure2D import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra -import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra +import space.kscience.kmath.tensors.core.* +import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import kotlin.math.abs import kotlin.math.min import kotlin.math.sign @@ -114,7 +119,7 @@ internal fun BufferedTensor.setUpPivots(): IntTensor { ) } -internal fun DoubleLinearOpsTensorAlgebra.computeLU( +internal fun DoubleTensorAlgebra.computeLU( tensor: DoubleTensor, epsilon: Double ): Pair? { @@ -218,7 +223,7 @@ internal fun luMatrixInv( } } -internal fun DoubleLinearOpsTensorAlgebra.qrHelper( +internal fun DoubleTensorAlgebra.qrHelper( matrix: DoubleTensor, q: DoubleTensor, r: MutableStructure2D @@ -241,14 +246,14 @@ internal fun DoubleLinearOpsTensorAlgebra.qrHelper( } } } - r[j, j] = DoubleAnalyticTensorAlgebra { (v dot v).sqrt().value() } + r[j, j] = DoubleTensorAlgebra { (v dot v).sqrt().value() } for (i in 0 until n) { qM[i, j] = vv[i] / r[j, j] } } } -internal fun DoubleLinearOpsTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10): DoubleTensor { +internal fun DoubleTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10): DoubleTensor { val (n, m) = a.shape var v: DoubleTensor val b: DoubleTensor @@ -264,7 +269,7 @@ internal fun DoubleLinearOpsTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double while (true) { lastV = v v = b.dot(lastV) - val norm = DoubleAnalyticTensorAlgebra { (v dot v).sqrt().value() } + val norm = DoubleTensorAlgebra { (v dot v).sqrt().value() } v = v.times(1.0 / norm) if (abs(v.dot(lastV).value()) > 1 - epsilon) { return v @@ -272,7 +277,7 @@ internal fun DoubleLinearOpsTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double } } -internal fun DoubleLinearOpsTensorAlgebra.svdHelper( +internal fun DoubleTensorAlgebra.svdHelper( matrix: DoubleTensor, USV: Pair, Pair, BufferedTensor>>, m: Int, n: Int, epsilon: Double @@ -298,12 +303,12 @@ internal fun DoubleLinearOpsTensorAlgebra.svdHelper( if (n > m) { v = svd1d(a, epsilon) u = matrix.dot(v) - norm = DoubleAnalyticTensorAlgebra { (u dot u).sqrt().value() } + norm = DoubleTensorAlgebra { (u dot u).sqrt().value() } u = u.times(1.0 / norm) } else { u = svd1d(a, epsilon) v = matrix.transpose(0, 1).dot(u) - norm = DoubleAnalyticTensorAlgebra { (v dot v).sqrt().value() } + norm = DoubleTensorAlgebra { (v dot v).sqrt().value() } v = v.times(1.0 / norm) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt similarity index 88% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCastsUtils.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt index 70e3b9c61..67cb0b842 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCastsUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt @@ -3,11 +3,14 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.tensors.core +package space.kscience.kmath.tensors.core.internal import space.kscience.kmath.nd.MutableBufferND import space.kscience.kmath.structures.asMutableBuffer import space.kscience.kmath.tensors.api.Tensor +import space.kscience.kmath.tensors.core.BufferedTensor +import space.kscience.kmath.tensors.core.DoubleTensor +import space.kscience.kmath.tensors.core.IntTensor import space.kscience.kmath.tensors.core.algebras.TensorLinearStructure internal fun BufferedTensor.asTensor(): IntTensor = diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt similarity index 91% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt index 0211342bb..0ffaf39e7 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt @@ -1,9 +1,16 @@ -package space.kscience.kmath.tensors.core +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.tensors.core.internal import space.kscience.kmath.nd.as1D import space.kscience.kmath.samplers.GaussianSampler import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.structures.* +import space.kscience.kmath.tensors.core.BufferedTensor +import space.kscience.kmath.tensors.core.DoubleTensor import kotlin.math.* /** diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt index 2743a5218..814a1bb9b 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt @@ -6,6 +6,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.tensors.api.Tensor +import space.kscience.kmath.tensors.core.internal.tensor /** * Casts [Tensor] to [DoubleTensor] diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt index 6e3b4df60..80c7ab13a 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt @@ -3,6 +3,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra +import space.kscience.kmath.tensors.core.internal.* import kotlin.test.Test import kotlin.test.assertTrue diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt index 3ea19da26..4dcc367ca 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt @@ -1,7 +1,6 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import kotlin.math.* import kotlin.test.Test @@ -28,73 +27,73 @@ internal class TestDoubleAnalyticTensorAlgebra { } @Test - fun testExp() = DoubleAnalyticTensorAlgebra { + fun testExp() = DoubleTensorAlgebra { assertTrue { tensor.exp() eq expectedTensor(::exp) } } @Test - fun testLog() = DoubleAnalyticTensorAlgebra { + fun testLog() = DoubleTensorAlgebra { assertTrue { tensor.ln() eq expectedTensor(::ln) } } @Test - fun testSqrt() = DoubleAnalyticTensorAlgebra { + fun testSqrt() = DoubleTensorAlgebra { assertTrue { tensor.sqrt() eq expectedTensor(::sqrt) } } @Test - fun testCos() = DoubleAnalyticTensorAlgebra { + fun testCos() = DoubleTensorAlgebra { assertTrue { tensor.cos() eq expectedTensor(::cos) } } @Test - fun testCosh() = DoubleAnalyticTensorAlgebra { + fun testCosh() = DoubleTensorAlgebra { assertTrue { tensor.cosh() eq expectedTensor(::cosh) } } @Test - fun testAcosh() = DoubleAnalyticTensorAlgebra { + fun testAcosh() = DoubleTensorAlgebra { assertTrue { tensor.acosh() eq expectedTensor(::acosh) } } @Test - fun testSin() = DoubleAnalyticTensorAlgebra { + fun testSin() = DoubleTensorAlgebra { assertTrue { tensor.sin() eq expectedTensor(::sin) } } @Test - fun testSinh() = DoubleAnalyticTensorAlgebra { + fun testSinh() = DoubleTensorAlgebra { assertTrue { tensor.sinh() eq expectedTensor(::sinh) } } @Test - fun testAsinh() = DoubleAnalyticTensorAlgebra { + fun testAsinh() = DoubleTensorAlgebra { assertTrue { tensor.asinh() eq expectedTensor(::asinh) } } @Test - fun testTan() = DoubleAnalyticTensorAlgebra { + fun testTan() = DoubleTensorAlgebra { assertTrue { tensor.tan() eq expectedTensor(::tan) } } @Test - fun testAtan() = DoubleAnalyticTensorAlgebra { + fun testAtan() = DoubleTensorAlgebra { assertTrue { tensor.atan() eq expectedTensor(::atan) } } @Test - fun testTanh() = DoubleAnalyticTensorAlgebra { + fun testTanh() = DoubleTensorAlgebra { assertTrue { tensor.tanh() eq expectedTensor(::tanh) } } @Test - fun testCeil() = DoubleAnalyticTensorAlgebra { + fun testCeil() = DoubleTensorAlgebra { assertTrue { tensor.ceil() eq expectedTensor(::ceil) } } @Test - fun testFloor() = DoubleAnalyticTensorAlgebra { + fun testFloor() = DoubleTensorAlgebra { assertTrue { tensor.floor() eq expectedTensor(::floor) } } @@ -145,7 +144,7 @@ internal class TestDoubleAnalyticTensorAlgebra { } @Test - fun testMean() = DoubleAnalyticTensorAlgebra { + fun testMean() = DoubleTensorAlgebra { assertTrue { tensor2.mean() == 1.0 } assertTrue { tensor2.mean(0, true) eq fromArray( intArrayOf(1, 2), diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 65070af7f..77748b15e 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -1,7 +1,9 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.algebras.DoubleLinearOpsTensorAlgebra +import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra +import space.kscience.kmath.tensors.core.internal.array +import space.kscience.kmath.tensors.core.internal.svd1d import kotlin.math.abs import kotlin.test.Test import kotlin.test.assertEquals @@ -10,7 +12,7 @@ import kotlin.test.assertTrue internal class TestDoubleLinearOpsTensorAlgebra { @Test - fun testDetLU() = DoubleLinearOpsTensorAlgebra { + fun testDetLU() = DoubleTensorAlgebra { val tensor = fromArray( intArrayOf(2, 2, 2), doubleArrayOf( @@ -35,7 +37,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testDet() = DoubleLinearOpsTensorAlgebra { + fun testDet() = DoubleTensorAlgebra { val expectedValue = 0.019827417 val m = fromArray( intArrayOf(3, 3), doubleArrayOf( @@ -49,7 +51,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testDetSingle() = DoubleLinearOpsTensorAlgebra { + fun testDetSingle() = DoubleTensorAlgebra { val expectedValue = 48.151623 val m = fromArray( intArrayOf(1, 1), doubleArrayOf( @@ -61,7 +63,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testInvLU() = DoubleLinearOpsTensorAlgebra { + fun testInvLU() = DoubleTensorAlgebra { val tensor = fromArray( intArrayOf(2, 2, 2), doubleArrayOf( @@ -86,14 +88,14 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testScalarProduct() = DoubleLinearOpsTensorAlgebra { + fun testScalarProduct() = DoubleTensorAlgebra { val a = fromArray(intArrayOf(3), doubleArrayOf(1.8, 2.5, 6.8)) val b = fromArray(intArrayOf(3), doubleArrayOf(5.5, 2.6, 6.4)) assertEquals(a.dot(b).value(), 59.92) } @Test - fun testQR() = DoubleLinearOpsTensorAlgebra { + fun testQR() = DoubleTensorAlgebra { val shape = intArrayOf(2, 2, 2) val buffer = doubleArrayOf( 1.0, 3.0, @@ -114,7 +116,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testLU() = DoubleLinearOpsTensorAlgebra { + fun testLU() = DoubleTensorAlgebra { val shape = intArrayOf(2, 2, 2) val buffer = doubleArrayOf( 1.0, 3.0, @@ -134,7 +136,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testCholesky() = DoubleLinearOpsTensorAlgebra { + fun testCholesky() = DoubleTensorAlgebra { val tensor = randomNormal(intArrayOf(2, 5, 5), 0) val sigma = (tensor dot tensor.transpose()) + diagonalEmbedding( fromArray(intArrayOf(2, 5), DoubleArray(10) { 0.1 }) @@ -145,7 +147,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testSVD1D() = DoubleLinearOpsTensorAlgebra { + fun testSVD1D() = DoubleTensorAlgebra { val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val res = svd1d(tensor2) @@ -156,13 +158,13 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testSVD() = DoubleLinearOpsTensorAlgebra{ + fun testSVD() = DoubleTensorAlgebra{ 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))) } @Test - fun testBatchedSVD() = DoubleLinearOpsTensorAlgebra { + fun testBatchedSVD() = DoubleTensorAlgebra { val tensor = randomNormal(intArrayOf(2, 5, 3), 0) val (tensorU, tensorS, tensorV) = tensor.svd() val tensorSVD = tensorU dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) @@ -170,7 +172,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } @Test - fun testBatchedSymEig() = DoubleLinearOpsTensorAlgebra { + fun testBatchedSymEig() = DoubleTensorAlgebra { val tensor = randomNormal(shape = intArrayOf(2, 3, 3), 0) val tensorSigma = tensor + tensor.transpose() val (tensorS, tensorV) = tensorSigma.symEig() @@ -182,7 +184,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } -private fun DoubleLinearOpsTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double = 1e-10): Unit { +private fun DoubleTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double = 1e-10): Unit { val svd = tensor.svd() val tensorSVD = svd.first diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index 132735cc7..c4f9f94b0 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -8,6 +8,10 @@ import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.toDoubleArray import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra +import space.kscience.kmath.tensors.core.internal.array +import space.kscience.kmath.tensors.core.internal.asTensor +import space.kscience.kmath.tensors.core.internal.matrixSequence +import space.kscience.kmath.tensors.core.internal.toBufferedTensor import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index d782d78d9..ed858259e 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -3,6 +3,7 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra +import space.kscience.kmath.tensors.core.internal.array import kotlin.test.Test import kotlin.test.assertFalse import kotlin.test.assertTrue From 0ef64130aeae0deb5543b9c6f73af3a46f465394 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 7 May 2021 13:00:30 +0100 Subject: [PATCH 169/178] TensorLinearStructure made internal --- .../space/kscience/kmath/tensors/DataSetNormalization.kt | 2 +- .../kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt | 2 +- .../kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt | 4 ++-- .../main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt | 2 +- examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt | 2 +- .../core/{algebras => }/BroadcastDoubleTensorAlgebra.kt | 3 +-- .../space/kscience/kmath/tensors/core/BufferedTensor.kt | 5 +++-- .../kmath/tensors/core/{algebras => }/DoubleTensorAlgebra.kt | 3 +-- .../core/{algebras => internal}/TensorLinearStructure.kt | 4 ++-- .../space/kscience/kmath/tensors/core/internal/checks.kt | 2 +- .../space/kscience/kmath/tensors/core/internal/linUtils.kt | 2 +- .../kscience/kmath/tensors/core/internal/tensorCastsUtils.kt | 1 - .../space/kscience/kmath/tensors/core/TestBroadcasting.kt | 2 -- .../kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt | 1 - .../kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt | 1 - .../space/kscience/kmath/tensors/core/TestDoubleTensor.kt | 1 - .../kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt | 1 - 17 files changed, 15 insertions(+), 23 deletions(-) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{algebras => }/BroadcastDoubleTensorAlgebra.kt (97%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{algebras => }/DoubleTensorAlgebra.kt (99%) rename kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/{algebras => internal}/TensorLinearStructure.kt (91%) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt index d029348f2..6fbf16a91 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.tensors import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra +import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra // Dataset normalization diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt index c0ece04ca..78370b517 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.tensors import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra +import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra // solving linear system with LUP decomposition diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt index 1998b8d16..874ac8034 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt @@ -7,8 +7,8 @@ package space.kscience.kmath.tensors import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra -import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra +import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra +import space.kscience.kmath.tensors.core.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.toDoubleArray import kotlin.math.sqrt diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt index 497f63b41..42a0a4ba1 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.tensors import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra +import space.kscience.kmath.tensors.core.DoubleTensorAlgebra import kotlin.math.abs diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt index d29dbb094..f8ac13d3f 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt @@ -6,7 +6,7 @@ package space.kscience.kmath.tensors import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra +import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra // simple PCA diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt similarity index 97% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt index bc7d90c28..b8530f637 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt @@ -3,10 +3,9 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.tensors.core.algebras +package space.kscience.kmath.tensors.core import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.* import space.kscience.kmath.tensors.core.internal.array import space.kscience.kmath.tensors.core.internal.broadcastTensors import space.kscience.kmath.tensors.core.internal.broadcastTo diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index e8c0556c2..858532abc 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt @@ -1,8 +1,9 @@ package space.kscience.kmath.tensors.core +import space.kscience.kmath.nd.Strides import space.kscience.kmath.structures.* import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.algebras.TensorLinearStructure +import space.kscience.kmath.tensors.core.internal.TensorLinearStructure /** * Represents [Tensor] over a [MutableBuffer] intended to be used through [DoubleTensor] and [IntTensor] @@ -16,7 +17,7 @@ public open class BufferedTensor internal constructor( /** * Buffer strides based on [TensorLinearStructure] implementation */ - public val linearStructure: TensorLinearStructure + public val linearStructure: Strides get() = TensorLinearStructure(shape) /** diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt similarity index 99% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index cb06432d0..d4a0f1433 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.tensors.core.algebras +package space.kscience.kmath.tensors.core import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D @@ -11,7 +11,6 @@ import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra import space.kscience.kmath.tensors.api.TensorPartialDivisionAlgebra import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.* import space.kscience.kmath.tensors.core.internal.dotHelper import space.kscience.kmath.tensors.core.internal.getRandomNormals import space.kscience.kmath.tensors.core.internal.* diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt similarity index 91% rename from kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt rename to kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt index f65e2b955..4bdd987db 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/TensorLinearStructure.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package space.kscience.kmath.tensors.core.algebras +package space.kscience.kmath.tensors.core.internal import space.kscience.kmath.nd.Strides import kotlin.math.max @@ -44,7 +44,7 @@ internal fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): IntArra * * @param shape the shape of the tensor. */ -public class TensorLinearStructure(override val shape: IntArray) : Strides { +internal class TensorLinearStructure(override val shape: IntArray) : Strides { override val strides: IntArray get() = stridesFromShape(shape) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt index 0221c961e..f1c158770 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt @@ -7,7 +7,7 @@ package space.kscience.kmath.tensors.core.internal import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra +import space.kscience.kmath.tensors.core.DoubleTensorAlgebra internal fun checkEmptyShape(shape: IntArray) = diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt index 23909f81e..ff78ca64c 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt @@ -11,7 +11,7 @@ import space.kscience.kmath.nd.as1D import space.kscience.kmath.nd.as2D import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.* -import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra +import space.kscience.kmath.tensors.core.DoubleTensorAlgebra import kotlin.math.abs import kotlin.math.min import kotlin.math.sign diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt index 67cb0b842..d965b6bcd 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt @@ -11,7 +11,6 @@ import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.BufferedTensor import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.IntTensor -import space.kscience.kmath.tensors.core.algebras.TensorLinearStructure internal fun BufferedTensor.asTensor(): IntTensor = IntTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt index 80c7ab13a..672089a3c 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt @@ -1,8 +1,6 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra -import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.internal.* import kotlin.test.Test import kotlin.test.assertTrue diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt index 4dcc367ca..05fedaa09 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt @@ -1,7 +1,6 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import kotlin.math.* import kotlin.test.Test import kotlin.test.assertTrue diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 77748b15e..fddb37251 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -1,7 +1,6 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.internal.array import space.kscience.kmath.tensors.core.internal.svd1d import kotlin.math.abs diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index c4f9f94b0..d39b5c365 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -7,7 +7,6 @@ import space.kscience.kmath.nd.as2D import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.toDoubleArray -import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.internal.array import space.kscience.kmath.tensors.core.internal.asTensor import space.kscience.kmath.tensors.core.internal.matrixSequence diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index ed858259e..354840719 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -2,7 +2,6 @@ package space.kscience.kmath.tensors.core import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.algebras.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.internal.array import kotlin.test.Test import kotlin.test.assertFalse From d31726a0d90de41ced32d211d3d929dd46f5091c Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 7 May 2021 13:12:18 +0100 Subject: [PATCH 170/178] produce routine --- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index d4a0f1433..052d8d97e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -56,6 +56,17 @@ public open class DoubleTensorAlgebra : return DoubleTensor(shape, buffer, 0) } + /** + * Constructs a tensor with the specified shape and initializer. + * + * @param shape the desired shape for the tensor. + * @param initializer mapping tensor indices to values. + * @return tensor with the [shape] shape and data generated by initializer. + */ + public fun produce(shape: IntArray, initializer: (IntArray) -> Double): DoubleTensor = + fromArray(shape, + TensorLinearStructure(shape).indices().map(initializer).toMutableList().toDoubleArray()) + override operator fun Tensor.get(i: Int): DoubleTensor { val lastShape = tensor.shape.drop(1).toIntArray() val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) From e80eefa90f5832de6b3c81487b27e7a355d38358 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 7 May 2021 13:12:55 +0100 Subject: [PATCH 171/178] typo corrected --- .../space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 052d8d97e..5baf6c7ad 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -61,7 +61,7 @@ public open class DoubleTensorAlgebra : * * @param shape the desired shape for the tensor. * @param initializer mapping tensor indices to values. - * @return tensor with the [shape] shape and data generated by initializer. + * @return tensor with the [shape] shape and data generated by the [initializer]. */ public fun produce(shape: IntArray, initializer: (IntArray) -> Double): DoubleTensor = fromArray(shape, From d73d03c0558348af0d8de282664206b99fccf681 Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 7 May 2021 13:36:15 +0100 Subject: [PATCH 172/178] valueOrNull added --- .../kmath/tensors/LinearSystemSolvingWithLUP.kt | 2 +- .../space/kscience/kmath/tensors/OLSWithSVD.kt | 2 +- .../kscience/kmath/tensors/api/TensorAlgebra.kt | 3 ++- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 10 ++++------ .../kmath/tensors/core/internal/checks.kt | 4 ++-- .../kmath/tensors/core/internal/linUtils.kt | 15 ++++++++------- .../tensors/core/TestDoubleLinearOpsAlgebra.kt | 6 +++--- .../kmath/tensors/core/TestDoubleTensor.kt | 2 +- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt index 78370b517..4494d6799 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt @@ -69,7 +69,7 @@ fun main () { val n = l.shape[0] val x = zeros(intArrayOf(n)) for (i in 0 until n){ - x[intArrayOf(i)] = (b[intArrayOf(i)] - l[i].dot(x).value()) / l[intArrayOf(i, i)] + x[intArrayOf(i)] = (b[intArrayOf(i)] - l[i].dot(x).valueOrNull()!!) / l[intArrayOf(i, i)] } return x } diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt index 42a0a4ba1..5d1883e7c 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt @@ -60,7 +60,7 @@ fun main() { require(yTrue.shape contentEquals yPred.shape) val diff = yTrue - yPred - return diff.dot(diff).sqrt().value() + return diff.dot(diff).sqrt().valueOrNull()!! } println("MSE: ${mse(alpha, alphaOLS)}") diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index e7f8dc7ae..78a36e229 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -16,11 +16,12 @@ import space.kscience.kmath.operations.Algebra public interface TensorAlgebra: Algebra> { /** + * * Returns a single tensor value of unit dimension. The tensor shape must be equal to [1]. * * @return the value of a scalar tensor. */ - public fun Tensor.value(): T + public fun Tensor.valueOrNull(): T? /** * Each element of the tensor [other] is added to this value. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index 5baf6c7ad..bf27a2690 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -35,12 +35,10 @@ public open class DoubleTensorAlgebra : public companion object : DoubleTensorAlgebra() - override fun Tensor.value(): Double { - check(tensor.shape contentEquals intArrayOf(1)) { - "Inconsistent value for tensor of shape ${shape.toList()}" - } - return tensor.mutableBuffer.array()[tensor.bufferStart] - } + override fun Tensor.valueOrNull(): Double? = if(tensor.shape contentEquals intArrayOf(1)) { + // Inconsistent value for tensor of with this shape + tensor.mutableBuffer.array()[tensor.bufferStart] + } else null /** * Constructs a tensor with the specified shape and data. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt index f1c158770..bfbc6334d 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt @@ -58,7 +58,7 @@ internal fun DoubleTensorAlgebra.checkSymmetric( internal fun DoubleTensorAlgebra.checkPositiveDefinite(tensor: DoubleTensor, epsilon: Double = 1e-6) { checkSymmetric(tensor, epsilon) for (mat in tensor.matrixSequence()) - check(mat.asTensor().detLU().value() > 0.0) { - "Tensor contains matrices which are not positive definite ${mat.asTensor().detLU().value()}" + check(mat.asTensor().detLU().valueOrNull()!! > 0.0) { + "Tensor contains matrices which are not positive definite ${mat.asTensor().detLU().valueOrNull()!!}" } } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt index ff78ca64c..5c120c05f 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt @@ -12,6 +12,7 @@ import space.kscience.kmath.nd.as2D import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.* import space.kscience.kmath.tensors.core.DoubleTensorAlgebra +import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.valueOrNull import kotlin.math.abs import kotlin.math.min import kotlin.math.sign @@ -239,14 +240,14 @@ internal fun DoubleTensorAlgebra.qrHelper( val vv = v.as1D() if (j > 0) { for (i in 0 until j) { - r[i, j] = (qT[i] dot matrixT[j]).value() + r[i, j] = (qT[i] dot matrixT[j]).valueOrNull()!! for (k in 0 until n) { val qTi = qT[i].as1D() vv[k] = vv[k] - r[i, j] * qTi[k] } } } - r[j, j] = DoubleTensorAlgebra { (v dot v).sqrt().value() } + r[j, j] = DoubleTensorAlgebra { (v dot v).sqrt().valueOrNull()!! } for (i in 0 until n) { qM[i, j] = vv[i] / r[j, j] } @@ -269,9 +270,9 @@ internal fun DoubleTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10) while (true) { lastV = v v = b.dot(lastV) - val norm = DoubleTensorAlgebra { (v dot v).sqrt().value() } + val norm = DoubleTensorAlgebra { (v dot v).sqrt().valueOrNull()!! } v = v.times(1.0 / norm) - if (abs(v.dot(lastV).value()) > 1 - epsilon) { + if (abs(v.dot(lastV).valueOrNull()!!) > 1 - epsilon) { return v } } @@ -292,7 +293,7 @@ internal fun DoubleTensorAlgebra.svdHelper( val outerProduct = DoubleArray(u.shape[0] * v.shape[0]) for (i in 0 until u.shape[0]) { for (j in 0 until v.shape[0]) { - outerProduct[i * v.shape[0] + j] = u[i].value() * v[j].value() + outerProduct[i * v.shape[0] + j] = u[i].valueOrNull()!! * v[j].valueOrNull()!! } } a = a - singularValue.times(DoubleTensor(intArrayOf(u.shape[0], v.shape[0]), outerProduct)) @@ -303,12 +304,12 @@ internal fun DoubleTensorAlgebra.svdHelper( if (n > m) { v = svd1d(a, epsilon) u = matrix.dot(v) - norm = DoubleTensorAlgebra { (u dot u).sqrt().value() } + norm = DoubleTensorAlgebra { (u dot u).sqrt().valueOrNull()!! } u = u.times(1.0 / norm) } else { u = svd1d(a, epsilon) v = matrix.transpose(0, 1).dot(u) - norm = DoubleTensorAlgebra { (v dot v).sqrt().value() } + norm = DoubleTensorAlgebra { (v dot v).sqrt().valueOrNull()!! } v = v.times(1.0 / norm) } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index fddb37251..99f00edbf 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -46,7 +46,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { ) ) - assertTrue { abs(m.det().value() - expectedValue) < 1e-5 } + assertTrue { abs(m.det().valueOrNull()!! - expectedValue) < 1e-5 } } @Test @@ -58,7 +58,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { ) ) - assertTrue { abs(m.det().value() - expectedValue) < 1e-5 } + assertTrue { abs(m.det().valueOrNull()!! - expectedValue) < 1e-5 } } @Test @@ -90,7 +90,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { fun testScalarProduct() = DoubleTensorAlgebra { val a = fromArray(intArrayOf(3), doubleArrayOf(1.8, 2.5, 6.8)) val b = fromArray(intArrayOf(3), doubleArrayOf(5.5, 2.6, 6.4)) - assertEquals(a.dot(b).value(), 59.92) + assertEquals(a.dot(b).valueOrNull()!!, 59.92) } @Test diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index d39b5c365..1afdb2263 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -21,7 +21,7 @@ internal class TestDoubleTensor { fun testValue() = DoubleTensorAlgebra { val value = 12.5 val tensor = fromArray(intArrayOf(1), doubleArrayOf(value)) - assertEquals(tensor.value(), value) + assertEquals(tensor.valueOrNull()!!, value) } @Test From 5b725a087b81b8c4f9206a4f9098b2cc01c4cd54 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Fri, 7 May 2021 15:53:09 +0300 Subject: [PATCH 173/178] new cast --- .../kmath/tensors/core/tensorCasts.kt | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt index 814a1bb9b..921bcf97e 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt @@ -35,3 +35,35 @@ public fun IntTensor.toIntArray(): IntArray { mutableBuffer[bufferStart + i] } } + +/** + * Casts [Array] to [DoubleTensor] + */ +public fun Array.toDoubleTensor(): DoubleTensor { + val n = size + check(n > 0) { "An empty array cannot be casted to tensor" } + val m = first().size + check(m > 0) { "Inner arrays must have at least 1 argument" } + check(all { size == m }) { "Inner arrays must be the same size" } + + val shape = intArrayOf(n, m) + val buffer = this.flatMap { arr -> arr.map { it } }.toDoubleArray() + + return DoubleTensor(shape, buffer, 0) +} + +/** + * Casts [Array] to [IntTensor] + */ +public fun Array.toIntTensor(): IntTensor { + val n = size + check(n > 0) { "An empty array cannot be casted to tensor" } + val m = first().size + check(m > 0) { "Inner arrays must have at least 1 argument" } + check(all { size == m }) { "Inner arrays must be the same size" } + + val shape = intArrayOf(n, m) + val buffer = this.flatMap { arr -> arr.map { it } }.toIntArray() + + return IntTensor(shape, buffer, 0) +} From 21b5d45b96878e89c464020994b3c7d931464c7f Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 7 May 2021 14:13:07 +0100 Subject: [PATCH 174/178] Throwable value method --- .../tensors/LinearSystemSolvingWithLUP.kt | 2 +- .../kscience/kmath/tensors/OLSWithSVD.kt | 2 +- .../kmath/tensors/api/TensorAlgebra.kt | 10 ++++- .../kmath/tensors/core/DoubleTensorAlgebra.kt | 44 ++++++++++++------- .../kmath/tensors/core/internal/checks.kt | 4 +- .../kmath/tensors/core/internal/linUtils.kt | 14 +++--- .../core/TestDoubleLinearOpsAlgebra.kt | 6 +-- .../kmath/tensors/core/TestDoubleTensor.kt | 2 +- 8 files changed, 51 insertions(+), 33 deletions(-) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt index 4494d6799..78370b517 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt @@ -69,7 +69,7 @@ fun main () { val n = l.shape[0] val x = zeros(intArrayOf(n)) for (i in 0 until n){ - x[intArrayOf(i)] = (b[intArrayOf(i)] - l[i].dot(x).valueOrNull()!!) / l[intArrayOf(i, i)] + x[intArrayOf(i)] = (b[intArrayOf(i)] - l[i].dot(x).value()) / l[intArrayOf(i, i)] } return x } diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt index 5d1883e7c..42a0a4ba1 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt @@ -60,7 +60,7 @@ fun main() { require(yTrue.shape contentEquals yPred.shape) val diff = yTrue - yPred - return diff.dot(diff).sqrt().valueOrNull()!! + return diff.dot(diff).sqrt().value() } println("MSE: ${mse(alpha, alphaOLS)}") diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 78a36e229..4718b6a58 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -15,13 +15,21 @@ import space.kscience.kmath.operations.Algebra */ public interface TensorAlgebra: Algebra> { + /** + * + * Returns a single tensor value of unit dimension if tensor shape equals to [1]. + * + * @return a nullable value of a potentially scalar tensor. + */ + public fun Tensor.valueOrNull(): T? + /** * * Returns a single tensor value of unit dimension. The tensor shape must be equal to [1]. * * @return the value of a scalar tensor. */ - public fun Tensor.valueOrNull(): T? + public fun Tensor.value(): T /** * Each element of the tensor [other] is added to this value. diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt index bf27a2690..c1694644f 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt @@ -35,10 +35,11 @@ public open class DoubleTensorAlgebra : public companion object : DoubleTensorAlgebra() - override fun Tensor.valueOrNull(): Double? = if(tensor.shape contentEquals intArrayOf(1)) { - // Inconsistent value for tensor of with this shape - tensor.mutableBuffer.array()[tensor.bufferStart] - } else null + override fun Tensor.valueOrNull(): Double? = if (tensor.shape contentEquals intArrayOf(1)) + tensor.mutableBuffer.array()[tensor.bufferStart] else null + + override fun Tensor.value(): Double = + valueOrNull() ?: throw IllegalArgumentException("Inconsistent value for tensor of with $shape shape") /** * Constructs a tensor with the specified shape and data. @@ -62,8 +63,10 @@ public open class DoubleTensorAlgebra : * @return tensor with the [shape] shape and data generated by the [initializer]. */ public fun produce(shape: IntArray, initializer: (IntArray) -> Double): DoubleTensor = - fromArray(shape, - TensorLinearStructure(shape).indices().map(initializer).toMutableList().toDoubleArray()) + fromArray( + shape, + TensorLinearStructure(shape).indices().map(initializer).toMutableList().toDoubleArray() + ) override operator fun Tensor.get(i: Int): DoubleTensor { val lastShape = tensor.shape.drop(1).toIntArray() @@ -621,7 +624,7 @@ public open class DoubleTensorAlgebra : keepDim ) - private fun cov(x: DoubleTensor, y:DoubleTensor): Double{ + private fun cov(x: DoubleTensor, y: DoubleTensor): Double { val n = x.shape[0] return ((x - x.mean()) * (y - y.mean())).mean() * n / (n - 1) } @@ -633,10 +636,10 @@ public open class DoubleTensorAlgebra : check(tensors.all { it.shape contentEquals intArrayOf(m) }) { "Tensors must have same shapes" } val resTensor = DoubleTensor( intArrayOf(n, n), - DoubleArray(n * n) {0.0} + DoubleArray(n * n) { 0.0 } ) - for (i in 0 until n){ - for (j in 0 until n){ + for (i in 0 until n) { + for (j in 0 until n) { resTensor[intArrayOf(i, j)] = cov(tensors[i].tensor, tensors[j].tensor) } } @@ -779,8 +782,10 @@ public open class DoubleTensorAlgebra : val qTensor = zeroesLike() val rTensor = zeroesLike() tensor.matrixSequence() - .zip((qTensor.matrixSequence() - .zip(rTensor.matrixSequence()))).forEach { (matrix, qr) -> + .zip( + (qTensor.matrixSequence() + .zip(rTensor.matrixSequence())) + ).forEach { (matrix, qr) -> val (q, r) = qr qrHelper(matrix.asTensor(), q.asTensor(), r.as2D()) } @@ -812,9 +817,13 @@ public open class DoubleTensorAlgebra : val vTensor = zeros(commonShape + intArrayOf(min(n, m), m)) tensor.matrixSequence() - .zip(uTensor.matrixSequence() - .zip(sTensor.vectorSequence() - .zip(vTensor.matrixSequence()))).forEach { (matrix, USV) -> + .zip( + uTensor.matrixSequence() + .zip( + sTensor.vectorSequence() + .zip(vTensor.matrixSequence()) + ) + ).forEach { (matrix, USV) -> val matrixSize = matrix.shape.reduce { acc, i -> acc * i } val curMatrix = DoubleTensor( matrix.shape, @@ -918,10 +927,11 @@ public open class DoubleTensorAlgebra : * @return triple of P, L and U tensors */ public fun Tensor.lu(epsilon: Double = 1e-9): Triple { - val (lu, pivots) = this.luFactor(epsilon) + val (lu, pivots) = tensor.luFactor(epsilon) return luPivot(lu, pivots) } override fun Tensor.lu(): Triple = lu(1e-9) - } + + diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt index bfbc6334d..f1c158770 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt @@ -58,7 +58,7 @@ internal fun DoubleTensorAlgebra.checkSymmetric( internal fun DoubleTensorAlgebra.checkPositiveDefinite(tensor: DoubleTensor, epsilon: Double = 1e-6) { checkSymmetric(tensor, epsilon) for (mat in tensor.matrixSequence()) - check(mat.asTensor().detLU().valueOrNull()!! > 0.0) { - "Tensor contains matrices which are not positive definite ${mat.asTensor().detLU().valueOrNull()!!}" + check(mat.asTensor().detLU().value() > 0.0) { + "Tensor contains matrices which are not positive definite ${mat.asTensor().detLU().value()}" } } \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt index 5c120c05f..7d3617547 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt @@ -240,14 +240,14 @@ internal fun DoubleTensorAlgebra.qrHelper( val vv = v.as1D() if (j > 0) { for (i in 0 until j) { - r[i, j] = (qT[i] dot matrixT[j]).valueOrNull()!! + r[i, j] = (qT[i] dot matrixT[j]).value() for (k in 0 until n) { val qTi = qT[i].as1D() vv[k] = vv[k] - r[i, j] * qTi[k] } } } - r[j, j] = DoubleTensorAlgebra { (v dot v).sqrt().valueOrNull()!! } + r[j, j] = DoubleTensorAlgebra { (v dot v).sqrt().value() } for (i in 0 until n) { qM[i, j] = vv[i] / r[j, j] } @@ -270,9 +270,9 @@ internal fun DoubleTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10) while (true) { lastV = v v = b.dot(lastV) - val norm = DoubleTensorAlgebra { (v dot v).sqrt().valueOrNull()!! } + val norm = DoubleTensorAlgebra { (v dot v).sqrt().value() } v = v.times(1.0 / norm) - if (abs(v.dot(lastV).valueOrNull()!!) > 1 - epsilon) { + if (abs(v.dot(lastV).value()) > 1 - epsilon) { return v } } @@ -293,7 +293,7 @@ internal fun DoubleTensorAlgebra.svdHelper( val outerProduct = DoubleArray(u.shape[0] * v.shape[0]) for (i in 0 until u.shape[0]) { for (j in 0 until v.shape[0]) { - outerProduct[i * v.shape[0] + j] = u[i].valueOrNull()!! * v[j].valueOrNull()!! + outerProduct[i * v.shape[0] + j] = u[i].value() * v[j].value() } } a = a - singularValue.times(DoubleTensor(intArrayOf(u.shape[0], v.shape[0]), outerProduct)) @@ -304,12 +304,12 @@ internal fun DoubleTensorAlgebra.svdHelper( if (n > m) { v = svd1d(a, epsilon) u = matrix.dot(v) - norm = DoubleTensorAlgebra { (u dot u).sqrt().valueOrNull()!! } + norm = DoubleTensorAlgebra { (u dot u).sqrt().value() } u = u.times(1.0 / norm) } else { u = svd1d(a, epsilon) v = matrix.transpose(0, 1).dot(u) - norm = DoubleTensorAlgebra { (v dot v).sqrt().valueOrNull()!! } + norm = DoubleTensorAlgebra { (v dot v).sqrt().value() } v = v.times(1.0 / norm) } diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index 99f00edbf..fddb37251 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -46,7 +46,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { ) ) - assertTrue { abs(m.det().valueOrNull()!! - expectedValue) < 1e-5 } + assertTrue { abs(m.det().value() - expectedValue) < 1e-5 } } @Test @@ -58,7 +58,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { ) ) - assertTrue { abs(m.det().valueOrNull()!! - expectedValue) < 1e-5 } + assertTrue { abs(m.det().value() - expectedValue) < 1e-5 } } @Test @@ -90,7 +90,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { fun testScalarProduct() = DoubleTensorAlgebra { val a = fromArray(intArrayOf(3), doubleArrayOf(1.8, 2.5, 6.8)) val b = fromArray(intArrayOf(3), doubleArrayOf(5.5, 2.6, 6.4)) - assertEquals(a.dot(b).valueOrNull()!!, 59.92) + assertEquals(a.dot(b).value(), 59.92) } @Test diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index 1afdb2263..d39b5c365 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -21,7 +21,7 @@ internal class TestDoubleTensor { fun testValue() = DoubleTensorAlgebra { val value = 12.5 val tensor = fromArray(intArrayOf(1), doubleArrayOf(value)) - assertEquals(tensor.valueOrNull()!!, value) + assertEquals(tensor.value(), value) } @Test From a5b72f201617752033941b50c1789cd5598902ec Mon Sep 17 00:00:00 2001 From: Roland Grinis Date: Fri, 7 May 2021 14:15:48 +0100 Subject: [PATCH 175/178] Doc typo --- .../kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 4718b6a58..2eb18ada6 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt @@ -16,7 +16,6 @@ import space.kscience.kmath.operations.Algebra public interface TensorAlgebra: Algebra> { /** - * * Returns a single tensor value of unit dimension if tensor shape equals to [1]. * * @return a nullable value of a potentially scalar tensor. @@ -24,7 +23,6 @@ public interface TensorAlgebra: Algebra> { public fun Tensor.valueOrNull(): T? /** - * * Returns a single tensor value of unit dimension. The tensor shape must be equal to [1]. * * @return the value of a scalar tensor. From dde1db7b0afa27162988fcb1b3543afe6187a4d6 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Fri, 7 May 2021 23:05:37 +0300 Subject: [PATCH 176/178] fixes --- .../kmath/tensors/core/tensorCasts.kt | 40 ++----------------- 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt index 921bcf97e..4e43ed1e1 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt @@ -9,17 +9,17 @@ import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.internal.tensor /** - * Casts [Tensor] to [DoubleTensor] + * Casts [Tensor] iof [Double] to [DoubleTensor] */ public fun Tensor.toDoubleTensor(): DoubleTensor = this.tensor /** - * Casts [Tensor] to [IntTensor] + * Casts [Tensor] iof [Int] to [IntTensor] */ public fun Tensor.toIntTensor(): IntTensor = this.tensor /** - * @return [DoubleArray] of tensor elements + * Returns [DoubleArray] of tensor elements */ public fun DoubleTensor.toDoubleArray(): DoubleArray { return DoubleArray(numElements) { i -> @@ -28,42 +28,10 @@ public fun DoubleTensor.toDoubleArray(): DoubleArray { } /** - * @return [IntArray] of tensor elements + * Returns [IntArray] of tensor elements */ public fun IntTensor.toIntArray(): IntArray { return IntArray(numElements) { i -> mutableBuffer[bufferStart + i] } } - -/** - * Casts [Array] to [DoubleTensor] - */ -public fun Array.toDoubleTensor(): DoubleTensor { - val n = size - check(n > 0) { "An empty array cannot be casted to tensor" } - val m = first().size - check(m > 0) { "Inner arrays must have at least 1 argument" } - check(all { size == m }) { "Inner arrays must be the same size" } - - val shape = intArrayOf(n, m) - val buffer = this.flatMap { arr -> arr.map { it } }.toDoubleArray() - - return DoubleTensor(shape, buffer, 0) -} - -/** - * Casts [Array] to [IntTensor] - */ -public fun Array.toIntTensor(): IntTensor { - val n = size - check(n > 0) { "An empty array cannot be casted to tensor" } - val m = first().size - check(m > 0) { "Inner arrays must have at least 1 argument" } - check(all { size == m }) { "Inner arrays must be the same size" } - - val shape = intArrayOf(n, m) - val buffer = this.flatMap { arr -> arr.map { it } }.toIntArray() - - return IntTensor(shape, buffer, 0) -} From 11a1624e64d2b779e84d25bf120698b49b400cc1 Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Fri, 7 May 2021 23:06:41 +0300 Subject: [PATCH 177/178] fixes --- .../kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt index 4e43ed1e1..142cb2156 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt @@ -9,12 +9,12 @@ import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.internal.tensor /** - * Casts [Tensor] iof [Double] to [DoubleTensor] + * Casts [Tensor] of [Double] to [DoubleTensor] */ public fun Tensor.toDoubleTensor(): DoubleTensor = this.tensor /** - * Casts [Tensor] iof [Int] to [IntTensor] + * Casts [Tensor] of [Int] to [IntTensor] */ public fun Tensor.toIntTensor(): IntTensor = this.tensor From 33e27cd99262d64533ccde72bbdb10b47c75d9fe Mon Sep 17 00:00:00 2001 From: Andrei Kislitsyn Date: Fri, 7 May 2021 23:07:02 +0300 Subject: [PATCH 178/178] fixed --- .../space/kscience/kmath/tensors/core/TestBroadcasting.kt | 2 +- .../kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt | 2 +- .../kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt | 2 -- .../space/kscience/kmath/tensors/core/TestDoubleTensor.kt | 2 +- .../kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt | 2 +- 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt index 672089a3c..35e605fd9 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt @@ -102,4 +102,4 @@ internal class TestBroadcasting { assertTrue(tensor32.mutableBuffer.array() contentEquals doubleArrayOf(490.0, 480.0, 470.0)) } -} \ No newline at end of file +} diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt index 05fedaa09..3b4c615b4 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt @@ -155,4 +155,4 @@ internal class TestDoubleAnalyticTensorAlgebra { )} } -} \ No newline at end of file +} diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt index fddb37251..347bb683f 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt @@ -194,5 +194,3 @@ private fun DoubleTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double assertTrue(tensor.eq(tensorSVD, epsilon)) } - - diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt index d39b5c365..a6c6a7618 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt @@ -86,4 +86,4 @@ internal class TestDoubleTensor { assertEquals(ndArray[intArrayOf(0)], 1.0) } -} \ No newline at end of file +} diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt index 354840719..e7e898008 100644 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt @@ -164,4 +164,4 @@ internal class TestDoubleTensorAlgebra { assertFalse(tensor1.eq(tensor3)) } -} \ No newline at end of file +}