From c475c43744f12d2e0385492f725d0b714629042d Mon Sep 17 00:00:00 2001 From: darksnake Date: Sat, 14 Dec 2024 11:50:46 +0300 Subject: [PATCH] Named buffers and named module --- .space/CODEOWNERS | 0 .../space/kscience/kmath/fit/chiSquared.kt | 4 +++- .../kmath/wasm/internal/WasmBuilder.kt | 6 ++++- .../kotlin/space/kscience/kmath/wasm/wasm.kt | 1 + .../kotlin/space/kscience/kmath/asm/asm.kt | 1 + .../kmath/asm/internal/PrimitiveAsmBuilder.kt | 2 ++ .../kmath/commons/optimization/CMOptimizer.kt | 4 ++-- .../space/kscience/kmath/domains/Domain1D.kt | 2 +- .../kscience/kmath/expressions/DSAlgebra.kt | 1 + .../kscience/kmath/expressions/DSCompiler.kt | 2 +- .../kscience/kmath/expressions/Expression.kt | 1 + .../space/kscience/kmath/named/NamedBuffer.kt | 22 +++++++++++++++++++ .../{expressions => named}/NamedMatrix.kt | 12 +++++++++- .../{expressions => named}/SymbolIndexer.kt | 6 ++++- .../kmath/optimization/OptimizationProblem.kt | 2 +- .../kmath/optimization/QowOptimizer.kt | 8 ++++++- .../MultivariateNormalDistribution.kt | 12 ++++++++++ .../kotlin/space/kscience/kmath/stat/Mean.kt | 8 +++---- .../kscience/kmath/stat/StatisticTest.kt | 9 ++++---- 19 files changed, 84 insertions(+), 19 deletions(-) delete mode 100644 .space/CODEOWNERS create mode 100644 kmath-core/src/commonMain/kotlin/space/kscience/kmath/named/NamedBuffer.kt rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/{expressions => named}/NamedMatrix.kt (79%) rename kmath-core/src/commonMain/kotlin/space/kscience/kmath/{expressions => named}/SymbolIndexer.kt (95%) create mode 100644 kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/MultivariateNormalDistribution.kt diff --git a/.space/CODEOWNERS b/.space/CODEOWNERS deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt b/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt index 5c00e2d81..5df519c19 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt @@ -9,6 +9,7 @@ import kotlinx.html.br import kotlinx.html.h3 import space.kscience.kmath.commons.optimization.CMOptimizer import space.kscience.kmath.distributions.NormalDistribution +import space.kscience.kmath.expressions.DifferentiableExpression import space.kscience.kmath.expressions.autodiff import space.kscience.kmath.expressions.symbol import space.kscience.kmath.operations.asIterable @@ -19,6 +20,7 @@ import space.kscience.kmath.real.DoubleVector import space.kscience.kmath.real.map import space.kscience.kmath.real.step import space.kscience.kmath.stat.chiSquaredExpression +import space.kscience.kmath.structures.Float64 import space.kscience.plotly.* import space.kscience.plotly.models.ScatterMode import space.kscience.plotly.models.TraceValues @@ -64,7 +66,7 @@ suspend fun main() { val yErr = y.map { sqrt(it) }//RealVector.same(x.size, sigma) // compute differentiable chi^2 sum for given model ax^2 + bx + c - val chi2 = Double.autodiff.chiSquaredExpression(x, y, yErr) { arg -> + val chi2: DifferentiableExpression = Double.autodiff.chiSquaredExpression(x, y, yErr) { arg -> //bind variables to autodiff context val a = bindSymbol(a) val b = bindSymbol(b) diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt index 5a12ccb8f..c12a7c033 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt @@ -7,9 +7,13 @@ package space.kscience.kmath.wasm.internal import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.ast.TypedMst -import space.kscience.kmath.expressions.* +import space.kscience.kmath.expressions.DoubleExpression +import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.expressions.IntExpression +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.internal.binaryen.* import space.kscience.kmath.internal.webassembly.Instance +import space.kscience.kmath.named.SimpleSymbolIndexer import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Float64 import space.kscience.kmath.internal.binaryen.Module as BinaryenModule diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt index 26e6a2486..a70638159 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt @@ -11,6 +11,7 @@ import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.ast.TypedMst import space.kscience.kmath.ast.evaluateConstants import space.kscience.kmath.expressions.* +import space.kscience.kmath.named.SimpleSymbolIndexer import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Int32Ring import space.kscience.kmath.structures.Float64 diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt index ac35562d2..9a417e1d8 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt @@ -12,6 +12,7 @@ import space.kscience.kmath.asm.internal.* import space.kscience.kmath.ast.TypedMst import space.kscience.kmath.ast.evaluateConstants import space.kscience.kmath.expressions.* +import space.kscience.kmath.named.SimpleSymbolIndexer import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Int32Ring diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt index ed0f361af..117e2b9cb 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt @@ -14,6 +14,8 @@ import org.objectweb.asm.commons.InstructionAdapter import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.ast.TypedMst import space.kscience.kmath.expressions.* +import space.kscience.kmath.named.SimpleSymbolIndexer +import space.kscience.kmath.named.SymbolIndexer import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Float64 import java.lang.invoke.MethodHandles diff --git a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt index db4b3b733..e0cca4ae5 100644 --- a/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt +++ b/kmath-commons/src/jvmMain/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt @@ -18,9 +18,9 @@ import space.kscience.attributes.AttributesBuilder import space.kscience.attributes.SetAttribute import space.kscience.kmath.UnstableKMathAPI import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.SymbolIndexer import space.kscience.kmath.expressions.derivative -import space.kscience.kmath.expressions.withSymbols +import space.kscience.kmath.named.SymbolIndexer +import space.kscience.kmath.named.withSymbols import space.kscience.kmath.optimization.* import space.kscience.kmath.structures.Float64 import kotlin.collections.set diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt index 62d97f7b7..d80c1b78d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain1D.kt @@ -23,7 +23,7 @@ public abstract class Domain1D>(public val range: ClosedRange< @UnstableKMathAPI public class DoubleDomain1D( - @Suppress("CanBeParameter") public val doubleRange: ClosedFloatingPointRange, + public val doubleRange: ClosedFloatingPointRange, ) : Domain1D(doubleRange), Float64Domain { override fun getLowerBound(num: Int): Double { require(num == 0) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt index a6e721d13..5965fa3aa 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSAlgebra.kt @@ -7,6 +7,7 @@ package space.kscience.kmath.expressions import space.kscience.attributes.SafeType import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.named.SymbolIndexer import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableBuffer diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt index 0699ca1df..1f80eb65b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DSCompiler.kt @@ -126,7 +126,7 @@ public class DSCompiler> internal constructor( * If all orders are set to 0, then the 0th order derivative is returned, which is the value of the * function. * - * The indices of derivatives are between 0 and [size] − 1. Their specific order is fixed for a given compiler, but + * The indices of derivatives are between 0 and [getSize] − 1. Their specific order is fixed for a given compiler, but * otherwise not publicly specified. There are however some simple cases which have guaranteed indices: * * * the index of 0th order derivative is always 0 diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt index 1cc3b766b..8661a7c20 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt @@ -9,6 +9,7 @@ import space.kscience.attributes.SafeType import space.kscience.attributes.WithType import space.kscience.attributes.safeTypeOf import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.named.SymbolIndexer import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/named/NamedBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/named/NamedBuffer.kt new file mode 100644 index 000000000..5b9b8f0d0 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/named/NamedBuffer.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2018-2024 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. + */ + +@file:OptIn(UnstableKMathAPI::class) + +package space.kscience.kmath.named + +import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.MutableBuffer + +public class NamedBuffer(public val values: Buffer, public val indexer: SymbolIndexer): Buffer by values{ + public operator fun get(symbol: Symbol): T = values[indexer.indexOf(symbol)] +} + +public class NamedMutableBuffer(public val values: MutableBuffer, public val indexer: SymbolIndexer): MutableBuffer by values{ + public operator fun get(symbol: Symbol): T = values[indexer.indexOf(symbol)] + public operator fun set(symbol: Symbol, value: T) { values[indexer.indexOf(symbol)] = value } +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/named/NamedMatrix.kt similarity index 79% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/named/NamedMatrix.kt index 14ccafb0b..395cbdc17 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/NamedMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/named/NamedMatrix.kt @@ -5,14 +5,24 @@ @file:OptIn(UnstableKMathAPI::class) -package space.kscience.kmath.expressions +package space.kscience.kmath.named import space.kscience.kmath.PerformancePitfall import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.linear.Matrix import space.kscience.kmath.structures.getOrNull +/** + * A square matrix that could be accessed via column and row names. + * + * Multiple symbols could in theory reference the same columns or rows. Some columns could be not references at all. + */ public class NamedMatrix(public val values: Matrix, public val indexer: SymbolIndexer) : Matrix by values { + init { + require(values.rows.size == values.columns.size) { "Only square matrices could be named" } + } + public operator fun get(i: Symbol, j: Symbol): T = get(indexer.indexOf(i), indexer.indexOf(j)) public companion object { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/named/SymbolIndexer.kt similarity index 95% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/named/SymbolIndexer.kt index d47202df3..0c3e27158 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/named/SymbolIndexer.kt @@ -3,9 +3,10 @@ * 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.expressions +package space.kscience.kmath.named import space.kscience.kmath.UnstableKMathAPI +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.linear.Point import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.structures.BufferFactory @@ -69,6 +70,9 @@ public interface SymbolIndexer { public fun Map.toDoubleArray(): DoubleArray = DoubleArray(symbols.size) { getValue(symbols[it]) } } +@UnstableKMathAPI +public val SymbolIndexer.size: Int get() = symbols.size + @UnstableKMathAPI @JvmInline public value class SimpleSymbolIndexer(override val symbols: List) : SymbolIndexer diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt index 2ba80251b..4c0e4038e 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt @@ -6,9 +6,9 @@ package space.kscience.kmath.optimization import space.kscience.attributes.* -import space.kscience.kmath.expressions.NamedMatrix import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.misc.Loggable +import space.kscience.kmath.named.NamedMatrix public interface OptimizationAttribute : Attribute diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt index 25f1ec72e..4b115d7e1 100644 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt +++ b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt @@ -6,9 +6,15 @@ package space.kscience.kmath.optimization import space.kscience.kmath.UnstableKMathAPI -import space.kscience.kmath.expressions.* +import space.kscience.kmath.expressions.DifferentiableExpression +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.expressions.derivative +import space.kscience.kmath.expressions.withDefaultArgs import space.kscience.kmath.linear.* import space.kscience.kmath.misc.log +import space.kscience.kmath.named.NamedMatrix +import space.kscience.kmath.named.SymbolIndexer +import space.kscience.kmath.named.named import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.operations.Float64L2Norm import space.kscience.kmath.operations.algebra diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/MultivariateNormalDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/MultivariateNormalDistribution.kt new file mode 100644 index 000000000..b158347f3 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/MultivariateNormalDistribution.kt @@ -0,0 +1,12 @@ +/* + * Copyright 2018-2024 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.distributions + +public interface MultivariateNormalDistribution: NamedDistribution { + public companion object{ + + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt index 031bb3298..fa3c13d6b 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt @@ -6,9 +6,7 @@ package space.kscience.kmath.stat import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.Float64 -import space.kscience.kmath.structures.indices +import space.kscience.kmath.structures.* /** * Arithmetic mean @@ -44,8 +42,8 @@ public class Mean( public companion object { public fun evaluate(buffer: Buffer): Double = Float64Field.mean.evaluateBlocking(buffer) - public fun evaluate(buffer: Buffer): Int = Int32Ring.mean.evaluateBlocking(buffer) - public fun evaluate(buffer: Buffer): Long = Int64Ring.mean.evaluateBlocking(buffer) + public fun evaluate(buffer: Buffer): Int = Int32Ring.mean.evaluateBlocking(buffer) + public fun evaluate(buffer: Buffer): Long = Int64Ring.mean.evaluateBlocking(buffer) } } diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt index fb9a4351a..7f770c50d 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.last import kotlinx.coroutines.flow.take import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest import space.kscience.kmath.operations.Float64Field import space.kscience.kmath.random.RandomGenerator import space.kscience.kmath.random.chain @@ -27,21 +28,21 @@ internal class StatisticTest { val chunked = data.chunked(1000) @Test - fun singleBlockingMean() { - val first = runBlocking { chunked.first() } + fun singleBlockingMean() = runTest { + val first = chunked.first() val res = Float64Field.mean(first) assertEquals(0.5, res, 1e-1) } @Test - fun singleSuspendMean() = runBlocking { + fun singleSuspendMean() = runTest { val first = runBlocking { chunked.first() } val res = Float64Field.mean(first) assertEquals(0.5, res, 1e-1) } @Test - fun parallelMean() = runBlocking { + fun parallelMean() = runTest { val average = Float64Field.mean .flow(chunked) //create a flow from evaluated results .take(100) // Take 100 data chunks from the source and accumulate them