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 {