diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cffef64b0..cde58b6d6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,20 +13,29 @@ jobs: runs-on: ${{matrix.os}} timeout-minutes: 40 steps: - - uses: actions/checkout@v3.0.0 - - uses: actions/setup-java@v3.0.0 + - name: Checkout the repo + uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: DeLaGuardo/setup-graalvm@4.0 with: - java-version: 11 - distribution: liberica + graalvm: 21.2.0 + java: java11 + arch: amd64 + - name: Cache gradle + uses: actions/cache@v2 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} + restore-keys: | + ${{ runner.os }}-gradle- - name: Cache konan - uses: actions/cache@v3.0.1 + uses: actions/cache@v2 with: path: ~/.konan key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} restore-keys: | ${{ runner.os }}-gradle- - - name: Gradle Wrapper Validation - uses: gradle/wrapper-validation-action@v1.0.4 - - uses: gradle/gradle-build-action@v2.1.5 - with: - arguments: build + - name: Build + run: ./gradlew build --build-cache --no-daemon --stacktrace diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 9b76fd16e..23ed54357 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -9,22 +9,20 @@ jobs: runs-on: ubuntu-20.04 timeout-minutes: 40 steps: - - uses: actions/checkout@v3.0.0 - - uses: actions/setup-java@v3.0.0 + - uses: actions/checkout@v2 + - uses: DeLaGuardo/setup-graalvm@4.0 with: - java-version: 11 - distribution: liberica - - name: Cache konan - uses: actions/cache@v3.0.1 + graalvm: 21.2.0 + java: java11 + arch: amd64 + - uses: actions/cache@v2 with: - path: ~/.konan + path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} restore-keys: | ${{ runner.os }}-gradle- - - uses: gradle/gradle-build-action@v2.1.5 - with: - arguments: dokkaHtmlMultiModule --no-parallel - - uses: JamesIves/github-pages-deploy-action@4.2.5 + - run: ./gradlew dokkaHtmlMultiModule --build-cache --no-daemon --no-parallel --stacktrace + - uses: JamesIves/github-pages-deploy-action@4.1.0 with: branch: gh-pages folder: build/dokka/htmlMultiModule diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8e9b98dcb..c5075cb0f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,36 +14,40 @@ jobs: os: [ macOS-latest, windows-latest ] runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v3.0.0 - - uses: actions/setup-java@v3.0.0 + - name: Checkout the repo + uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: DeLaGuardo/setup-graalvm@4.0 with: - java-version: 11 - distribution: liberica + graalvm: 21.2.0 + java: java11 + arch: amd64 + - name: Cache gradle + uses: actions/cache@v2 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} + restore-keys: | + ${{ runner.os }}-gradle- - name: Cache konan - uses: actions/cache@v3.0.1 + uses: actions/cache@v2 with: path: ~/.konan key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} restore-keys: | ${{ runner.os }}-gradle- - - uses: gradle/wrapper-validation-action@v1.0.4 - name: Publish Windows Artifacts if: matrix.os == 'windows-latest' - uses: gradle/gradle-build-action@v2.1.5 - with: - arguments: | - releaseAll - -Ppublishing.enabled=true - -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} - -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} + shell: cmd + run: > + ./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true + -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} + -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} - name: Publish Mac Artifacts if: matrix.os == 'macOS-latest' - uses: gradle/gradle-build-action@v2.1.5 - with: - arguments: | - releaseMacosX64 - releaseIosArm64 - releaseIosX64 - -Ppublishing.enabled=true - -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} - -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} + run: > + ./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true -Ppublishing.platform=macosX64 + -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} + -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} diff --git a/.gitignore b/.gitignore index 5ddd846a8..d6c4af4e3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ out/ .idea/ +!.idea/copyright/ +!.idea/scopes/ .vscode/ @@ -16,7 +18,3 @@ out/ # Generated by javac -h and runtime *.class *.log - -!/.idea/copyright/ -!/.idea/scopes/ -/kotlin-js-store/yarn.lock diff --git a/.idea/copyright/kmath.xml b/.idea/copyright/kmath.xml index 17e44e4d0..1070e5d33 100644 --- a/.idea/copyright/kmath.xml +++ b/.idea/copyright/kmath.xml @@ -1,6 +1,6 @@ - diff --git a/.idea/scopes/Apply_copyright.xml b/.idea/scopes/Apply_copyright.xml index a2575f774..0eb589133 100644 --- a/.idea/scopes/Apply_copyright.xml +++ b/.idea/scopes/Apply_copyright.xml @@ -1,3 +1,4 @@ - - \ No newline at end of file + + diff --git a/CHANGELOG.md b/CHANGELOG.md index a19b1f467..12540821e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,12 +13,8 @@ - Extended operations for ND4J fields - Jupyter Notebook integration module (kmath-jupyter) - `@PerformancePitfall` annotation to mark possibly slow API -- Unified architecture for Integration and Optimization using features. - `BigInt` operation performance improvement and fixes by @zhelenskiy (#328) - Integration between `MST` and Symja `IExpr` -- Complex power -- Separate methods for UInt, Int and Number powers. NaN safety. -- Tensorflow prototype ### Changed - Exponential operations merged with hyperbolic functions @@ -40,17 +36,8 @@ - Remove Any restriction on polynomials - Add `out` variance to type parameters of `StructureND` and its implementations where possible - Rename `DifferentiableMstExpression` to `KotlingradExpression` -- `FeatureSet` now accepts only `Feature`. It is possible to override keys and use interfaces. -- Use `Symbol` factory function instead of `StringSymbol` -- New discoverability pattern: `.algebra.` -- Adjusted commons-math API for linear solvers to match conventions. -- Buffer algebra does not require size anymore -- Operations -> Ops -- Default Buffer and ND algebras are now Ops and lack neutral elements (0, 1) as well as algebra-level shapes. -- Tensor algebra takes read-only structures as input and inherits AlgebraND ### Deprecated -- Specialized `DoubleBufferAlgebra` ### Removed - Nearest in Domain. To be implemented in geometry package. @@ -60,7 +47,6 @@ - Expression algebra builders - Complex and Quaternion no longer are elements. - Second generic from DifferentiableExpression -- Algebra elements are completely removed. Use algebra contexts instead. ### Fixed - Ring inherits RingOperations, not GroupOperations diff --git a/README.md b/README.md index aea94f529..db069d4e0 100644 --- a/README.md +++ b/README.md @@ -50,20 +50,52 @@ module definitions below. The module stability could have the following levels: with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. * **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## Modules +
-### [benchmarks](benchmarks) +* ### [benchmarks](benchmarks) > > > **Maturity**: EXPERIMENTAL +
-### [examples](examples) +* ### [examples](examples) > > > **Maturity**: EXPERIMENTAL +
-### [kmath-ast](kmath-ast) +* ### [kmath-ast](kmath-ast) > > > **Maturity**: EXPERIMENTAL @@ -74,13 +106,15 @@ module definitions below. The module stability could have the following levels: > - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler > - [rendering](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt) : Extendable MST rendering +
-### [kmath-commons](kmath-commons) +* ### [kmath-commons](kmath-commons) > > > **Maturity**: EXPERIMENTAL +
-### [kmath-complex](kmath-complex) +* ### [kmath-complex](kmath-complex) > Complex numbers and quaternions. > > **Maturity**: PROTOTYPE @@ -89,8 +123,9 @@ module definitions below. The module stability could have the following levels: > - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers > - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions +
-### [kmath-core](kmath-core) +* ### [kmath-core](kmath-core) > Core classes, algebra definitions, basic linear algebra > > **Maturity**: DEVELOPMENT @@ -106,18 +141,21 @@ performance calculations to code generation. > - [domains](kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains) : Domains > - [autodiff](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation +
-### [kmath-coroutines](kmath-coroutines) +* ### [kmath-coroutines](kmath-coroutines) > > > **Maturity**: EXPERIMENTAL +
-### [kmath-dimensions](kmath-dimensions) +* ### [kmath-dimensions](kmath-dimensions) > > > **Maturity**: PROTOTYPE +
-### [kmath-ejml](kmath-ejml) +* ### [kmath-ejml](kmath-ejml) > > > **Maturity**: PROTOTYPE @@ -127,8 +165,9 @@ performance calculations to code generation. > - [ejml-matrix](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt) : Matrix implementation. > - [ejml-linear-space](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt) : LinearSpace implementations. +
-### [kmath-for-real](kmath-for-real) +* ### [kmath-for-real](kmath-for-real) > Extension module that should be used to achieve numpy-like behavior. All operations are specialized to work with `Double` numbers without declaring algebraic contexts. One can still use generic algebras though. @@ -140,8 +179,9 @@ One can still use generic algebras though. > - [DoubleMatrix](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt) : Numpy-like operations for 2d real structures > - [grids](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt) : Uniform grid generators +
-### [kmath-functions](kmath-functions) +* ### [kmath-functions](kmath-functions) > > > **Maturity**: EXPERIMENTAL @@ -153,18 +193,21 @@ One can still use generic algebras though. > - [spline interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt) : Cubic spline XY interpolator. > - [integration](kmath-functions/#) : Univariate and multivariate quadratures +
-### [kmath-geometry](kmath-geometry) +* ### [kmath-geometry](kmath-geometry) > > > **Maturity**: PROTOTYPE +
-### [kmath-histograms](kmath-histograms) +* ### [kmath-histograms](kmath-histograms) > > > **Maturity**: PROTOTYPE +
-### [kmath-jafama](kmath-jafama) +* ### [kmath-jafama](kmath-jafama) > > > **Maturity**: PROTOTYPE @@ -172,13 +215,15 @@ One can still use generic algebras though. > **Features:** > - [jafama-double](kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/) : Double ExtendedField implementations based on Jafama +
-### [kmath-jupyter](kmath-jupyter) +* ### [kmath-jupyter](kmath-jupyter) > > > **Maturity**: PROTOTYPE +
-### [kmath-kotlingrad](kmath-kotlingrad) +* ### [kmath-kotlingrad](kmath-kotlingrad) > > > **Maturity**: EXPERIMENTAL @@ -187,18 +232,15 @@ One can still use generic algebras though. > - [differentiable-mst-expression](kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt) : MST based DifferentiableExpression. > - [scalars-adapters](kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt) : Conversions between Kotlin∇'s SFun and MST +
-### [kmath-memory](kmath-memory) +* ### [kmath-memory](kmath-memory) > An API and basic implementation for arranging objects in a continuous memory block. > > **Maturity**: DEVELOPMENT +
-### [kmath-multik](kmath-multik) -> -> -> **Maturity**: PROTOTYPE - -### [kmath-nd4j](kmath-nd4j) +* ### [kmath-nd4j](kmath-nd4j) > > > **Maturity**: EXPERIMENTAL @@ -208,28 +250,21 @@ One can still use generic algebras though. > - [nd4jarrayrings](kmath-nd4j/#) : Rings over Nd4jArrayStructure of Int and Long > - [nd4jarrayfields](kmath-nd4j/#) : Fields over Nd4jArrayStructure of Float and Double +
-### [kmath-optimization](kmath-optimization) +* ### [kmath-stat](kmath-stat) > > > **Maturity**: EXPERIMENTAL +
-### [kmath-stat](kmath-stat) -> -> -> **Maturity**: EXPERIMENTAL - -### [kmath-symja](kmath-symja) +* ### [kmath-symja](kmath-symja) > > > **Maturity**: PROTOTYPE +
-### [kmath-tensorflow](kmath-tensorflow) -> -> -> **Maturity**: PROTOTYPE - -### [kmath-tensors](kmath-tensors) +* ### [kmath-tensors](kmath-tensors) > > > **Maturity**: PROTOTYPE @@ -239,11 +274,13 @@ One can still use generic algebras though. > - [tensor algebra with broadcasting](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/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) +* ### [kmath-viktor](kmath-viktor) > > > **Maturity**: DEVELOPMENT +
## Multi-platform support @@ -282,8 +319,8 @@ repositories { } dependencies { - api("space.kscience:kmath-core:$version") - // api("space.kscience:kmath-core-jvm:$version") for jvm-specific version + api("space.kscience:kmath-core:0.3.0-dev-14") + // api("space.kscience:kmath-core-jvm:0.3.0-dev-14") for jvm-specific version } ``` diff --git a/benchmarks/README.md b/benchmarks/README.md deleted file mode 100644 index cd8fbafd3..000000000 --- a/benchmarks/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Module benchmarks - - - diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index 22712816d..d96c5a8b6 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -13,22 +13,19 @@ sourceSets.register("benchmarks") repositories { mavenCentral() + maven("https://repo.kotlin.link") + maven("https://clojars.org/repo") + maven("https://jitpack.io") + + maven("http://logicrunch.research.it.uu.se/maven") { + isAllowInsecureProtocol = true + } } kotlin { jvm() - js(IR) { - nodejs() - } - sourceSets { - all { - languageSettings { - progressiveMode = true - } - } - val commonMain by getting { dependencies { implementation(project(":kmath-ast")) @@ -38,8 +35,8 @@ kotlin { implementation(project(":kmath-stat")) implementation(project(":kmath-dimensions")) implementation(project(":kmath-for-real")) - implementation(project(":kmath-tensors")) - implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.4.2") + implementation(project(":kmath-jafama")) + implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.1") } } @@ -50,10 +47,6 @@ kotlin { implementation(project(":kmath-nd4j")) implementation(project(":kmath-kotlingrad")) implementation(project(":kmath-viktor")) - implementation(project(":kmath-jafama")) - implementation(project(":kmath-multik")) - implementation(projects.kmath.kmathTensorflow) - implementation("org.tensorflow:tensorflow-core-platform:0.4.0") implementation("org.nd4j:nd4j-native:1.0.0-M1") // uncomment if your system supports AVX2 // val os = System.getProperty("os.name") @@ -74,13 +67,12 @@ benchmark { // Setup configurations targets { register("jvm") - register("js") } fun kotlinx.benchmark.gradle.BenchmarkConfiguration.commonConfiguration() { - warmups = 2 + warmups = 1 iterations = 5 - iterationTime = 2000 + iterationTime = 1000 iterationTimeUnit = "ms" } @@ -89,23 +81,13 @@ benchmark { include("BufferBenchmark") } - configurations.register("nd") { - commonConfiguration() - include("NDFieldBenchmark") - } - configurations.register("dot") { commonConfiguration() include("DotBenchmark") } configurations.register("expressions") { - // Some extra precision - warmups = 2 - iterations = 10 - iterationTime = 10 - iterationTimeUnit = "s" - outputTimeUnit = "s" + commonConfiguration() include("ExpressionsInterpretersBenchmark") } @@ -123,21 +105,6 @@ benchmark { commonConfiguration() include("JafamaBenchmark") } - - configurations.register("tensorAlgebra") { - commonConfiguration() - include("TensorAlgebraBenchmark") - } - - configurations.register("viktor") { - commonConfiguration() - include("ViktorBenchmark") - } - - configurations.register("viktorLog") { - commonConfiguration() - include("ViktorLogBenchmark") - } } // Fix kotlinx-benchmarks bug @@ -147,21 +114,23 @@ afterEvaluate { } } + kotlin.sourceSets.all { with(languageSettings) { - optIn("kotlin.contracts.ExperimentalContracts") - optIn("kotlin.ExperimentalUnsignedTypes") - optIn("space.kscience.kmath.misc.UnstableKMathAPI") + useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") + useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") + useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") } } -tasks.withType { +tasks.withType { kotlinOptions { jvmTarget = "11" - freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xlambdas=indy" + freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" } } + readme { maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL } diff --git a/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt deleted file mode 100644 index 126a2e648..000000000 --- a/benchmarks/src/jsMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ /dev/null @@ -1,105 +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.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.bindSymbol -import space.kscience.kmath.operations.invoke -import kotlin.math.sin -import kotlin.random.Random -import space.kscience.kmath.estree.compileToExpression as estreeCompileToExpression -import space.kscience.kmath.wasm.compileToExpression as wasmCompileToExpression - -@State(Scope.Benchmark) -class ExpressionsInterpretersBenchmark { - /** - * Benchmark case for [Expression] created with [expressionInExtendedField]. - */ - @Benchmark - fun functionalExpression(blackhole: Blackhole) = invokeAndSum(functional, blackhole) - - /** - * Benchmark case for [Expression] created with [toExpression]. - */ - @Benchmark - fun mstExpression(blackhole: Blackhole) = invokeAndSum(mst, blackhole) - - /** - * Benchmark case for [Expression] created with [compileToExpression]. - */ - @Benchmark - fun wasmExpression(blackhole: Blackhole) = invokeAndSum(wasm, blackhole) - - /** - * Benchmark case for [Expression] created with [compileToExpression]. - */ - @Benchmark - fun estreeExpression(blackhole: Blackhole) = invokeAndSum(estree, blackhole) - - /** - * Benchmark case for [Expression] implemented manually with `kotlin.math` functions. - */ - @Benchmark - fun rawExpression(blackhole: Blackhole) = invokeAndSum(raw, blackhole) - - /** - * Benchmark case for direct computation w/o [Expression]. - */ - @Benchmark - fun justCalculate(blackhole: Blackhole) { - val random = Random(0) - var sum = 0.0 - - repeat(times) { - val x = random.nextDouble() - sum += x * 2.0 + 2.0 / x - 16.0 / sin(x) - } - - blackhole.consume(sum) - } - - private fun invokeAndSum(expr: Expression, blackhole: Blackhole) { - val random = Random(0) - var sum = 0.0 - val m = HashMap() - - repeat(times) { - m[x] = random.nextDouble() - sum += expr(m) - } - - blackhole.consume(sum) - } - - private companion object { - private val x by symbol - private const val times = 1_000_000 - - private val functional = DoubleField.expression { - val x = bindSymbol(Symbol.x) - x * number(2.0) + 2.0 / x - 16.0 / sin(x) - } - - private val node = MstExtendedField { - x * 2.0 + number(2.0) / x - number(16.0) / sin(x) - } - - private val mst = node.toExpression(DoubleField) - private val wasm = node.wasmCompileToExpression(DoubleField) - private val estree = node.estreeCompileToExpression(DoubleField) - - private val raw = Expression { args -> - val x = args[x]!! - x * 2.0 + 2.0 / x - 16.0 / sin(x) - } - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt index ff933997f..17983e88c 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.benchmarks diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt index 188a48ca7..6f501dedb 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.benchmarks @@ -11,10 +11,7 @@ import org.openjdk.jmh.annotations.Benchmark import org.openjdk.jmh.annotations.Scope import org.openjdk.jmh.annotations.State import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.BigIntField -import space.kscience.kmath.operations.JBigIntegerField -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.operations.parseBigInteger +import space.kscience.kmath.operations.* import java.math.BigInteger @@ -22,24 +19,12 @@ import java.math.BigInteger @State(Scope.Benchmark) internal class BigIntBenchmark { - val kmSmallNumber = BigIntField.number(100) - val jvmSmallNumber = JBigIntegerField.number(100) val kmNumber = BigIntField.number(Int.MAX_VALUE) val jvmNumber = JBigIntegerField.number(Int.MAX_VALUE) - val kmLargeNumber = BigIntField { number(11).pow(100_000U) } - val jvmLargeNumber: BigInteger = JBigIntegerField { number(11).pow(100_000) } + val largeKmNumber = BigIntField { number(11).pow(100_000U) } + val largeJvmNumber: BigInteger = JBigIntegerField { number(11).pow(100_000) } val bigExponent = 50_000 - @Benchmark - fun kmSmallAdd(blackhole: Blackhole) = BigIntField { - blackhole.consume(kmSmallNumber + kmSmallNumber + kmSmallNumber) - } - - @Benchmark - fun jvmSmallAdd(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(jvmSmallNumber + jvmSmallNumber + jvmSmallNumber) - } - @Benchmark fun kmAdd(blackhole: Blackhole) = BigIntField { blackhole.consume(kmNumber + kmNumber + kmNumber) @@ -52,12 +37,12 @@ internal class BigIntBenchmark { @Benchmark fun kmAddLarge(blackhole: Blackhole) = BigIntField { - blackhole.consume(kmLargeNumber + kmLargeNumber + kmLargeNumber) + blackhole.consume(largeKmNumber + largeKmNumber + largeKmNumber) } @Benchmark fun jvmAddLarge(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(jvmLargeNumber + jvmLargeNumber + jvmLargeNumber) + blackhole.consume(largeJvmNumber + largeJvmNumber + largeJvmNumber) } @Benchmark @@ -67,7 +52,7 @@ internal class BigIntBenchmark { @Benchmark fun kmMultiplyLarge(blackhole: Blackhole) = BigIntField { - blackhole.consume(kmLargeNumber*kmLargeNumber) + blackhole.consume(largeKmNumber*largeKmNumber) } @Benchmark @@ -77,7 +62,7 @@ internal class BigIntBenchmark { @Benchmark fun jvmMultiplyLarge(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(jvmLargeNumber*jvmLargeNumber) + blackhole.consume(largeJvmNumber*largeJvmNumber) } @Benchmark diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt index 39819d407..5cf194b67 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.benchmarks diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt index 7d5ae310b..629408479 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.benchmarks @@ -11,15 +11,9 @@ import kotlinx.benchmark.Scope import kotlinx.benchmark.State import space.kscience.kmath.commons.linear.CMLinearSpace import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM +import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.invoke -import space.kscience.kmath.linear.linearSpace -import space.kscience.kmath.multik.multikAlgebra import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.tensorflow.produceWithTF -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.tensorAlgebra import kotlin.random.Random @State(Scope.Benchmark) @@ -29,12 +23,8 @@ internal class DotBenchmark { const val dim = 1000 //creating invertible matrix - val matrix1 = DoubleField.linearSpace.buildMatrix(dim, dim) { _, _ -> - random.nextDouble() - } - val matrix2 = DoubleField.linearSpace.buildMatrix(dim, dim) { _, _ -> - random.nextDouble() - } + val matrix1 = LinearSpace.real.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } + val matrix2 = LinearSpace.real.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } val cmMatrix1 = CMLinearSpace { matrix1.toCM() } val cmMatrix2 = CMLinearSpace { matrix2.toCM() } @@ -43,58 +33,38 @@ internal class DotBenchmark { val ejmlMatrix2 = EjmlLinearSpaceDDRM { matrix2.toEjml() } } - @Benchmark - fun tfDot(blackhole: Blackhole) { - blackhole.consume( - DoubleField.produceWithTF { - matrix1 dot matrix1 - } - ) + fun cmDot(blackhole: Blackhole) { + CMLinearSpace.run { + blackhole.consume(cmMatrix1 dot cmMatrix2) + } } @Benchmark - fun cmDotWithConversion(blackhole: Blackhole) = CMLinearSpace { - blackhole.consume(matrix1 dot matrix2) + fun ejmlDot(blackhole: Blackhole) { + EjmlLinearSpaceDDRM { + blackhole.consume(ejmlMatrix1 dot ejmlMatrix2) + } } @Benchmark - fun cmDot(blackhole: Blackhole) = CMLinearSpace { - blackhole.consume(cmMatrix1 dot cmMatrix2) + fun ejmlDotWithConversion(blackhole: Blackhole) { + EjmlLinearSpaceDDRM { + blackhole.consume(matrix1 dot matrix2) + } } @Benchmark - fun ejmlDot(blackhole: Blackhole) = EjmlLinearSpaceDDRM { - blackhole.consume(ejmlMatrix1 dot ejmlMatrix2) + fun bufferedDot(blackhole: Blackhole) { + LinearSpace.auto(DoubleField).invoke { + blackhole.consume(matrix1 dot matrix2) + } } @Benchmark - fun ejmlDotWithConversion(blackhole: Blackhole) = EjmlLinearSpaceDDRM { - blackhole.consume(matrix1 dot matrix2) - } - - @Benchmark - fun tensorDot(blackhole: Blackhole) = with(DoubleField.tensorAlgebra) { - blackhole.consume(matrix1 dot matrix2) - } - - @Benchmark - fun multikDot(blackhole: Blackhole) = with(DoubleField.multikAlgebra) { - blackhole.consume(matrix1 dot matrix2) - } - - @Benchmark - fun bufferedDot(blackhole: Blackhole) = with(DoubleField.linearSpace(Buffer.Companion::auto)) { - blackhole.consume(matrix1 dot matrix2) - } - - @Benchmark - fun doubleDot(blackhole: Blackhole) = with(DoubleField.linearSpace) { - blackhole.consume(matrix1 dot matrix2) - } - - @Benchmark - fun doubleTensorDot(blackhole: Blackhole) = DoubleTensorAlgebra.invoke { - blackhole.consume(matrix1 dot matrix2) + fun realDot(blackhole: Blackhole) { + LinearSpace.real { + blackhole.consume(matrix1 dot matrix2) + } } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt index db3524e67..8c3c8ec2b 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.benchmarks @@ -11,7 +11,6 @@ import kotlinx.benchmark.Scope import kotlinx.benchmark.State import space.kscience.kmath.asm.compileToExpression import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke @@ -36,30 +35,7 @@ internal class ExpressionsInterpretersBenchmark { * Benchmark case for [Expression] created with [compileToExpression]. */ @Benchmark - fun asmGenericExpression(blackhole: Blackhole) = invokeAndSum(asmGeneric, blackhole) - - /** - * Benchmark case for [Expression] created with [compileToExpression]. - */ - @Benchmark - fun asmPrimitiveExpressionArray(blackhole: Blackhole) { - val random = Random(0) - var sum = 0.0 - val m = DoubleArray(1) - - repeat(times) { - m[xIdx] = random.nextDouble() - sum += asmPrimitive(m) - } - - blackhole.consume(sum) - } - - /** - * Benchmark case for [Expression] created with [compileToExpression]. - */ - @Benchmark - fun asmPrimitiveExpression(blackhole: Blackhole) = invokeAndSum(asmPrimitive, blackhole) + fun asmExpression(blackhole: Blackhole) = invokeAndSum(asm, blackhole) /** * Benchmark case for [Expression] implemented manually with `kotlin.math` functions. @@ -86,11 +62,9 @@ internal class ExpressionsInterpretersBenchmark { private fun invokeAndSum(expr: Expression, blackhole: Blackhole) { val random = Random(0) var sum = 0.0 - val m = HashMap() repeat(times) { - m[x] = random.nextDouble() - sum += expr(m) + sum += expr(x to random.nextDouble()) } blackhole.consume(sum) @@ -98,11 +72,11 @@ internal class ExpressionsInterpretersBenchmark { private companion object { private val x by symbol + private val algebra = DoubleField private const val times = 1_000_000 - private val functional = DoubleField.expression { - val x = bindSymbol(Symbol.x) - x * number(2.0) + 2.0 / x - 16.0 / sin(x) + private val functional = DoubleField.expressionInExtendedField { + bindSymbol(x) * number(2.0) + number(2.0) / bindSymbol(x) - number(16.0) / sin(bindSymbol(x)) } private val node = MstExtendedField { @@ -110,11 +84,7 @@ internal class ExpressionsInterpretersBenchmark { } private val mst = node.toExpression(DoubleField) - - private val asmPrimitive = node.compileToExpression(DoubleField) - private val xIdx = asmPrimitive.indexer.indexOf(x) - - private val asmGeneric = node.compileToExpression(DoubleField as Algebra) + private val asm = node.compileToExpression(DoubleField) private val raw = Expression { args -> val x = args[x]!! diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt index 5d4eee7c0..9c6551302 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.benchmarks diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt index 4ff687aac..1072a55c3 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.benchmarks @@ -10,12 +10,13 @@ import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State import space.kscience.kmath.commons.linear.CMLinearSpace -import space.kscience.kmath.commons.linear.lupSolver +import space.kscience.kmath.commons.linear.inverse import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM +import space.kscience.kmath.linear.InverseMatrixFeature +import space.kscience.kmath.linear.LinearSpace +import space.kscience.kmath.linear.inverseWithLup import space.kscience.kmath.linear.invoke -import space.kscience.kmath.linear.linearSpace -import space.kscience.kmath.linear.lupSolver -import space.kscience.kmath.operations.algebra +import space.kscience.kmath.nd.getFeature import kotlin.random.Random @State(Scope.Benchmark) @@ -24,7 +25,7 @@ internal class MatrixInverseBenchmark { private val random = Random(1224) private const val dim = 100 - private val space = Double.algebra.linearSpace + private val space = LinearSpace.real //creating invertible matrix private val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } @@ -34,20 +35,20 @@ internal class MatrixInverseBenchmark { @Benchmark fun kmathLupInversion(blackhole: Blackhole) { - blackhole.consume(Double.algebra.linearSpace.lupSolver().inverse(matrix)) + blackhole.consume(LinearSpace.real.inverseWithLup(matrix)) } @Benchmark fun cmLUPInversion(blackhole: Blackhole) { CMLinearSpace { - blackhole.consume(lupSolver().inverse(matrix)) + blackhole.consume(inverse(matrix)) } } @Benchmark fun ejmlInverse(blackhole: Blackhole) { EjmlLinearSpaceDDRM { - blackhole.consume(matrix.toEjml().inverse()) + blackhole.consume(matrix.getFeature>()?.inverse) } } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt index e3b3dde05..0cd9a46ab 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.benchmarks @@ -9,97 +9,45 @@ import kotlinx.benchmark.Benchmark import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State -import org.jetbrains.kotlinx.multik.api.Multik -import org.jetbrains.kotlinx.multik.api.ones -import org.jetbrains.kotlinx.multik.ndarray.data.DN -import org.jetbrains.kotlinx.multik.ndarray.data.DataType -import space.kscience.kmath.multik.multikAlgebra -import space.kscience.kmath.nd.BufferedFieldOpsND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.nd.one -import space.kscience.kmath.nd4j.nd4j +import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.one -import space.kscience.kmath.tensors.core.tensorAlgebra -import space.kscience.kmath.viktor.viktorAlgebra @State(Scope.Benchmark) internal class NDFieldBenchmark { @Benchmark - fun autoFieldAdd(blackhole: Blackhole) = with(autoField) { - var res: StructureND = one(shape) - repeat(n) { res += 1.0 } - blackhole.consume(res) + fun autoFieldAdd(blackhole: Blackhole) { + with(autoField) { + var res: StructureND = one + repeat(n) { res += one } + blackhole.consume(res) + } } @Benchmark - fun specializedFieldAdd(blackhole: Blackhole) = with(specializedField) { - var res: StructureND = one(shape) - repeat(n) { res += 1.0 } - blackhole.consume(res) + fun specializedFieldAdd(blackhole: Blackhole) { + with(specializedField) { + var res: StructureND = one + repeat(n) { res += 1.0 } + blackhole.consume(res) + } } + @Benchmark - fun boxingFieldAdd(blackhole: Blackhole) = with(genericField) { - var res: StructureND = one(shape) - repeat(n) { res += 1.0 } - blackhole.consume(res) + fun boxingFieldAdd(blackhole: Blackhole) { + with(genericField) { + var res: StructureND = one + repeat(n) { res += 1.0 } + blackhole.consume(res) + } } - @Benchmark - fun multikAdd(blackhole: Blackhole) = with(multikField) { - var res: StructureND = one(shape) - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - - @Benchmark - fun viktorAdd(blackhole: Blackhole) = with(viktorField) { - var res: StructureND = one(shape) - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - - @Benchmark - fun tensorAdd(blackhole: Blackhole) = with(Double.tensorAlgebra) { - var res: DoubleTensor = one(shape) - repeat(n) { res = res + 1.0 } - blackhole.consume(res) - } - - @Benchmark - fun tensorInPlaceAdd(blackhole: Blackhole) = with(Double.tensorAlgebra) { - val res: DoubleTensor = one(shape) - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - - @Benchmark - fun multikInPlaceAdd(blackhole: Blackhole) = with(DoubleField.multikAlgebra) { - val res = Multik.ones(shape, DataType.DoubleDataType).wrap() - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - -// @Benchmark -// fun nd4jAdd(blackhole: Blackhole) = with(nd4jField) { -// var res: StructureND = one(dim, dim) -// repeat(n) { res += 1.0 } -// blackhole.consume(res) -// } - private companion object { private const val dim = 1000 private const val n = 100 - private val shape = intArrayOf(dim, dim) - private val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto) - private val specializedField = DoubleField.ndAlgebra - private val genericField = BufferedFieldOpsND(DoubleField, Buffer.Companion::boxing) - private val nd4jField = DoubleField.nd4j - private val multikField = DoubleField.multikAlgebra - private val viktorField = DoubleField.viktorAlgebra + private val autoField = AlgebraND.auto(DoubleField, dim, dim) + private val specializedField = AlgebraND.real(dim, dim) + private val genericField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim) } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt deleted file mode 100644 index 38e064e53..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/TensorAlgebraBenchmark.kt +++ /dev/null @@ -1,37 +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.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import space.kscience.kmath.linear.linearSpace -import space.kscience.kmath.linear.matrix -import space.kscience.kmath.linear.symmetric -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.tensors.core.tensorAlgebra -import kotlin.random.Random - -@State(Scope.Benchmark) -internal class TensorAlgebraBenchmark { - companion object { - private val random = Random(12224) - private const val dim = 30 - - private val matrix = DoubleField.linearSpace.matrix(dim, dim).symmetric { _, _ -> random.nextDouble() } - } - - @Benchmark - fun tensorSymEigSvd(blackhole: Blackhole) = with(Double.tensorAlgebra) { - blackhole.consume(matrix.symEigSvd(1e-10)) - } - - @Benchmark - fun tensorSymEigJacobi(blackhole: Blackhole) = with(Double.tensorAlgebra) { - blackhole.consume(matrix.symEigJacobi(50, 1e-10)) - } -} \ No newline at end of file diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt index de301678c..1ddc79cf8 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.benchmarks @@ -10,17 +10,19 @@ import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.nd.* +import space.kscience.kmath.nd.AlgebraND +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.nd.auto +import space.kscience.kmath.nd.real import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.viktor.ViktorFieldND +import space.kscience.kmath.viktor.ViktorNDField @State(Scope.Benchmark) internal class ViktorBenchmark { @Benchmark fun automaticFieldAddition(blackhole: Blackhole) { with(autoField) { - var res: StructureND = one(shape) + var res: StructureND = one repeat(n) { res += 1.0 } blackhole.consume(res) } @@ -29,7 +31,7 @@ internal class ViktorBenchmark { @Benchmark fun realFieldAddition(blackhole: Blackhole) { with(realField) { - var res: StructureND = one(shape) + var res: StructureND = one repeat(n) { res += 1.0 } blackhole.consume(res) } @@ -38,7 +40,7 @@ internal class ViktorBenchmark { @Benchmark fun viktorFieldAddition(blackhole: Blackhole) { with(viktorField) { - var res = one(shape) + var res = one repeat(n) { res += 1.0 } blackhole.consume(res) } @@ -55,11 +57,10 @@ internal class ViktorBenchmark { private companion object { private const val dim = 1000 private const val n = 100 - private val shape = Shape(dim, dim) // automatically build context most suited for given type. - private val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto) - private val realField = DoubleField.ndAlgebra - private val viktorField = ViktorFieldND(dim, dim) + private val autoField = AlgebraND.auto(DoubleField, dim, dim) + private val realField = AlgebraND.real(dim, dim) + private val viktorField = ViktorNDField(dim, dim) } } diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt index dfdd89d74..8622e8f30 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.benchmarks @@ -10,21 +10,19 @@ import kotlinx.benchmark.Blackhole import kotlinx.benchmark.Scope import kotlinx.benchmark.State import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.nd.BufferedFieldOpsND -import space.kscience.kmath.nd.Shape -import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.nd.one +import space.kscience.kmath.nd.AlgebraND +import space.kscience.kmath.nd.auto +import space.kscience.kmath.nd.real import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.Buffer import space.kscience.kmath.viktor.ViktorFieldND @State(Scope.Benchmark) internal class ViktorLogBenchmark { @Benchmark fun realFieldLog(blackhole: Blackhole) { - with(realField) { - val fortyTwo = structureND(shape) { 42.0 } - var res = one(shape) + with(realNdField) { + val fortyTwo = produce { 42.0 } + var res = one repeat(n) { res = ln(fortyTwo) } blackhole.consume(res) } @@ -33,7 +31,7 @@ internal class ViktorLogBenchmark { @Benchmark fun viktorFieldLog(blackhole: Blackhole) { with(viktorField) { - val fortyTwo = structureND(shape) { 42.0 } + val fortyTwo = produce { 42.0 } var res = one repeat(n) { res = ln(fortyTwo) } blackhole.consume(res) @@ -51,11 +49,10 @@ internal class ViktorLogBenchmark { private companion object { private const val dim = 1000 private const val n = 100 - private val shape = Shape(dim, dim) // automatically build context most suited for given type. - private val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto) - private val realField = DoubleField.ndAlgebra - private val viktorField = ViktorFieldND(dim, dim) + private val autoField = AlgebraND.auto(DoubleField, dim, dim) + private val realNdField = AlgebraND.real(dim, dim) + private val viktorField = ViktorFieldND(intArrayOf(dim, dim)) } } diff --git a/build.gradle.kts b/build.gradle.kts index 445976853..6bb19cd35 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,23 +1,31 @@ +import java.net.URL + plugins { id("ru.mipt.npm.gradle.project") - id("org.jetbrains.kotlinx.kover") version "0.5.0" + kotlin("jupyter.api") apply false } allprojects { repositories { - maven("https://repo.kotlin.link") + maven("https://clojars.org/repo") + maven("https://jitpack.io") + + maven("http://logicrunch.research.it.uu.se/maven") { + isAllowInsecureProtocol = true + } + maven("https://oss.sonatype.org/content/repositories/snapshots") mavenCentral() } group = "space.kscience" - version = "0.3.0-dev-20" + version = "0.3.0-dev-14" } subprojects { if (name.startsWith("kmath")) apply() - plugins.withId("org.jetbrains.dokka"){ + afterEvaluate { tasks.withType { dependsOn(tasks["assemble"]) @@ -31,7 +39,7 @@ subprojects { localDirectory.set(kotlinDir) remoteUrl.set( - java.net.URL("https://github.com/mipt-npm/kmath/tree/master/${this@subprojects.name}/$kotlinDirPath") + URL("https://github.com/mipt-npm/${rootProject.name}/tree/master/${this@subprojects.name}/$kotlinDirPath") ) } @@ -56,9 +64,9 @@ subprojects { readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") ksciencePublish { - github("kmath", addToRelease = false) - space() - sonatype() + vcs("https://github.com/mipt-npm/kmath") + space(publish = true) + sonatype(publish = true) } apiValidation.nonPublicMarkers.add("space.kscience.kmath.misc.UnstableKMathAPI") diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index fa5142538..36a1ffd9e 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,31 +1,20 @@ plugins { `kotlin-dsl` - `version-catalog` - alias(miptNpmLibs.plugins.kotlin.plugin.serialization) + kotlin("plugin.serialization") version "1.4.31" } -java.targetCompatibility = JavaVersion.VERSION_11 - repositories { - mavenLocal() maven("https://repo.kotlin.link") mavenCentral() gradlePluginPortal() } -val toolsVersion: String by extra -val kotlinVersion = miptNpmLibs.versions.kotlin.asProvider().get() -val benchmarksVersion = miptNpmLibs.versions.kotlinx.benchmark.get() - dependencies { - api("ru.mipt.npm:gradle-tools:$toolsVersion") - //plugins form benchmarks - api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:$benchmarksVersion") - api("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion") - //to be used inside build-script only - implementation(miptNpmLibs.kotlinx.serialization.json) + api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0") + api("ru.mipt.npm:gradle-tools:0.10.2") + api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:0.3.1") } kotlin.sourceSets.all { - languageSettings.optIn("kotlin.OptIn") + languageSettings.useExperimentalAnnotation("kotlin.ExperimentalStdlibApi") } diff --git a/buildSrc/gradle.properties b/buildSrc/gradle.properties deleted file mode 100644 index a0b05e812..000000000 --- a/buildSrc/gradle.properties +++ /dev/null @@ -1,7 +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. -# - -kotlin.code.style=official -toolsVersion=0.11.2-kotlin-1.6.10 diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts deleted file mode 100644 index 7c1df133d..000000000 --- a/buildSrc/settings.gradle.kts +++ /dev/null @@ -1,23 +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. - */ - -enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") - -dependencyResolutionManagement { - val toolsVersion: String by extra - - repositories { - mavenLocal() - maven("https://repo.kotlin.link") - mavenCentral() - gradlePluginPortal() - } - - versionCatalogs { - create("miptNpmLibs") { - from("ru.mipt.npm:version-catalog:$toolsVersion") - } - } -} diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt index eaa0f59d8..6859de845 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.benchmarks diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt index dc9327348..72c9ff0ad 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt @@ -1,20 +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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.benchmarks import kotlinx.benchmark.gradle.BenchmarksExtension -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json +import kotlinx.serialization.* +import kotlinx.serialization.json.* import org.gradle.api.Project import ru.mipt.npm.gradle.KScienceReadmeExtension -import java.time.LocalDateTime -import java.time.ZoneId -import java.time.format.DateTimeFormatter -import java.time.format.DateTimeFormatterBuilder -import java.time.format.SignStyle +import java.time.* +import java.time.format.* import java.time.temporal.ChronoField.* private val ISO_DATE_TIME: DateTimeFormatter = DateTimeFormatterBuilder().run { @@ -50,14 +47,14 @@ fun Project.addBenchmarkProperties() { rootProject.subprojects.forEach { p -> p.extensions.findByType(KScienceReadmeExtension::class.java)?.run { benchmarksProject.extensions.findByType(BenchmarksExtension::class.java)?.configurations?.forEach { cfg -> - property("benchmark${cfg.name.capitalize()}") { + property("benchmark${cfg.name.replaceFirstChar(Char::uppercase)}") { val launches = benchmarksProject.buildDir.resolve("reports/benchmarks/${cfg.name}") val resDirectory = launches.listFiles()?.maxByOrNull { LocalDateTime.parse(it.name, ISO_DATE_TIME).atZone(ZoneId.systemDefault()).toInstant() } - if (resDirectory == null || !(resDirectory.resolve("jvm.json")).exists()) { + if (resDirectory == null) { "> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**." } else { val reports = diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt index 7f8cb35b3..68bb10428 100644 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ @file:Suppress("KDocUnresolvedReference") @@ -203,7 +203,7 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, override fun ${type}.times(v: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> = v * this @UnstableKMathAPI - override fun computeFeature(structure: Matrix<${type}>, type: KClass): F? { + override fun getFeature(structure: Matrix<${type}>, type: KClass): F? { structure.getFeature(type)?.let { return it } val origin = structure.toEjml().origin @@ -240,10 +240,10 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, } override val q: Matrix<${type}> by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) + qr.getQ(null, false).wrapMatrix() + OrthogonalFeature } - override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } + override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix() + UFeature } } CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<${type}> { @@ -251,7 +251,7 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, val cholesky = DecompositionFactory_${ops}.chol(structure.rowNum, true).apply { decompose(origin.copy()) } - cholesky.getT(null).wrapMatrix().withFeature(LFeature) + cholesky.getT(null).wrapMatrix() + LFeature } } @@ -261,11 +261,11 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, } override val l: Matrix<${type}> by lazy { - lup.getLower(null).wrapMatrix().withFeature(LFeature) + lup.getLower(null).wrapMatrix() + LFeature } override val u: Matrix<${type}> by lazy { - lup.getUpper(null).wrapMatrix().withFeature(UFeature) + lup.getUpper(null).wrapMatrix() + UFeature } override val p: Matrix<${type}> by lazy { lup.getRowPivot(null).wrapMatrix() } @@ -275,10 +275,10 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, } override val q: Matrix<${type}> by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) + qr.getQ(null, false).wrapMatrix() + OrthogonalFeature } - override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } + override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix() + UFeature } } CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<${type}> { @@ -286,7 +286,7 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, val cholesky = DecompositionFactory_${ops}.cholesky().apply { decompose(origin.copy()) } - (cholesky.getT(null) as ${ejmlMatrixParentTypeMatrix}).wrapMatrix().withFeature(LFeature) + (cholesky.getT(null) as ${ejmlMatrixParentTypeMatrix}).wrapMatrix() + LFeature } } @@ -297,11 +297,11 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, } override val l: Matrix<${type}> by lazy { - lu.getLower(null).wrapMatrix().withFeature(LFeature) + lu.getLower(null).wrapMatrix() + LFeature } override val u: Matrix<${type}> by lazy { - lu.getUpper(null).wrapMatrix().withFeature(UFeature) + lu.getUpper(null).wrapMatrix() + UFeature } override val inverse: Matrix<${type}> by lazy { diff --git a/docs/diagrams/core.puml b/docs/diagrams/core.puml deleted file mode 100644 index 87f8f2e2d..000000000 --- a/docs/diagrams/core.puml +++ /dev/null @@ -1,1020 +0,0 @@ -@startuml -interface "ColumnarData" { - size: Int -} -interface "XYColumnarData" { - x: Buffer - y: Buffer -} -interface "XYErrorColumnarData" { - yErr: Buffer -} -interface "XYZColumnarData" { - z: Buffer -} -interface "Domain" { - dimension: Int -} -interface "DoubleDomain" { - -} -class "HyperSquareDomain" { - lower: Buffer - upper: Buffer -} -class "UnconstrainedDomain" { - dimension: Int -} -class "UnivariateDomain" { - range: ClosedFloatingPointRange -} -interface "DifferentiableExpression" { - -} -interface "SpecialDifferentiableExpression" { - -} -abstract "FirstDerivativeExpression" { - -} -interface "AutoDiffProcessor" { - -} -interface "Expression" { - -} -interface "ExpressionAlgebra" { - -} -abstract "FunctionalExpressionAlgebra" { - algebra: A -} -class "FunctionalExpressionGroup" { - algebra: A -} -class "FunctionalExpressionRing" { - algebra: A -} -class "FunctionalExpressionField" { - algebra: A -} -class "FunctionalExpressionExtendedField" { - algebra: A -} -interface "MST" { - -} -class "Numeric" { - value: Number -} -class "Unary" { - operation: String - value: MST -} -class "Binary" { - operation: String - left: MST - right: MST -} -class "InnerAlgebra" { - algebra: Algebra - arguments: Map -} -class "MstNumericAlgebra" { - number() - bindSymbolOrNull() - bindSymbol() - unaryOperationFunction() - binaryOperationFunction() -} -class "MstGroup" { - zero: MST.Numericnumber() - bindSymbolOrNull() - add() - unaryPlus() - unaryMinus() - minus() - scale() - binaryOperationFunction() - unaryOperationFunction() -} -class "MstRing" { - zero: MST.Numeric - one: MST.Numericnumber() - bindSymbolOrNull() - add() - scale() - multiply() - unaryPlus() - unaryMinus() - minus() - binaryOperationFunction() - unaryOperationFunction() -} -class "MstField" { - zero: MST.Numeric - one: MST.NumericbindSymbolOrNull() - number() - add() - scale() - multiply() - divide() - unaryPlus() - unaryMinus() - minus() - binaryOperationFunction() - unaryOperationFunction() -} -class "MstExtendedField" { - zero: MST.Numeric - one: MST.NumericbindSymbolOrNull() - number() - sin() - cos() - tan() - asin() - acos() - atan() - sinh() - cosh() - tanh() - asinh() - acosh() - atanh() - add() - sqrt() - scale() - multiply() - divide() - unaryPlus() - unaryMinus() - minus() - power() - exp() - ln() - binaryOperationFunction() - unaryOperationFunction() -} -class "MstLogicAlgebra" { - bindSymbolOrNull() - const() - not() - and() - or() - xor() -} -class "AutoDiffValue" { - value: T -} -class "DerivationResult" { - value: T - derivativeValues: Map - context: Field -} -class "SimpleAutoDiffField" { - context: F - bindings: Map -} -class "AutoDiffVariableWithDerivative" { - identity: String - value: T - d: T -} -class "SimpleAutoDiffExpression" { - field: F - function: SimpleAutoDiffField -} -class "SimpleAutoDiffExtendedField" { - context: F - bindings: Map -} -interface "Symbol" { - identity: String -} -class "StringSymbol" { - identity: String -} -interface "SymbolIndexer" { - symbols: List -} -class "SimpleSymbolIndexer" { - symbols: List -} -class "BufferedLinearSpace" { - elementAlgebra: A - bufferFactory: BufferFactory -} -interface "LinearSolver" { - -} -interface "LinearSpace" { - elementAlgebra: A -} -class "LupDecomposition" { - context: LinearSpace - elementContext: Field - lu: Matrix - pivot: IntArray - even: Boolean -} -class "MatrixBuilder" { - linearSpace: LinearSpace - rows: Int - columns: Int -} -class "SymmetricMatrixFeature" { - -} -interface "MatrixFeature" { - -} -interface "DiagonalFeature" { - -} -class "ZeroFeature" { - -} -class "UnitFeature" { - -} -interface "InverseMatrixFeature" { - inverse: Matrix -} -interface "DeterminantFeature" { - determinant: T -} -class "LFeature" { - -} -class "UFeature" { - -} -interface "LUDecompositionFeature" { - l: Matrix - u: Matrix -} -interface "LupDecompositionFeature" { - l: Matrix - u: Matrix - p: Matrix -} -class "OrthogonalFeature" { - -} -interface "QRDecompositionFeature" { - q: Matrix - r: Matrix -} -interface "CholeskyDecompositionFeature" { - l: Matrix -} -interface "SingularValueDecompositionFeature" { - u: Matrix - s: Matrix - v: Matrix - singularValues: Point -} -class "MatrixWrapper" { - origin: Matrix - features: FeatureSet -} -class "TransposedFeature" { - original: Matrix -} -class "VirtualMatrix" { - rowNum: Int - colNum: Int - generator: (i:Int,j:Int)->T -} -class "UnstableKMathAPI" { - -} -class "PerformancePitfall" { - message: String -} -interface "Featured" { - -} -interface "Feature" { - key: FeatureKey -} -class "FeatureSet" { - features: Map -} -interface "Loggable" { - -} -class "ShapeMismatchException" { - expected: IntArray - actual: IntArray -} -interface "AlgebraND" { - shape: IntArray - elementContext: C -} -interface "GroupND" { - -} -interface "RingND" { - -} -interface "FieldND" { - -} -interface "BufferAlgebraND" { - strides: Strides - bufferFactory: BufferFactory - buffer: Buffer -} -class "BufferedGroupND" { - shape: IntArray - elementContext: A - bufferFactory: BufferFactory -} -class "BufferedRingND" { - shape: IntArray - elementContext: R - bufferFactory: BufferFactory -} -class "BufferedFieldND" { - shape: IntArray - elementContext: R - bufferFactory: BufferFactory -} -class "BufferND" { - strides: Strides - buffer: Buffer -} -class "MutableBufferND" { - strides: Strides - mutableBuffer: MutableBuffer -} -class "DoubleFieldND" { - shape: IntArray -} -class "ShortRingND" { - shape: IntArray -} -interface "Structure1D" { - dimension: Int -} -interface "MutableStructure1D" { - -} -class "Structure1DWrapper" { - structure: StructureND -} -class "MutableStructure1DWrapper" { - structure: MutableStructureND -} -class "Buffer1DWrapper" { - buffer: Buffer -} -class "MutableBuffer1DWrapper" { - buffer: MutableBuffer -} -interface "Structure2D" { - rowNum: Int - colNum: Int - shape: IntArray - rows: List - columns: List -} -interface "MutableStructure2D" { - rows: List - columns: List -} -class "Structure2DWrapper" { - structure: StructureND -} -class "MutableStructure2DWrapper" { - structure: MutableStructureND -} -interface "StructureFeature" { - -} -interface "StructureND" { - shape: IntArray - dimension: Int -} -interface "MutableStructureND" { - -} -interface "Strides" { - shape: IntArray - strides: IntArray - linearSize: Int -} -class "DefaultStrides" { - shape: IntArray -} -class "KMathContext" { - -} -interface "Algebra" { - -} -interface "GroupOperations" { - -} -interface "Group" { - zero: T -} -interface "RingOperations" { - -} -interface "Ring" { - one: T -} -interface "FieldOperations" { - -} -interface "Field" { - -} -interface "AlgebraElement" { - context: C -} -interface "GroupElement" { - -} -interface "RingElement" { - -} -interface "FieldElement" { - -} -class "BigIntField" { - zero: BigInt - one: BigIntnumber() - unaryMinus() - add() - scale() - multiply() - divide() - unaryPlus() - unaryMinus() -} -class "BigInt" { - sign: Byte - magnitude: Magnitude -} -interface "BufferAlgebra" { - bufferFactory: BufferFactory - elementAlgebra: A -} -class "BufferField" { - bufferFactory: BufferFactory - elementAlgebra: A - size: Int -} -interface "LogicAlgebra" { - -} -class "BooleanAlgebra" { - const() - not() - and() - or() - xor() -} -interface "ExtendedFieldOperations" { - -} -interface "ExtendedField" { - -} -class "DoubleField" { - zero: Double - one: Doublenumber() - binaryOperationFunction() - add() - multiply() - divide() - scale() - sin() - cos() - tan() - acos() - asin() - atan() - sinh() - cosh() - tanh() - asinh() - acosh() - atanh() - sqrt() - power() - exp() - ln() - norm() - unaryMinus() - plus() - minus() - times() - div() -} -class "FloatField" { - zero: Float - one: Floatnumber() - binaryOperationFunction() - add() - scale() - multiply() - divide() - sin() - cos() - tan() - acos() - asin() - atan() - sinh() - cosh() - tanh() - asinh() - acosh() - atanh() - sqrt() - power() - exp() - ln() - norm() - unaryMinus() - plus() - minus() - times() - div() -} -class "IntRing" { - zero: Int - one: Intnumber() - add() - multiply() - norm() - unaryMinus() - plus() - minus() - times() -} -class "ShortRing" { - zero: Short - one: Shortnumber() - add() - multiply() - norm() - unaryMinus() - plus() - minus() - times() -} -class "ByteRing" { - zero: Byte - one: Bytenumber() - add() - multiply() - norm() - unaryMinus() - plus() - minus() - times() -} -class "LongRing" { - zero: Long - one: Longnumber() - add() - multiply() - norm() - unaryMinus() - plus() - minus() - times() -} -interface "NumericAlgebra" { - -} -interface "ScaleOperations" { - -} -interface "NumbersAddOperations" { - -} -interface "TrigonometricOperations" { - -} -interface "PowerOperations" { - -} -interface "ExponentialOperations" { - -} -interface "Norm" { - -} -interface "Buffer" { - size: Int -} -interface "MutableBuffer" { - -} -class "ListBuffer" { - list: List -} -class "MutableListBuffer" { - list: MutableList -} -class "ArrayBuffer" { - array: Array -} -class "ReadOnlyBuffer" { - buffer: MutableBuffer -} -class "VirtualBuffer" { - size: Int - generator: (Int)->T -} -class "BufferAccessor2D" { - rowNum: Int - colNum: Int - factory: MutableBufferFactory -} -class "Row" { - buffer: MutableBuffer - rowIndex: Int -} -class "DoubleBuffer" { - array: DoubleArray -} -class "DoubleBufferFieldOperations" { - unaryMinus() - add() - multiply() - divide() - sin() - cos() - tan() - asin() - acos() - atan() - sinh() - cosh() - tanh() - asinh() - acosh() - atanh() - power() - exp() - ln() -} -class "DoubleL2Norm" { - norm() -} -class "DoubleBufferField" { - size: Int -} -enum "ValueFlag" { - NAN - MISSING - NEGATIVE_INFINITY - POSITIVE_INFINITY -} -interface "FlaggedBuffer" { - -} -class "FlaggedDoubleBuffer" { - values: DoubleArray - flags: ByteArray -} -class "FloatBuffer" { - array: FloatArray -} -class "IntBuffer" { - array: IntArray -} -class "LongBuffer" { - array: LongArray -} -class "MemoryBuffer" { - memory: Memory - spec: MemorySpec -} -class "MutableMemoryBuffer" { - memory: Memory - spec: MemorySpec -} -class "ShortBuffer" { - array: ShortArray -} -class "ExpressionFieldTest" { - x -} -class "InterpretTest" { - -} -class "SimpleAutoDiffTest" { - x - y - z -} -class "DoubleLUSolverTest" { - -} -class "MatrixTest" { - -} -class "CumulativeKtTest" { - -} -class "BigIntAlgebraTest" { - -} -class "BigIntConstructorTest" { - -} -class "BigIntConversionsTest" { - -} -class "BigIntOperationsTest" { - -} -class "DoubleFieldTest" { - -} -class "NDFieldTest" { - -} -class "NumberNDFieldTest" { - algebra - array1 - array2 -} -class "L2Norm" { - norm() -} -interface "AlgebraicVerifier" { - algebra: A -} -class "FieldVerifier" { - algebra: A - a: T - b: T - c: T - x: Number -} -class "RingVerifier" { - algebra: A - a: T - b: T - c: T - x: Number -} -class "SpaceVerifier" { - algebra: S - a: T - b: T - c: T - x: Number -} -class "JBigIntegerField" { - zero: BigInteger - one: BigIntegernumber() - add() - minus() - multiply() - unaryMinus() -} -abstract "JBigDecimalFieldBase" { - mathContext: MathContext -} -class "JBigDecimalField" { - mathContext: MathContext -} -"ColumnarData" <|--- XYColumnarData -"XYColumnarData" <|--- XYErrorColumnarData -"XYColumnarData" <|--- XYZColumnarData -"Domain" <|--- DoubleDomain -"DoubleDomain" <|--- HyperSquareDomain -"DoubleDomain" <|--- UnconstrainedDomain -"DoubleDomain" <|--- UnivariateDomain -"Expression" <|--- DifferentiableExpression -"DifferentiableExpression" <|--- SpecialDifferentiableExpression -"DifferentiableExpression" <|--- FirstDerivativeExpression -"Algebra" <|--- ExpressionAlgebra -"ExpressionAlgebra" <|--- FunctionalExpressionAlgebra -"FunctionalExpressionAlgebra" <|--- FunctionalExpressionGroup -"Group" <|--- FunctionalExpressionGroup -"FunctionalExpressionGroup" <|--- FunctionalExpressionRing -"Ring" <|--- FunctionalExpressionRing -"FunctionalExpressionRing" <|--- FunctionalExpressionField -"Field" <|--- FunctionalExpressionField -"ScaleOperations" <|--- FunctionalExpressionField -"FunctionalExpressionField" <|--- FunctionalExpressionExtendedField -"ExtendedField" <|--- FunctionalExpressionExtendedField -"MST" <|--- Numeric -"MST" <|--- Unary -"MST" <|--- Binary -"NumericAlgebra" <|--- InnerAlgebra -"NumericAlgebra" <|--- MstNumericAlgebra -"Group" <|--- MstGroup -"NumericAlgebra" <|--- MstGroup -"ScaleOperations" <|--- MstGroup -"Ring" <|--- MstRing -"NumbersAddOperations" <|--- MstRing -"ScaleOperations" <|--- MstRing -"Field" <|--- MstField -"NumbersAddOperations" <|--- MstField -"ScaleOperations" <|--- MstField -"ExtendedField" <|--- MstExtendedField -"NumericAlgebra" <|--- MstExtendedField -"LogicAlgebra" <|--- MstLogicAlgebra -"Field" <|--- SimpleAutoDiffField -"ExpressionAlgebra" <|--- SimpleAutoDiffField -"NumbersAddOperations" <|--- SimpleAutoDiffField -"AutoDiffValue" <|--- AutoDiffVariableWithDerivative -"Symbol" <|--- AutoDiffVariableWithDerivative -"FirstDerivativeExpression" <|--- SimpleAutoDiffExpression -"ExtendedField" <|--- SimpleAutoDiffExtendedField -"ScaleOperations" <|--- SimpleAutoDiffExtendedField -'"" <|--- SimpleAutoDiffExtendedField -"SimpleAutoDiffField" <|--- SimpleAutoDiffExtendedField -"MST" <|--- Symbol -"Symbol" <|--- StringSymbol -"SymbolIndexer" <|--- SimpleSymbolIndexer -"LinearSpace" <|--- BufferedLinearSpace -"LupDecompositionFeature" <|--- LupDecomposition -"DeterminantFeature" <|--- LupDecomposition -"MatrixFeature" <|--- SymmetricMatrixFeature -"StructureFeature" <|--- MatrixFeature -"MatrixFeature" <|--- DiagonalFeature -"DiagonalFeature" <|--- ZeroFeature -"DiagonalFeature" <|--- UnitFeature -"MatrixFeature" <|--- InverseMatrixFeature -"MatrixFeature" <|--- DeterminantFeature -"MatrixFeature" <|--- LFeature -"MatrixFeature" <|--- UFeature -"MatrixFeature" <|--- LUDecompositionFeature -"MatrixFeature" <|--- LupDecompositionFeature -"MatrixFeature" <|--- OrthogonalFeature -"MatrixFeature" <|--- QRDecompositionFeature -"MatrixFeature" <|--- CholeskyDecompositionFeature -"MatrixFeature" <|--- SingularValueDecompositionFeature -'"Matrixbyorigin{ -' -' -' @UnstableKMathAPI -' @Suppress -'overridefungetFeature:F? = -'features.getFeature -' -'overridefuntoString" -'}" <|--- MatrixWrapper -"MatrixFeature" <|--- TransposedFeature -"Matrix" <|--- VirtualMatrix -"Featured" <|--- FeatureSet -"RuntimeException" <|--- ShapeMismatchException -"Group" <|--- GroupND -"AlgebraND" <|--- GroupND -"Ring" <|--- RingND -"GroupND" <|--- RingND -"Field" <|--- FieldND -"RingND" <|--- FieldND -"AlgebraND" <|--- BufferAlgebraND -"GroupND" <|--- BufferedGroupND -"BufferAlgebraND" <|--- BufferedGroupND -"BufferedGroupND" <|--- BufferedRingND -"RingND" <|--- BufferedRingND -"BufferedRingND" <|--- BufferedFieldND -"FieldND" <|--- BufferedFieldND -"StructureND" <|--- BufferND -"MutableStructureND" <|--- MutableBufferND -"BufferND" <|--- MutableBufferND -"BufferedFieldND" <|--- DoubleFieldND -'" -'" <|--- DoubleFieldND -'"NumbersAddOperations" <|--- DoubleFieldND -'" -'" <|--- DoubleFieldND -'"ScaleOperations" <|--- DoubleFieldND -'" -'" <|--- DoubleFieldND -"ExtendedField" <|--- DoubleFieldND -"BufferedRingND" <|--- ShortRingND -'" -'" <|--- ShortRingND -"NumbersAddOperations" <|--- ShortRingND -"StructureND" <|--- Structure1D -"Buffer" <|--- Structure1D -"Structure1D" <|--- MutableStructure1D -"MutableStructureND" <|--- MutableStructure1D -"MutableBuffer" <|--- MutableStructure1D -"Structure1D" <|--- Structure1DWrapper -"MutableStructure1D" <|--- MutableStructure1DWrapper -"Structure1D" <|--- Buffer1DWrapper -"MutableStructure1D" <|--- MutableBuffer1DWrapper -"StructureND" <|--- Structure2D -"Structure2D" <|--- MutableStructure2D -"MutableStructureND" <|--- MutableStructure2D -"Structure2D" <|--- Structure2DWrapper -"MutableStructure2D" <|--- MutableStructure2DWrapper -"Feature" <|--- StructureFeature -"Featured" <|--- StructureND -"StructureND" <|--- MutableStructureND -"Strides" <|--- DefaultStrides -"Algebra" <|--- GroupOperations -"GroupOperations" <|--- Group -"GroupOperations" <|--- RingOperations -"Group" <|--- Ring -"RingOperations" <|--- Ring -"RingOperations" <|--- FieldOperations -"Ring" <|--- Field -"FieldOperations" <|--- Field -"ScaleOperations" <|--- Field -"NumericAlgebra" <|--- Field -"AlgebraElement" <|--- GroupElement -"GroupElement" <|--- RingElement -"RingElement" <|--- FieldElement -"Field" <|--- BigIntField -"NumbersAddOperations" <|--- BigIntField -"ScaleOperations" <|--- BigIntField -"Comparable" <|--- BigInt -"Algebra" <|--- BufferAlgebra -"BufferAlgebra" <|--- BufferField -"Field" <|--- BufferField -"Algebra" <|--- LogicAlgebra -"LogicAlgebra" <|--- BooleanAlgebra -"FieldOperations" <|--- ExtendedFieldOperations -'" -'" <|--- ExtendedFieldOperations -'"TrigonometricOperations" <|--- ExtendedFieldOperations -'" -'" <|--- ExtendedFieldOperations -'"PowerOperations" <|--- ExtendedFieldOperations -'" -'" <|--- ExtendedFieldOperations -"ExponentialOperations" <|--- ExtendedFieldOperations -"ExtendedFieldOperations" <|--- ExtendedField -"Field" <|--- ExtendedField -"NumericAlgebra" <|--- ExtendedField -"ScaleOperations" <|--- ExtendedField -"ExtendedField" <|--- DoubleField -"Norm" <|--- DoubleField -"ScaleOperations" <|--- DoubleField -"ExtendedField" <|--- FloatField -"Norm" <|--- FloatField -"Ring" <|--- IntRing -"Norm" <|--- IntRing -"NumericAlgebra" <|--- IntRing -"Ring" <|--- ShortRing -"Norm" <|--- ShortRing -"NumericAlgebra" <|--- ShortRing -"Ring" <|--- ByteRing -"Norm" <|--- ByteRing -"NumericAlgebra" <|--- ByteRing -"Ring" <|--- LongRing -"Norm" <|--- LongRing -"NumericAlgebra" <|--- LongRing -"Algebra" <|--- NumericAlgebra -"Algebra" <|--- ScaleOperations -"Ring" <|--- NumbersAddOperations -"NumericAlgebra" <|--- NumbersAddOperations -"Algebra" <|--- TrigonometricOperations -"Algebra" <|--- PowerOperations -"Algebra" <|--- ExponentialOperations -"Buffer" <|--- MutableBuffer -"Buffer" <|--- ListBuffer -"MutableBuffer" <|--- MutableListBuffer -"MutableBuffer" <|--- ArrayBuffer -"Buffer" <|--- ReadOnlyBuffer -"Buffer" <|--- VirtualBuffer -"MutableBuffer" <|--- Row -"MutableBuffer" <|--- DoubleBuffer -"ExtendedFieldOperations" <|--- DoubleBufferFieldOperations -"Norm" <|--- DoubleL2Norm -"ExtendedField" <|--- DoubleBufferField -"Norm" <|--- DoubleBufferField -"Buffer" <|--- FlaggedBuffer -"FlaggedBuffer" <|--- FlaggedDoubleBuffer -'" -'" <|--- FlaggedDoubleBuffer -"Buffer" <|--- FlaggedDoubleBuffer -"MutableBuffer" <|--- FloatBuffer -"MutableBuffer" <|--- IntBuffer -"MutableBuffer" <|--- LongBuffer -"Buffer" <|--- MemoryBuffer -"MemoryBuffer" <|--- MutableMemoryBuffer -'" -'" <|--- MutableMemoryBuffer -"MutableBuffer" <|--- MutableMemoryBuffer -"MutableBuffer" <|--- ShortBuffer -"Norm" <|--- L2Norm -"RingVerifier" <|--- FieldVerifier -"SpaceVerifier" <|--- RingVerifier -"AlgebraicVerifier" <|--- SpaceVerifier -"Ring" <|--- JBigIntegerField -"NumericAlgebra" <|--- JBigIntegerField -"Field" <|--- JBigDecimalFieldBase -"PowerOperations" <|--- JBigDecimalFieldBase -"NumericAlgebra" <|--- JBigDecimalFieldBase -"ScaleOperations" <|--- JBigDecimalFieldBase -"JBigDecimalFieldBase" <|--- JBigDecimalField -@enduml \ No newline at end of file diff --git a/docs/images/KM.svg b/docs/images/KM.svg index 6f80e4d08..f5ec452c7 100644 --- a/docs/images/KM.svg +++ b/docs/images/KM.svg @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + ## Modules -${modules} +$modules ## Multi-platform support diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index d4e1c5289..000000000 --- a/examples/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Module examples - - - diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index 60f8f5aed..22e71ad46 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -5,7 +5,12 @@ plugins { repositories { mavenCentral() maven("https://repo.kotlin.link") + maven("https://clojars.org/repo") + maven("https://jitpack.io") maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-js-wrappers") + maven("http://logicrunch.research.it.uu.se/maven") { + isAllowInsecureProtocol = true + } } dependencies { @@ -15,7 +20,6 @@ dependencies { implementation(project(":kmath-coroutines")) implementation(project(":kmath-commons")) implementation(project(":kmath-complex")) - implementation(project(":kmath-optimization")) implementation(project(":kmath-stat")) implementation(project(":kmath-viktor")) implementation(project(":kmath-dimensions")) @@ -23,12 +27,8 @@ dependencies { implementation(project(":kmath-nd4j")) implementation(project(":kmath-tensors")) implementation(project(":kmath-symja")) + implementation(project(":kmath-units")) implementation(project(":kmath-for-real")) - //jafama - implementation(project(":kmath-jafama")) - //multik - implementation(project(":kmath-multik")) - implementation("org.nd4j:nd4j-native:1.0.0-beta7") @@ -42,26 +42,26 @@ dependencies { // } else implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") - // multik implementation - implementation("org.jetbrains.kotlinx:multik-default:0.1.0") - - implementation("org.slf4j:slf4j-simple:1.7.32") + implementation("org.slf4j:slf4j-simple:1.7.31") // plotting - implementation("space.kscience:plotlykt-server:0.5.0") + implementation("space.kscience:plotlykt-server:0.4.2") + //jafama + implementation(project(":kmath-jafama")) } kotlin.sourceSets.all { with(languageSettings) { - optIn("kotlin.contracts.ExperimentalContracts") - optIn("kotlin.ExperimentalUnsignedTypes") - optIn("space.kscience.kmath.misc.UnstableKMathAPI") + useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") + useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") + useExperimentalAnnotation("kotlin.time.ExperimentalTime") + useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") } } -tasks.withType { +tasks.withType { kotlinOptions { jvmTarget = "11" - freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" + "-Xlambdas=indy" + freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" } } diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt index c4f263f97..0c16d82d1 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt index 907f1bbe4..887d76c42 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt @@ -1,26 +1,22 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast -import space.kscience.kmath.asm.compileToExpression -import space.kscience.kmath.expressions.MstExtendedField +import space.kscience.kmath.expressions.MstField import space.kscience.kmath.expressions.Symbol.Companion.x +import space.kscience.kmath.expressions.interpret import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke fun main() { - val expr = MstExtendedField { - x * 2.0 + number(2.0) / x - number(16.0) + asinh(x) / sin(x) - }.compileToExpression(DoubleField) - - val m = DoubleArray(expr.indexer.symbols.size) - val xIdx = expr.indexer.indexOf(x) + val expr = MstField { + x * 2.0 + number(2.0) / x - 16.0 + } repeat(10000000) { - m[xIdx] = 1.0 - expr(m) + expr.interpret(DoubleField, x to 1.0) } -} +} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt index dec3bfb81..4e3528b3e 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt index 7e09faeff..209523c89 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt similarity index 71% rename from examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt rename to examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt index 63e57bd8c..406cbd040 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/chiSquared.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt @@ -1,27 +1,24 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ -package space.kscience.kmath.fit +package space.kscience.kmath.commons.fit import kotlinx.html.br import kotlinx.html.h3 -import space.kscience.kmath.commons.expressions.DSProcessor -import space.kscience.kmath.commons.optimization.CMOptimizer +import space.kscience.kmath.commons.optimization.chiSquared +import space.kscience.kmath.commons.optimization.minimize import space.kscience.kmath.distributions.NormalDistribution -import space.kscience.kmath.expressions.chiSquaredExpression import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.operations.asIterable -import space.kscience.kmath.operations.toList -import space.kscience.kmath.optimization.FunctionOptimizationTarget -import space.kscience.kmath.optimization.optimizeWith -import space.kscience.kmath.optimization.resultPoint -import space.kscience.kmath.optimization.resultValue +import space.kscience.kmath.optimization.FunctionOptimization +import space.kscience.kmath.optimization.OptimizationResult import space.kscience.kmath.real.DoubleVector import space.kscience.kmath.real.map import space.kscience.kmath.real.step import space.kscience.kmath.stat.RandomGenerator +import space.kscience.kmath.structures.asIterable +import space.kscience.kmath.structures.toList import space.kscience.plotly.* import space.kscience.plotly.models.ScatterMode import space.kscience.plotly.models.TraceValues @@ -45,7 +42,7 @@ operator fun TraceValues.invoke(vector: DoubleVector) { */ suspend fun main() { //A generator for a normally distributed values - val generator = NormalDistribution(0.0, 1.0) + val generator = NormalDistribution(2.0, 7.0) //A chain/flow of random values with the given seed val chain = generator.sample(RandomGenerator.default(112667)) @@ -56,7 +53,7 @@ suspend fun main() { //Perform an operation on each x value (much more effective, than numpy) - val y = x.map { it -> + val y = x.map { val value = it.pow(2) + it + 1 value + chain.next() * sqrt(value) } @@ -67,21 +64,17 @@ 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 = DSProcessor.chiSquaredExpression(x, y, yErr) { arg -> + val chi2 = FunctionOptimization.chiSquared(x, y, yErr) { x1 -> //bind variables to autodiff context val a = bindSymbol(a) val b = bindSymbol(b) //Include default value for c if it is not provided as a parameter val c = bindSymbolOrNull(c) ?: one - a * arg.pow(2) + b * arg + c + a * x1.pow(2) + b * x1 + c } //minimize the chi^2 in given starting point. Derivatives are not required, they are already included. - val result = chi2.optimizeWith( - CMOptimizer, - mapOf(a to 1.5, b to 0.9, c to 1.0), - FunctionOptimizationTarget.MINIMIZE - ) + val result: OptimizationResult = chi2.minimize(a to 1.5, b to 0.9, c to 1.0) //display a page with plot and numerical results val page = Plotly.page { @@ -98,7 +91,7 @@ suspend fun main() { scatter { mode = ScatterMode.lines x(x) - y(x.map { result.resultPoint[a]!! * it.pow(2) + result.resultPoint[b]!! * it + 1 }) + y(x.map { result.point[a]!! * it.pow(2) + result.point[b]!! * it + 1 }) name = "fit" } } @@ -107,7 +100,7 @@ suspend fun main() { +"Fit result: $result" } h3 { - +"Chi2/dof = ${result.resultValue / (x.size - 3)}" + +"Chi2/dof = ${result.value / (x.size - 3)}" } } diff --git a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt b/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt deleted file mode 100644 index d52976671..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/fit/qowFit.kt +++ /dev/null @@ -1,106 +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.fit - -import kotlinx.html.br -import kotlinx.html.h3 -import space.kscience.kmath.commons.expressions.DSProcessor -import space.kscience.kmath.data.XYErrorColumnarData -import space.kscience.kmath.distributions.NormalDistribution -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.binding -import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.operations.asIterable -import space.kscience.kmath.operations.toList -import space.kscience.kmath.optimization.QowOptimizer -import space.kscience.kmath.optimization.chiSquaredOrNull -import space.kscience.kmath.optimization.fitWith -import space.kscience.kmath.optimization.resultPoint -import space.kscience.kmath.real.map -import space.kscience.kmath.real.step -import space.kscience.kmath.stat.RandomGenerator -import space.kscience.plotly.* -import space.kscience.plotly.models.ScatterMode -import kotlin.math.abs -import kotlin.math.pow -import kotlin.math.sqrt - -// Forward declaration of symbols that will be used in expressions. -private val a by symbol -private val b by symbol -private val c by symbol - - -/** - * Least squares fie with auto-differentiation. Uses `kmath-commons` and `kmath-for-real` modules. - */ -suspend fun main() { - //A generator for a normally distributed values - val generator = NormalDistribution(0.0, 1.0) - - //A chain/flow of random values with the given seed - val chain = generator.sample(RandomGenerator.default(112667)) - - - //Create a uniformly distributed x values like numpy.arrange - val x = 1.0..100.0 step 1.0 - - - //Perform an operation on each x value (much more effective, than numpy) - val y = x.map { it -> - val value = it.pow(2) + it + 1 - value + chain.next() * sqrt(value) - } - // this will also work, but less effective: - // val y = x.pow(2)+ x + 1 + chain.nextDouble() - - // create same errors for all xs - val yErr = y.map { sqrt(abs(it)) } - require(yErr.asIterable().all { it > 0 }) { "All errors must be strictly positive" } - - val result = XYErrorColumnarData.of(x, y, yErr).fitWith( - QowOptimizer, - DSProcessor, - mapOf(a to 0.9, b to 1.2, c to 2.0) - ) { arg -> - //bind variables to autodiff context - val a by binding - val b by binding - //Include default value for c if it is not provided as a parameter - val c = bindSymbolOrNull(c) ?: one - a * arg.pow(2) + b * arg + c - } - - //display a page with plot and numerical results - val page = Plotly.page { - plot { - scatter { - mode = ScatterMode.markers - x(x) - y(y) - error_y { - array = yErr.toList() - } - name = "data" - } - scatter { - mode = ScatterMode.lines - x(x) - y(x.map { result.model(result.resultPoint + (Symbol.x to it)) }) - name = "fit" - } - } - br() - h3 { - +"Fit result: ${result.resultPoint}" - } - h3 { - +"Chi2/dof = ${result.chiSquaredOrNull!! / (x.size - 3)}" - } - } - - page.makeFile() -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt index f60b1ab45..c77d1d70c 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.functions diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt index 8dbc7b7a4..a98467ced 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.functions diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt index feefedece..76422d658 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt @@ -1,15 +1,15 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.functions +import space.kscience.kmath.interpolation.SplineInterpolator import space.kscience.kmath.interpolation.interpolatePolynomials -import space.kscience.kmath.interpolation.splineInterpolator import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.real.map import space.kscience.kmath.real.step +import space.kscience.kmath.structures.map import space.kscience.plotly.Plotly import space.kscience.plotly.UnstablePlotlyAPI import space.kscience.plotly.makeFile @@ -28,7 +28,7 @@ fun main() { val xs = 0.0..100.0 step 0.5 val ys = xs.map(function) - val polynomial: PiecewisePolynomial = DoubleField.splineInterpolator.interpolatePolynomials(xs, ys) + val polynomial: PiecewisePolynomial = SplineInterpolator.double.interpolatePolynomials(xs, ys) val polyFunction = polynomial.asFunction(DoubleField, 0.0) diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt index 4f99aeb47..5af867061 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.functions @@ -9,21 +9,20 @@ import space.kscience.kmath.integration.gaussIntegrator import space.kscience.kmath.integration.integrate import space.kscience.kmath.integration.value import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.structureND -import space.kscience.kmath.nd.withNdAlgebra -import space.kscience.kmath.operations.algebra +import space.kscience.kmath.nd.nd +import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke -fun main(): Unit = Double.algebra { - withNdAlgebra(2, 2) { +fun main(): Unit = DoubleField { + nd(2, 2) { //Produce a diagonal StructureND - fun diagonal(v: Double) = structureND { (i, j) -> + fun diagonal(v: Double) = produce { (i, j) -> if (i == j) v else 0.0 } //Define a function in a nd space - val function: (Double) -> StructureND = { x: Double -> 3 * x.pow(2) + 2 * diagonal(x) + 1 } + val function: (Double) -> StructureND = { x: Double -> 3 * number(x).pow(2) + 2 * diagonal(x) + 1 } //get the result of the integration val result = gaussIntegrator.integrate(0.0..10.0, function = function) diff --git a/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt index 9c3d0fdbe..10ed30728 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.jafama diff --git a/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt b/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt deleted file mode 100644 index a2d7d7c27..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/linear/dotPerformance.kt +++ /dev/null @@ -1,34 +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.linear - -import space.kscience.kmath.operations.algebra -import kotlin.random.Random -import kotlin.system.measureTimeMillis - -fun main() { - val random = Random(12224) - val dim = 1000 - - //creating invertible matrix - val matrix1 = Double.algebra.linearSpace.buildMatrix(dim, dim) { i, j -> - if (i <= j) random.nextDouble() else 0.0 - } - val matrix2 = Double.algebra.linearSpace.buildMatrix(dim, dim) { i, j -> - if (i <= j) random.nextDouble() else 0.0 - } - - val time = measureTimeMillis { - with(Double.algebra.linearSpace) { - repeat(10) { - matrix1 dot matrix2 - } - } - } - - println(time) - -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt index a01ea7fe2..afc42ea26 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.linear diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt index 51f439612..2039953b5 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.operations diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt new file mode 100644 index 000000000..eefc6e896 --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt @@ -0,0 +1,29 @@ +/* + * 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 file. + */ + +package space.kscience.kmath.operations + +import space.kscience.kmath.complex.Complex +import space.kscience.kmath.complex.complex +import space.kscience.kmath.nd.AlgebraND + +fun main() { + // 2d element + val element = AlgebraND.complex(2, 2).produce { (i, j) -> + Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble()) + } + println(element) + + // 1d element operation + val result = with(AlgebraND.complex(8)) { + val a = produce { (it) -> i * it - it.toDouble() } + val b = 3 + val c = Complex(1.0, 1.0) + + (a pow b) + c + } + + println(result) +} diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt deleted file mode 100644 index 2e1801cc2..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/complexDemo.kt +++ /dev/null @@ -1,41 +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.operations - -import space.kscience.kmath.complex.Complex -import space.kscience.kmath.complex.algebra -import space.kscience.kmath.complex.bufferAlgebra -import space.kscience.kmath.complex.ndAlgebra -import space.kscience.kmath.nd.BufferND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.structureND - -fun main() = Complex.algebra { - val complex = 2 + 2 * i - println(complex * 8 - 5 * i) - - //flat buffer - val buffer = with(bufferAlgebra){ - buffer(8) { Complex(it, -it) }.map { Complex(it.im, it.re) } - } - println(buffer) - - // 2d element - val element: BufferND = ndAlgebra.structureND(2, 2) { (i, j) -> - Complex(i - j, i + j) - } - println(element) - - // 1d element operation - val result: StructureND = ndAlgebra{ - val a = structureND(8) { (it) -> i * it - it.toDouble() } - val b = 3 - val c = Complex(1.0, 1.0) - - (a pow b) + c - } - println(result) -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt deleted file mode 100644 index 62c9c8076..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/mixedNDOperations.kt +++ /dev/null @@ -1,29 +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.operations - -import space.kscience.kmath.commons.linear.CMLinearSpace -import space.kscience.kmath.linear.matrix -import space.kscience.kmath.nd.DoubleBufferND -import space.kscience.kmath.nd.Shape -import space.kscience.kmath.nd.Structure2D -import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.viktor.ViktorStructureND -import space.kscience.kmath.viktor.viktorAlgebra - -fun main() { - val viktorStructure: ViktorStructureND = DoubleField.viktorAlgebra.structureND(Shape(2, 2)) { (i, j) -> - if (i == j) 2.0 else 0.0 - } - - val cmMatrix: Structure2D = CMLinearSpace.matrix(2, 2)(0.0, 1.0, 0.0, 3.0) - - val res: DoubleBufferND = DoubleField.ndAlgebra { - exp(viktorStructure) + 2.0 * cmMatrix - } - - println(res) -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt index 8e3cdf86f..732c9a8e3 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt index 15654971f..685214c39 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt @@ -1,13 +1,13 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat import kotlinx.coroutines.runBlocking import space.kscience.kmath.chains.Chain -import space.kscience.kmath.chains.combineWithState +import space.kscience.kmath.chains.collectWithState import space.kscience.kmath.distributions.NormalDistribution private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0) @@ -15,11 +15,11 @@ private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0 /** * Averaging. */ -private fun Chain.mean(): Chain = combineWithState(AveragingChainState(), { it.copy() }) { chain -> +private fun Chain.mean(): Chain = collectWithState(AveragingChainState(), { it.copy() }) { chain -> val next = chain.next() num++ value += next - return@combineWithState value / num + return@collectWithState value / num } diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt index d55f3df09..752e00bdf 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ @file:Suppress("unused") @@ -9,11 +9,10 @@ package space.kscience.kmath.structures import space.kscience.kmath.complex.* import space.kscience.kmath.linear.transpose +import space.kscience.kmath.nd.AlgebraND import space.kscience.kmath.nd.StructureND import space.kscience.kmath.nd.as2D -import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.nd.structureND -import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.nd.real import space.kscience.kmath.operations.invoke import kotlin.system.measureTimeMillis @@ -21,8 +20,8 @@ fun main() { val dim = 1000 val n = 1000 - val realField = DoubleField.ndAlgebra(dim, dim) - val complexField: ComplexFieldND = ComplexField.ndAlgebra(dim, dim) + val realField = AlgebraND.real(dim, dim) + val complexField: ComplexFieldND = AlgebraND.complex(dim, dim) val realTime = measureTimeMillis { realField { @@ -50,12 +49,12 @@ fun main() { fun complexExample() { //Create a context for 2-d structure with complex values ComplexField { - withNdAlgebra(4, 8) { + nd(4, 8) { //a constant real-valued structure val x = one * 2.5 operator fun Number.plus(other: Complex) = Complex(this.toDouble() + other.re, other.im) //a structure generator specific to this context - val matrix = structureND { (k, l) -> k + l * i } + val matrix = produce { (k, l) -> k + l * i } //Perform sum val sum = matrix + x + 1.0 diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt index b680e267d..c842960be 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures @@ -9,10 +9,10 @@ import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import org.nd4j.linalg.factory.Nd4j import space.kscience.kmath.nd.* -import space.kscience.kmath.nd4j.nd4j +import space.kscience.kmath.nd4j.Nd4jArrayField import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.invoke -import space.kscience.kmath.viktor.ViktorFieldND +import space.kscience.kmath.viktor.ViktorNDField import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.system.measureTimeMillis @@ -29,39 +29,37 @@ fun main() { Nd4j.zeros(0) val dim = 1000 val n = 1000 - val shape = Shape(dim, dim) - // automatically build context most suited for given type. - val autoField = BufferedFieldOpsND(DoubleField, Buffer.Companion::auto) + val autoField = AlgebraND.auto(DoubleField, dim, dim) // specialized nd-field for Double. It works as generic Double field as well. - val realField = DoubleField.ndAlgebra + val realField = AlgebraND.real(dim, dim) //A generic boxing field. It should be used for objects, not primitives. - val boxingField = BufferedFieldOpsND(DoubleField, Buffer.Companion::boxing) + val boxingField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim) // Nd4j specialized field. - val nd4jField = DoubleField.nd4j + val nd4jField = Nd4jArrayField.real(dim, dim) //viktor field - val viktorField = ViktorFieldND(dim, dim) + val viktorField = ViktorNDField(dim, dim) //parallel processing based on Java Streams - val parallelField = DoubleField.ndStreaming(dim, dim) + val parallelField = AlgebraND.realWithStream(dim, dim) measureAndPrint("Boxing addition") { boxingField { - var res: StructureND = one(shape) + var res: StructureND = one repeat(n) { res += 1.0 } } } measureAndPrint("Specialized addition") { realField { - var res: StructureND = one(shape) + var res: StructureND = one repeat(n) { res += 1.0 } } } measureAndPrint("Nd4j specialized addition") { nd4jField { - var res: StructureND = one(shape) + var res: StructureND = one repeat(n) { res += 1.0 } } } @@ -82,13 +80,13 @@ fun main() { measureAndPrint("Automatic field addition") { autoField { - var res: StructureND = one(shape) + var res: StructureND = one repeat(n) { res += 1.0 } } } measureAndPrint("Lazy addition") { - val res = realField.one(shape).mapAsync(GlobalScope) { + val res = realField.one.mapAsync(GlobalScope) { var c = 0.0 repeat(n) { c += 1.0 diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt index 548fb16c1..e443a588d 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures @@ -8,7 +8,7 @@ package space.kscience.kmath.structures import space.kscience.kmath.nd.* import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.NumbersAddOps +import space.kscience.kmath.operations.NumbersAddOperations import java.util.* import java.util.stream.IntStream @@ -17,17 +17,17 @@ import java.util.stream.IntStream * execution. */ class StreamDoubleFieldND(override val shape: IntArray) : FieldND, - NumbersAddOps>, + NumbersAddOperations>, ExtendedField> { private val strides = DefaultStrides(shape) - override val elementAlgebra: DoubleField get() = DoubleField - override val zero: BufferND by lazy { structureND(shape) { zero } } - override val one: BufferND by lazy { structureND(shape) { one } } + override val elementContext: DoubleField get() = DoubleField + override val zero: BufferND by lazy { produce { zero } } + override val one: BufferND by lazy { produce { one } } override fun number(value: Number): BufferND { val d = value.toDouble() // minimize conversions - return structureND(shape) { d } + return produce { d } } private val StructureND.buffer: DoubleBuffer @@ -36,11 +36,11 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND this.buffer as DoubleBuffer + this is BufferND && this.strides == this@StreamDoubleFieldND.strides -> this.buffer as DoubleBuffer else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) } } - override fun structureND(shape: Shape, initializer: DoubleField.(IntArray) -> Double): BufferND { + override fun produce(initializer: DoubleField.(IntArray) -> Double): BufferND { val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset -> val index = strides.index(offset) DoubleField.initializer(index) @@ -69,13 +69,13 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND, - right: StructureND, + override fun combine( + a: StructureND, + b: StructureND, transform: DoubleField.(Double, Double) -> Double, ): BufferND { val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset -> - DoubleField.transform(left.buffer.array[offset], right.buffer.array[offset]) + DoubleField.transform(a.buffer.array[offset], b.buffer.array[offset]) }.toArray() return BufferND(strides, array.asBuffer()) } @@ -105,4 +105,4 @@ class StreamDoubleFieldND(override val shape: IntArray) : FieldND): BufferND = arg.map { atanh(it) } } -fun DoubleField.ndStreaming(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(shape) +fun AlgebraND.Companion.realWithStream(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(shape) diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt index de36c664d..84dd6538c 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures @@ -19,24 +19,24 @@ fun main() { measureTimeMillis { var res = 0.0 - strides.asSequence().forEach { res = structure[it] } + strides.indices().forEach { res = structure[it] } } // warmup val time1 = measureTimeMillis { var res = 0.0 - strides.asSequence().forEach { res = structure[it] } + strides.indices().forEach { res = structure[it] } } println("Structure reading finished in $time1 millis") val time2 = measureTimeMillis { var res = 0.0 - strides.asSequence().forEach { res = buffer[strides.offset(it)] } + strides.indices().forEach { res = buffer[strides.offset(it)] } } println("Buffer reading finished in $time2 millis") val time3 = measureTimeMillis { var res = 0.0 - strides.asSequence().forEach { res = array[strides.offset(it)] } + strides.indices().forEach { res = array[strides.offset(it)] } } println("Array reading finished in $time3 millis") } diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt index dea7095a8..84644ddd9 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt deleted file mode 100644 index 889ea99bd..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/buffers.kt +++ /dev/null @@ -1,23 +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.structures - -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.buffer -import space.kscience.kmath.operations.bufferAlgebra -import space.kscience.kmath.operations.withSize - -inline fun MutableBuffer.Companion.same( - n: Int, - value: R -): MutableBuffer = auto(n) { value } - - -fun main() { - with(DoubleField.bufferAlgebra.withSize(5)) { - println(number(2.0) + buffer(1, 2, 3, 4, 5)) - } -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt index c28b566b9..853ebad32 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt similarity index 81% rename from examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt rename to examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt index a436ae1c3..3ef745da3 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/dataSetNormalization.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt @@ -1,17 +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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors -import space.kscience.kmath.tensors.core.tensorAlgebra -import space.kscience.kmath.tensors.core.withBroadcast +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra // Dataset normalization -fun main() = Double.tensorAlgebra.withBroadcast { // work in context with broadcast methods +fun main() = BroadcastDoubleTensorAlgebra { // work in context with broadcast methods // take dataset of 5-element vectors from normal distribution val dataset = randomNormal(intArrayOf(100, 5)) * 1.5 // all elements from N(0, 1.5) diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt similarity index 90% rename from examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt rename to examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt index f465fc424..27886413f 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/linearSystemSolvingWithLUP.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt @@ -1,17 +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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.tensorAlgebra -import space.kscience.kmath.tensors.core.withBroadcast // solving linear system with LUP decomposition -fun main() = Double.tensorAlgebra.withBroadcast {// work in context with linear operations +fun main() = BroadcastDoubleTensorAlgebra {// work in context with linear operations // 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 similarity index 96% rename from examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt rename to examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt index 5c41ab0f1..3025ff8a3 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/neuralNetwork.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors @@ -9,7 +9,7 @@ import space.kscience.kmath.operations.invoke import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.copyArray +import space.kscience.kmath.tensors.core.toDoubleArray import kotlin.math.sqrt const val seed = 100500L @@ -111,7 +111,7 @@ class NeuralNetwork(private val layers: List) { private fun softMaxLoss(yPred: DoubleTensor, yTrue: DoubleTensor): DoubleTensor = BroadcastDoubleTensorAlgebra { val onesForAnswers = yPred.zeroesLike() - yTrue.copyArray().forEachIndexed { index, labelDouble -> + yTrue.toDoubleArray().forEachIndexed { index, labelDouble -> val label = labelDouble.toInt() onesForAnswers[intArrayOf(index, label)] = 1.0 } @@ -163,7 +163,7 @@ class NeuralNetwork(private val layers: List) { for ((xBatch, yBatch) in iterBatch(xTrain, yTrain)) { train(xBatch, yBatch) } - println("Accuracy:${accuracy(yTrain, predict(xTrain).argMax(1, true).asDouble())}") + println("Accuracy:${accuracy(yTrain, predict(xTrain).argMax(1, true))}") } } @@ -230,7 +230,7 @@ fun main() = BroadcastDoubleTensorAlgebra { val prediction = model.predict(xTest) // process raw prediction via argMax - val predictionLabels = prediction.argMax(1, true).asDouble() + val predictionLabels = prediction.argMax(1, true) // find out accuracy val acc = accuracy(yTest, predictionLabels) 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 b42602988..a266d4849 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors 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 aced0cf7d..3302b49a8 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt @@ -1,23 +1,23 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors -import space.kscience.kmath.tensors.core.tensorAlgebra -import space.kscience.kmath.tensors.core.withBroadcast +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra // simple PCA -fun main(): Unit = Double.tensorAlgebra.withBroadcast { // work in context with broadcast methods +fun main(): Unit = BroadcastDoubleTensorAlgebra { // work in context with broadcast methods val seed = 100500L // assume x is range from 0 until 10 val x = fromArray( intArrayOf(10), - DoubleArray(10) { it.toDouble() } + (0 until 10).toList().map { it.toDouble() }.toDoubleArray() ) // take y dependent on x with noise @@ -62,7 +62,7 @@ fun main(): Unit = Double.tensorAlgebra.withBroadcast { // work in context with println("Eigenvector:\n$v") // reduce dimension of dataset - val datasetReduced = v dot stack(listOf(xScaled, yScaled)) + val datasetReduced = v dot stack(listOf(xScaled, yScaled)) println("Reduced data:\n$datasetReduced") // we can restore original data from reduced data; diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt deleted file mode 100644 index f2d1f0b41..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/multik.kt +++ /dev/null @@ -1,18 +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 - -import org.jetbrains.kotlinx.multik.api.Multik -import org.jetbrains.kotlinx.multik.api.ndarray -import space.kscience.kmath.multik.multikAlgebra -import space.kscience.kmath.nd.one -import space.kscience.kmath.operations.DoubleField - -fun main(): Unit = with(DoubleField.multikAlgebra) { - val a = Multik.ndarray(intArrayOf(1, 2, 3)).asType().wrap() - val b = Multik.ndarray(doubleArrayOf(1.0, 2.0, 3.0)).wrap() - one(a.shape) - a + b * 3.0 -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/units/main.kt b/examples/src/main/kotlin/space/kscience/kmath/units/main.kt new file mode 100644 index 000000000..0aaeaf1cb --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/units/main.kt @@ -0,0 +1,37 @@ +/* + * 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.units + +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.units.* + +fun main() { + var res = with(DoubleField.measurement()) { + val a = (2.0 * kg) / (3.0 * m) / (2.0 * with(MeasureAlgebra) { s * s }) + val b = (23.0 * Pa) + a + b + } + + println(res) + + res = with(DoubleField.measurement()) { + val a = (2.0 * G(m)) + (3.0 * M(m)) + val b = (3.0 * au) + a + b + } + + println(res) + + res = with(DoubleField.measurement()) { + val P = 100000.0 * Pa + val V = 0.0227 * (m pow 3) + val nu = 1.0 * mol + val T = 273.0 * K + P * V / (nu * T) + } + + println(res) +} diff --git a/examples/src/main/kotlin/space/kscience/kmath/units/perf.kt b/examples/src/main/kotlin/space/kscience/kmath/units/perf.kt new file mode 100644 index 000000000..dcd3b335b --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/units/perf.kt @@ -0,0 +1,33 @@ +/* + * 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.units + +import space.kscience.kmath.operations.DoubleField +import kotlin.random.Random +import kotlin.time.measureTime + +fun main() { + var rng = Random(0) + var sum1 = 0.0 + + measureTime { + repeat(10000000) { sum1 += rng.nextDouble() } + }.also(::println) + + println(sum1) + + rng = Random(0) + + with(DoubleField.measurement()) { + var sum2 = 0.0 * Pa + + measureTime { + repeat(10000000) { sum2 += rng.nextDouble() * Pa } + }.also(::println) + + println(sum2) + } +} diff --git a/gradle.properties b/gradle.properties index a7cd2f876..b97db1c54 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,10 +2,11 @@ # 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. # + kotlin.code.style=official -kotlin.jupyter.add.scanner=false +kotlin.mpp.enableGranularSourceSetsMetadata=true kotlin.mpp.stability.nowarn=true -kotlin.native.ignoreDisabledTargets=true +kotlin.native.enableDependencyPropagation=false org.gradle.configureondemand=true -org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G +org.gradle.jvmargs=-XX:MaxMetaspaceSize=2G org.gradle.parallel=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927a4..7454180f2 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index aa991fcea..05679dc3c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c78733..744e882ed 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/bin/sh +#!/usr/bin/env sh # -# Copyright © 2015-2021 the original authors. +# Copyright 2015 the original author or authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,101 +17,67 @@ # ############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# +## +## Gradle start up script for UN*X +## ############################################################################## # Attempt to set APP_HOME - # Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} +APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum +MAX_FD="maximum" warn () { echo "$*" -} >&2 +} die () { echo echo "$*" echo exit 1 -} >&2 +} # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MSYS* | MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -121,9 +87,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java + JAVACMD="$JAVA_HOME/jre/sh/java" else - JAVACMD=$JAVA_HOME/bin/java + JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -132,7 +98,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD=java + JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -140,95 +106,80 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi fi -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi # For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=$( cygpath --unix "$JAVACMD" ) + JAVACMD=`cygpath --unix "$JAVACMD"` - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" exec "$JAVACMD" "$@" diff --git a/kmath-ast/README.md b/kmath-ast/README.md index 4872a3a26..686506f6f 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -1,6 +1,6 @@ # Module kmath-ast -Extensions to MST API: transformations, dynamic compilation and visualization. +Performance and visualization extensions to MST API. - [expression-language](src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser - [mst-jvm-codegen](src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler @@ -10,17 +10,17 @@ Extensions to MST API: transformations, dynamic compilation and visualization. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-20`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-14`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-ast:0.3.0-dev-20' + implementation 'space.kscience:kmath-ast:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -31,30 +31,10 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ast:0.3.0-dev-20") + implementation("space.kscience:kmath-ast:0.3.0-dev-14") } ``` -## Parsing expressions - -In this module there is a parser from human-readable strings like `"x^3-x+3"` (in the more specific [grammar](reference/ArithmeticsEvaluator.g4)) to MST instances. - -Supported literals: -1. Constants and variables (consist of latin letters, digits and underscores, can't start with digit): `x`, `_Abc2`. -2. Numbers: `123`, `1.02`, `1e10`, `1e-10`, `1.0e+3`—all parsed either as `kotlin.Long` or `kotlin.Double`. - -Supported binary operators (from the highest precedence to the lowest one): -1. `^` -2. `*`, `/` -3. `+`, `-` - -Supported unary operator: -1. `-`, e. g. `-x` - -Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't start with digit. Examples: -1. `sin(x)` -2. `add(x, y)` - ## Dynamic expression code generation ### On JVM @@ -62,66 +42,48 @@ Arbitrary unary and binary functions are also supported: names consist of latin `kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a special implementation of `Expression` with implemented `invoke` function. -For example, the following code: +For example, the following builder: ```kotlin -import space.kscience.kmath.asm.compileToExpression -import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.expressions.Symbol.Companion.x +import space.kscience.kmath.expressions.* +import space.kscience.kmath.operations.* +import space.kscience.kmath.asm.* -"x^3-x+3".parseMath().compileToExpression(DoubleField) -``` +MstField { x + 2 }.compileToExpression(DoubleField) +``` -… leads to generation of bytecode, which can be decompiled to the following Java class: +... leads to generation of bytecode, which can be decompiled to the following Java class: ```java -import java.util.*; -import kotlin.jvm.functions.*; -import space.kscience.kmath.asm.internal.*; -import space.kscience.kmath.complex.*; -import space.kscience.kmath.expressions.*; +package space.kscience.kmath.asm.generated; -public final class CompiledExpression_45045_0 implements Expression { +import java.util.Map; + +import kotlin.jvm.functions.Function2; +import space.kscience.kmath.asm.internal.MapIntrinsics; +import space.kscience.kmath.expressions.Expression; +import space.kscience.kmath.expressions.Symbol; + +public final class AsmCompiledExpression_45045_0 implements Expression { private final Object[] constants; - public Complex invoke(Map arguments) { - Complex var2 = (Complex)MapIntrinsics.getOrFail(arguments, "x"); - return (Complex)((Function2)this.constants[0]).invoke(var2, (Complex)this.constants[1]); - } -} -``` - -For `LongRing`, `IntRing`, and `DoubleField` specialization is supported for better performance: - -```java -import java.util.*; -import space.kscience.kmath.asm.internal.*; -import space.kscience.kmath.expressions.*; - -public final class CompiledExpression_-386104628_0 implements DoubleExpression { - private final SymbolIndexer indexer; - - public SymbolIndexer getIndexer() { - return this.indexer; - } - - public double invoke(double[] arguments) { - double var2 = arguments[0]; - return Math.pow(var2, 3.0D) - var2 + 3.0D; - } - public final Double invoke(Map arguments) { - double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue(); - return Math.pow(var2, 3.0D) - var2 + 3.0D; + return (Double) ((Function2) this.constants[0]).invoke((Double) MapIntrinsics.getOrFail(arguments, "x"), 2); + } + + public AsmCompiledExpression_45045_0(Object[] constants) { + this.constants = constants; } } + ``` -Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually. +#### Known issues -#### Limitations - -- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class loading overhead. -- This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not support class loaders. +- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class + loading overhead. +- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders. ### On JS @@ -159,15 +121,15 @@ MstField { x + 2 }.compileToExpression(DoubleField) An example of emitted Wasm IR in the form of WAT: ```lisp -(func \$executable (param \$0 f64) (result f64) +(func $executable (param $0 f64) (result f64) (f64.add - (local.get \$0) + (local.get $0) (f64.const 2) ) ) ``` -#### Limitations +#### Known issues - ESTree expression compilation uses `eval` which can be unavailable in several environments. - WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/). diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 15b1d0900..9de7e9980 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -20,7 +20,7 @@ kotlin.js { kotlin.sourceSets { filter { it.name.contains("test", true) } .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) - .forEach { it.optIn("space.kscience.kmath.misc.UnstableKMathAPI") } + .forEach { it.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") } commonMain { dependencies { @@ -55,11 +55,6 @@ tasks.dokkaHtml { dependsOn(tasks.build) } -if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1") - tasks.jvmTest { - jvmArgs = (jvmArgs ?: emptyList()) + listOf("-Dspace.kscience.kmath.ast.dump.generated.classes=1") - } - readme { maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) diff --git a/kmath-ast/docs/README-TEMPLATE.md b/kmath-ast/docs/README-TEMPLATE.md index e9e22f4d4..9494af63a 100644 --- a/kmath-ast/docs/README-TEMPLATE.md +++ b/kmath-ast/docs/README-TEMPLATE.md @@ -1,31 +1,11 @@ # Module kmath-ast -Extensions to MST API: transformations, dynamic compilation and visualization. +Performance and visualization extensions to MST API. ${features} ${artifact} -## Parsing expressions - -In this module there is a parser from human-readable strings like `"x^3-x+3"` (in the more specific [grammar](reference/ArithmeticsEvaluator.g4)) to MST instances. - -Supported literals: -1. Constants and variables (consist of latin letters, digits and underscores, can't start with digit): `x`, `_Abc2`. -2. Numbers: `123`, `1.02`, `1e10`, `1e-10`, `1.0e+3`—all parsed either as `kotlin.Long` or `kotlin.Double`. - -Supported binary operators (from the highest precedence to the lowest one): -1. `^` -2. `*`, `/` -3. `+`, `-` - -Supported unary operator: -1. `-`, e. g. `-x` - -Arbitrary unary and binary functions are also supported: names consist of latin letters, digits and underscores, can't start with digit. Examples: -1. `sin(x)` -2. `add(x, y)` - ## Dynamic expression code generation ### On JVM @@ -33,66 +13,48 @@ Arbitrary unary and binary functions are also supported: names consist of latin `kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a special implementation of `Expression` with implemented `invoke` function. -For example, the following code: +For example, the following builder: ```kotlin -import space.kscience.kmath.asm.compileToExpression -import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.expressions.Symbol.Companion.x +import space.kscience.kmath.expressions.* +import space.kscience.kmath.operations.* +import space.kscience.kmath.asm.* -"x^3-x+3".parseMath().compileToExpression(DoubleField) -``` +MstField { x + 2 }.compileToExpression(DoubleField) +``` -… leads to generation of bytecode, which can be decompiled to the following Java class: +... leads to generation of bytecode, which can be decompiled to the following Java class: ```java -import java.util.*; -import kotlin.jvm.functions.*; -import space.kscience.kmath.asm.internal.*; -import space.kscience.kmath.complex.*; -import space.kscience.kmath.expressions.*; +package space.kscience.kmath.asm.generated; -public final class CompiledExpression_45045_0 implements Expression { +import java.util.Map; + +import kotlin.jvm.functions.Function2; +import space.kscience.kmath.asm.internal.MapIntrinsics; +import space.kscience.kmath.expressions.Expression; +import space.kscience.kmath.expressions.Symbol; + +public final class AsmCompiledExpression_45045_0 implements Expression { private final Object[] constants; - public Complex invoke(Map arguments) { - Complex var2 = (Complex)MapIntrinsics.getOrFail(arguments, "x"); - return (Complex)((Function2)this.constants[0]).invoke(var2, (Complex)this.constants[1]); - } -} -``` - -For `LongRing`, `IntRing`, and `DoubleField` specialization is supported for better performance: - -```java -import java.util.*; -import space.kscience.kmath.asm.internal.*; -import space.kscience.kmath.expressions.*; - -public final class CompiledExpression_-386104628_0 implements DoubleExpression { - private final SymbolIndexer indexer; - - public SymbolIndexer getIndexer() { - return this.indexer; - } - - public double invoke(double[] arguments) { - double var2 = arguments[0]; - return Math.pow(var2, 3.0D) - var2 + 3.0D; - } - public final Double invoke(Map arguments) { - double var2 = ((Double)MapIntrinsics.getOrFail(arguments, "x")).doubleValue(); - return Math.pow(var2, 3.0D) - var2 + 3.0D; + return (Double) ((Function2) this.constants[0]).invoke((Double) MapIntrinsics.getOrFail(arguments, "x"), 2); + } + + public AsmCompiledExpression_45045_0(Object[] constants) { + this.constants = constants; } } + ``` -Setting JVM system property `space.kscience.kmath.ast.dump.generated.classes` to `1` makes the translator dump class files to program's working directory, so they can be reviewed manually. +#### Known issues -#### Limitations - -- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class loading overhead. -- This API is not supported by non-dynamic JVM implementations like TeaVM or GraalVM Native Image because they may not support class loaders. +- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class + loading overhead. +- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders. ### On JS @@ -138,7 +100,7 @@ An example of emitted Wasm IR in the form of WAT: ) ``` -#### Limitations +#### Known issues - ESTree expression compilation uses `eval` which can be unavailable in several environments. - WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/). diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt deleted file mode 100644 index 8a8b8797d..000000000 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/TypedMst.kt +++ /dev/null @@ -1,177 +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.ast - -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.NumericAlgebra - -/** - * MST form where all values belong to the type [T]. It is optimal for constant folding, dynamic compilation, etc. - * - * @param T the type. - */ -@UnstableKMathAPI -public sealed interface TypedMst { - /** - * A node containing a unary operation. - * - * @param T the type. - * @property operation The identifier of operation. - * @property function The function implementing this operation. - * @property value The argument of this operation. - */ - public class Unary(public val operation: String, public val function: (T) -> T, public val value: TypedMst) : - TypedMst { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - other as Unary<*> - if (operation != other.operation) return false - if (value != other.value) return false - return true - } - - override fun hashCode(): Int { - var result = operation.hashCode() - result = 31 * result + value.hashCode() - return result - } - - override fun toString(): String = "Unary(operation=$operation, value=$value)" - } - - /** - * A node containing binary operation. - * - * @param T the type. - * @property operation The identifier of operation. - * @property function The binary function implementing this operation. - * @property left The left operand. - * @property right The right operand. - */ - public class Binary( - public val operation: String, - public val function: Function, - public val left: TypedMst, - public val right: TypedMst, - ) : TypedMst { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as Binary<*> - - if (operation != other.operation) return false - if (left != other.left) return false - if (right != other.right) return false - - return true - } - - override fun hashCode(): Int { - var result = operation.hashCode() - result = 31 * result + left.hashCode() - result = 31 * result + right.hashCode() - return result - } - - override fun toString(): String = "Binary(operation=$operation, left=$left, right=$right)" - } - - /** - * The non-numeric constant value. - * - * @param T the type. - * @property value The held value. - * @property number The number this value corresponds. - */ - public class Constant(public val value: T, public val number: Number?) : TypedMst { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - other as Constant<*> - if (value != other.value) return false - if (number != other.number) return false - return true - } - - override fun hashCode(): Int { - var result = value?.hashCode() ?: 0 - result = 31 * result + (number?.hashCode() ?: 0) - return result - } - - override fun toString(): String = "Constant(value=$value, number=$number)" - } - - /** - * The node containing a variable - * - * @param T the type. - * @property symbol The symbol of the variable. - */ - public class Variable(public val symbol: Symbol) : TypedMst { - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - other as Variable<*> - if (symbol != other.symbol) return false - return true - } - - override fun hashCode(): Int = symbol.hashCode() - override fun toString(): String = "Variable(symbol=$symbol)" - } -} - -/** - * Interprets the [TypedMst] node with this [Algebra] and [arguments]. - */ -@UnstableKMathAPI -public fun TypedMst.interpret(algebra: Algebra, arguments: Map): T = when (this) { - is TypedMst.Unary -> algebra.unaryOperation(operation, interpret(algebra, arguments)) - - is TypedMst.Binary -> when { - algebra is NumericAlgebra && left is TypedMst.Constant && left.number != null -> - algebra.leftSideNumberOperation(operation, left.number, right.interpret(algebra, arguments)) - - algebra is NumericAlgebra && right is TypedMst.Constant && right.number != null -> - algebra.rightSideNumberOperation(operation, left.interpret(algebra, arguments), right.number) - - else -> algebra.binaryOperation( - operation, - left.interpret(algebra, arguments), - right.interpret(algebra, arguments), - ) - } - - is TypedMst.Constant -> value - is TypedMst.Variable -> arguments.getValue(symbol) -} - -/** - * Interprets the [TypedMst] node with this [Algebra] and optional [arguments]. - */ -@UnstableKMathAPI -public fun TypedMst.interpret(algebra: Algebra, vararg arguments: Pair): T = interpret( - algebra, - when (arguments.size) { - 0 -> emptyMap() - 1 -> mapOf(arguments[0]) - else -> hashMapOf(*arguments) - }, -) - -/** - * Interpret this [TypedMst] node as expression. - */ -@UnstableKMathAPI -public fun TypedMst.toExpression(algebra: Algebra): Expression = Expression { arguments -> - interpret(algebra, arguments) -} diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt deleted file mode 100644 index 71fb154c9..000000000 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/evaluateConstants.kt +++ /dev/null @@ -1,93 +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.ast - -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.NumericAlgebra -import space.kscience.kmath.operations.bindSymbolOrNull - -/** - * Evaluates constants in given [MST] for given [algebra] at the same time with converting to [TypedMst]. - */ -@UnstableKMathAPI -public fun MST.evaluateConstants(algebra: Algebra): TypedMst = when (this) { - is MST.Numeric -> TypedMst.Constant( - (algebra as? NumericAlgebra)?.number(value) ?: error("Numeric nodes are not supported by $algebra"), - value, - ) - - is MST.Unary -> when (val arg = value.evaluateConstants(algebra)) { - is TypedMst.Constant -> { - val value = algebra.unaryOperation( - operation, - arg.value, - ) - - TypedMst.Constant(value, if (value is Number) value else null) - } - - else -> TypedMst.Unary(operation, algebra.unaryOperationFunction(operation), arg) - } - - is MST.Binary -> { - val left = left.evaluateConstants(algebra) - val right = right.evaluateConstants(algebra) - - when { - left is TypedMst.Constant && right is TypedMst.Constant -> { - val value = when { - algebra is NumericAlgebra && left.number != null -> algebra.leftSideNumberOperation( - operation, - left.number, - right.value, - ) - - algebra is NumericAlgebra && right.number != null -> algebra.rightSideNumberOperation( - operation, - left.value, - right.number, - ) - - else -> algebra.binaryOperation( - operation, - left.value, - right.value, - ) - } - - TypedMst.Constant(value, if (value is Number) value else null) - } - - algebra is NumericAlgebra && left is TypedMst.Constant && left.number != null -> TypedMst.Binary( - operation, - algebra.leftSideNumberOperationFunction(operation), - left, - right, - ) - - algebra is NumericAlgebra && right is TypedMst.Constant && right.number != null -> TypedMst.Binary( - operation, - algebra.rightSideNumberOperationFunction(operation), - left, - right, - ) - - else -> TypedMst.Binary(operation, algebra.binaryOperationFunction(operation), left, right) - } - } - - is Symbol -> { - val boundSymbol = algebra.bindSymbolOrNull(this) - - if (boundSymbol != null) - TypedMst.Constant(boundSymbol, if (boundSymbol is Number) boundSymbol else null) - else - TypedMst.Variable(this) - } -} diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt index 012a6e65f..b02cc926b 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast @@ -17,12 +17,11 @@ import com.github.h0tk3y.betterParse.lexer.regexToken import com.github.h0tk3y.betterParse.parser.ParseResult import com.github.h0tk3y.betterParse.parser.Parser import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.FieldOps -import space.kscience.kmath.operations.GroupOps +import space.kscience.kmath.expressions.StringSymbol +import space.kscience.kmath.operations.FieldOperations +import space.kscience.kmath.operations.GroupOperations import space.kscience.kmath.operations.PowerOperations -import space.kscience.kmath.operations.RingOps -import kotlin.math.floor +import space.kscience.kmath.operations.RingOperations /** * better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4. @@ -41,23 +40,10 @@ public object ArithmeticsEvaluator : Grammar() { private val div: Token by literalToken("/") private val minus: Token by literalToken("-") private val plus: Token by literalToken("+") - - @Suppress("unused") private val ws: Token by regexToken("\\s+".toRegex(), ignore = true) - // TODO Rewrite as custom parser to handle numbers with better precision. Currently, numbers like 1e10 are handled while they could be stored as longs without precision loss. - private val number: Parser by num use { - val d = text.toDoubleOrNull() - - MST.Numeric( - if (d == null || d == floor(d) && !d.isInfinite()) { - text.toLongOrNull() ?: text.toDouble() - } else - d - ) - } - - private val singular: Parser by id use { Symbol(text) } + private val number: Parser by num use { MST.Numeric(text.toDouble()) } + private val singular: Parser by id use { StringSymbol(text) } private val unaryFunction: Parser by (id and -lpar and parser(ArithmeticsEvaluator::subSumChain) and -rpar) .map { (id, term) -> MST.Unary(id.text, term) } @@ -74,7 +60,7 @@ public object ArithmeticsEvaluator : Grammar() { .or(binaryFunction) .or(unaryFunction) .or(singular) - .or(-minus and parser(ArithmeticsEvaluator::term) map { MST.Unary(GroupOps.MINUS_OPERATION, it) }) + .or(-minus and parser(ArithmeticsEvaluator::term) map { MST.Unary(GroupOperations.MINUS_OPERATION, it) }) .or(-lpar and parser(ArithmeticsEvaluator::subSumChain) and -rpar) private val powChain: Parser by leftAssociative(term = term, operator = pow) { a, _, b -> @@ -86,9 +72,9 @@ public object ArithmeticsEvaluator : Grammar() { operator = div or mul use TokenMatch::type ) { a, op, b -> if (op == div) - MST.Binary(FieldOps.DIV_OPERATION, a, b) + MST.Binary(FieldOperations.DIV_OPERATION, a, b) else - MST.Binary(RingOps.TIMES_OPERATION, a, b) + MST.Binary(RingOperations.TIMES_OPERATION, a, b) } private val subSumChain: Parser by leftAssociative( @@ -96,17 +82,16 @@ public object ArithmeticsEvaluator : Grammar() { operator = plus or minus use TokenMatch::type ) { a, op, b -> if (op == plus) - MST.Binary(GroupOps.PLUS_OPERATION, a, b) + MST.Binary(GroupOperations.PLUS_OPERATION, a, b) else - MST.Binary(GroupOps.MINUS_OPERATION, a, b) + MST.Binary(GroupOperations.MINUS_OPERATION, a, b) } override val rootParser: Parser by subSumChain } /** - * Tries to parse the string into [MST] using [ArithmeticsEvaluator]. Returns [ParseResult] representing expression or - * error. + * Tries to parse the string into [MST] using [ArithmeticsEvaluator]. Returns [ParseResult] representing expression or error. * * @receiver the string to parse. * @return the [MST] node. diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt index 2df3d3cc7..bf5916fa5 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt index 8b5819b84..5439c42fa 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt index fdef35ebd..24bac425a 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt index ee23ab408..81b7d2afb 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt index 362c07d72..2f285c600 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt index 90f78a152..a7a28d87f 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast.rendering @@ -39,7 +39,7 @@ public val PrintNumeric: RenderFeature = RenderFeature { _, node -> @UnstableKMathAPI private fun printSignedNumberString(s: String): MathSyntax = if (s.startsWith('-')) UnaryMinusSyntax( - operation = GroupOps.MINUS_OPERATION, + operation = GroupOperations.MINUS_OPERATION, operand = OperandSyntax( operand = NumberSyntax(string = s.removePrefix("-")), parentheses = true, @@ -72,7 +72,7 @@ public class PrettyPrintFloats(public val types: Set>) : Rend val exponent = afterE.toDouble().toString().removeSuffix(".0") return MultiplicationSyntax( - operation = RingOps.TIMES_OPERATION, + operation = RingOperations.TIMES_OPERATION, left = OperandSyntax(operand = NumberSyntax(significand), parentheses = true), right = OperandSyntax( operand = SuperscriptSyntax( @@ -91,7 +91,7 @@ public class PrettyPrintFloats(public val types: Set>) : Rend if (toString.startsWith('-')) return UnaryMinusSyntax( - operation = GroupOps.MINUS_OPERATION, + operation = GroupOperations.MINUS_OPERATION, operand = OperandSyntax(operand = infty, parentheses = true), ) @@ -211,9 +211,9 @@ public class BinaryPlus(operations: Collection?) : Binary(operations) { public companion object { /** - * The default instance configured with [GroupOps.PLUS_OPERATION]. + * The default instance configured with [GroupOperations.PLUS_OPERATION]. */ - public val Default: BinaryPlus = BinaryPlus(setOf(GroupOps.PLUS_OPERATION)) + public val Default: BinaryPlus = BinaryPlus(setOf(GroupOperations.PLUS_OPERATION)) } } @@ -233,9 +233,9 @@ public class BinaryMinus(operations: Collection?) : Binary(operations) { public companion object { /** - * The default instance configured with [GroupOps.MINUS_OPERATION]. + * The default instance configured with [GroupOperations.MINUS_OPERATION]. */ - public val Default: BinaryMinus = BinaryMinus(setOf(GroupOps.MINUS_OPERATION)) + public val Default: BinaryMinus = BinaryMinus(setOf(GroupOperations.MINUS_OPERATION)) } } @@ -253,9 +253,9 @@ public class UnaryPlus(operations: Collection?) : Unary(operations) { public companion object { /** - * The default instance configured with [GroupOps.PLUS_OPERATION]. + * The default instance configured with [GroupOperations.PLUS_OPERATION]. */ - public val Default: UnaryPlus = UnaryPlus(setOf(GroupOps.PLUS_OPERATION)) + public val Default: UnaryPlus = UnaryPlus(setOf(GroupOperations.PLUS_OPERATION)) } } @@ -273,9 +273,9 @@ public class UnaryMinus(operations: Collection?) : Unary(operations) { public companion object { /** - * The default instance configured with [GroupOps.MINUS_OPERATION]. + * The default instance configured with [GroupOperations.MINUS_OPERATION]. */ - public val Default: UnaryMinus = UnaryMinus(setOf(GroupOps.MINUS_OPERATION)) + public val Default: UnaryMinus = UnaryMinus(setOf(GroupOperations.MINUS_OPERATION)) } } @@ -295,9 +295,9 @@ public class Fraction(operations: Collection?) : Binary(operations) { public companion object { /** - * The default instance configured with [FieldOps.DIV_OPERATION]. + * The default instance configured with [FieldOperations.DIV_OPERATION]. */ - public val Default: Fraction = Fraction(setOf(FieldOps.DIV_OPERATION)) + public val Default: Fraction = Fraction(setOf(FieldOperations.DIV_OPERATION)) } } @@ -422,9 +422,9 @@ public class Multiplication(operations: Collection?) : Binary(operations public companion object { /** - * The default instance configured with [RingOps.TIMES_OPERATION]. + * The default instance configured with [RingOperations.TIMES_OPERATION]. */ - public val Default: Multiplication = Multiplication(setOf(RingOps.TIMES_OPERATION)) + public val Default: Multiplication = Multiplication(setOf(RingOperations.TIMES_OPERATION)) } } diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt index 291399cee..3e33d6415 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt index c0271fbb5..3d05e03d6 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt @@ -1,16 +1,16 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast.rendering import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess.PostProcessPhase import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.FieldOps -import space.kscience.kmath.operations.GroupOps +import space.kscience.kmath.operations.FieldOperations +import space.kscience.kmath.operations.GroupOperations import space.kscience.kmath.operations.PowerOperations -import space.kscience.kmath.operations.RingOps +import space.kscience.kmath.operations.RingOperations /** * Removes unnecessary times (×) symbols from [MultiplicationSyntax]. @@ -306,10 +306,10 @@ public class SimplifyParentheses(public val precedenceFunction: (MathSyntax) -> is BinarySyntax -> when (it.operation) { PowerOperations.POW_OPERATION -> 1 - RingOps.TIMES_OPERATION -> 3 - FieldOps.DIV_OPERATION -> 3 - GroupOps.MINUS_OPERATION -> 4 - GroupOps.PLUS_OPERATION -> 4 + RingOperations.TIMES_OPERATION -> 3 + FieldOperations.DIV_OPERATION -> 3 + GroupOperations.MINUS_OPERATION -> 4 + GroupOperations.PLUS_OPERATION -> 4 else -> 0 } diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt index 1edb5923e..802d4c10e 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt index be8a92f3e..f5b1e2842 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast @@ -44,30 +44,6 @@ internal class TestCompilerOperations { assertEquals(1.0, expr(x to 0.0)) } - @Test - fun testTangent() = runCompilerTest { - val expr = MstExtendedField { tan(x) }.compileToExpression(DoubleField) - assertEquals(0.0, expr(x to 0.0)) - } - - @Test - fun testArcSine() = runCompilerTest { - val expr = MstExtendedField { asin(x) }.compileToExpression(DoubleField) - assertEquals(0.0, expr(x to 0.0)) - } - - @Test - fun testArcCosine() = runCompilerTest { - val expr = MstExtendedField { acos(x) }.compileToExpression(DoubleField) - assertEquals(0.0, expr(x to 1.0)) - } - - @Test - fun testAreaHyperbolicSine() = runCompilerTest { - val expr = MstExtendedField { asinh(x) }.compileToExpression(DoubleField) - assertEquals(0.0, expr(x to 0.0)) - } - @Test fun testSubtract() = runCompilerTest { val expr = MstExtendedField { x - x }.compileToExpression(DoubleField) diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt index 93ef97b0f..8d9a2301f 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt @@ -1,15 +1,13 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast import space.kscience.kmath.expressions.MstRing import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.Symbol.Companion.y import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing import space.kscience.kmath.operations.invoke import kotlin.test.Test @@ -18,23 +16,11 @@ import kotlin.test.assertFailsWith internal class TestCompilerVariables { @Test - fun testNoVariables() = runCompilerTest { - val expr = "0".parseMath().compileToExpression(DoubleField) - assertEquals(0.0, expr(), 0.0001) - } - - @Test - fun testOneVariable() = runCompilerTest { + fun testVariable() = runCompilerTest { val expr = MstRing { x }.compileToExpression(IntRing) assertEquals(1, expr(x to 1)) } - @Test - fun testTwoVariables() = runCompilerTest { - val expr = "y+x/y+x".parseMath().compileToExpression(DoubleField) - assertEquals(8.0, expr(x to 4.0, y to 2.0)) - } - @Test fun testUndefinedVariableFails() = runCompilerTest { val expr = MstRing { x }.compileToExpression(IntRing) diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt deleted file mode 100644 index 954a0f330..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestFolding.kt +++ /dev/null @@ -1,52 +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.ast - -import space.kscience.kmath.operations.ByteRing -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.operations.pi -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.fail - -internal class TestFolding { - @Test - fun foldUnary() = assertEquals( - -1, - ("-(1)".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant ?: fail()).value, - ) - - @Test - fun foldDeepUnary() = assertEquals( - 1, - ("-(-(1))".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant ?: fail()).value, - ) - - @Test - fun foldBinary() = assertEquals( - 2, - ("1*2".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant ?: fail()).value, - ) - - @Test - fun foldDeepBinary() = assertEquals( - 10, - ("1*2*5".parseMath().evaluateConstants(IntRing) as? TypedMst.Constant ?: fail()).value, - ) - - @Test - fun foldSymbol() = assertEquals( - DoubleField.pi, - ("pi".parseMath().evaluateConstants(DoubleField) as? TypedMst.Constant ?: fail()).value, - ) - - @Test - fun foldNumeric() = assertEquals( - 42.toByte(), - ("42".parseMath().evaluateConstants(ByteRing) as? TypedMst.Constant ?: fail()).value, - ) -} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt index d0c3a789e..4c834a9ca 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt @@ -1,13 +1,13 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast import space.kscience.kmath.complex.Complex import space.kscience.kmath.complex.ComplexField -import space.kscience.kmath.expressions.interpret +import space.kscience.kmath.expressions.evaluate import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.DoubleField import kotlin.test.Test @@ -17,14 +17,14 @@ internal class TestParser { @Test fun evaluateParsedMst() { val mst = "2+2*(2+2)".parseMath() - val res = mst.interpret(ComplexField) + val res = ComplexField.evaluate(mst) assertEquals(Complex(10.0, 0.0), res) } @Test fun evaluateMstSymbol() { val mst = "i".parseMath() - val res = mst.interpret(ComplexField) + val res = ComplexField.evaluate(mst) assertEquals(ComplexField.i, res) } @@ -32,7 +32,7 @@ internal class TestParser { @Test fun evaluateMstUnary() { val mst = "sin(0)".parseMath() - val res = mst.interpret(DoubleField) + val res = DoubleField.evaluate(mst) assertEquals(0.0, res) } @@ -53,7 +53,7 @@ internal class TestParser { } val mst = "magic(a, b)".parseMath() - val res = mst.interpret(magicalAlgebra) + val res = magicalAlgebra.evaluate(mst) assertEquals("a ★ b", res) } } diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt index 42cf5ce58..9776da45c 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt @@ -1,39 +1,39 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast -import space.kscience.kmath.expressions.interpret +import space.kscience.kmath.expressions.evaluate import space.kscience.kmath.operations.DoubleField import kotlin.test.Test import kotlin.test.assertEquals internal class TestParserPrecedence { @Test - fun test1(): Unit = assertEquals(6.0, "2*2+2".parseMath().interpret(f)) + fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath())) @Test - fun test2(): Unit = assertEquals(6.0, "2+2*2".parseMath().interpret(f)) + fun test2(): Unit = assertEquals(6.0, f.evaluate("2+2*2".parseMath())) @Test - fun test3(): Unit = assertEquals(10.0, "2^3+2".parseMath().interpret(f)) + fun test3(): Unit = assertEquals(10.0, f.evaluate("2^3+2".parseMath())) @Test - fun test4(): Unit = assertEquals(10.0, "2+2^3".parseMath().interpret(f)) + fun test4(): Unit = assertEquals(10.0, f.evaluate("2+2^3".parseMath())) @Test - fun test5(): Unit = assertEquals(16.0, "2^3*2".parseMath().interpret(f)) + fun test5(): Unit = assertEquals(16.0, f.evaluate("2^3*2".parseMath())) @Test - fun test6(): Unit = assertEquals(16.0, "2*2^3".parseMath().interpret(f)) + fun test6(): Unit = assertEquals(16.0, f.evaluate("2*2^3".parseMath())) @Test - fun test7(): Unit = assertEquals(18.0, "2+2^3*2".parseMath().interpret(f)) + fun test7(): Unit = assertEquals(18.0, f.evaluate("2+2^3*2".parseMath())) @Test - fun test8(): Unit = assertEquals(18.0, "2*2^3+2".parseMath().interpret(f)) + fun test8(): Unit = assertEquals(18.0, f.evaluate("2*2^3+2".parseMath())) private companion object { private val f = DoubleField diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt index a40c785b9..ae429d97e 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt index 43f31baba..d8e432230 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt @@ -1,13 +1,13 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast.rendering import space.kscience.kmath.ast.rendering.TestUtils.testLatex import space.kscience.kmath.expressions.MST -import space.kscience.kmath.operations.GroupOps +import space.kscience.kmath.operations.GroupOperations import kotlin.test.Test internal class TestLatex { @@ -36,7 +36,7 @@ internal class TestLatex { fun unaryOperator() = testLatex("sin(1)", "\\operatorname{sin}\\,\\left(1\\right)") @Test - fun unaryPlus() = testLatex(MST.Unary(GroupOps.PLUS_OPERATION, MST.Numeric(1)), "+1") + fun unaryPlus() = testLatex(MST.Unary(GroupOperations.PLUS_OPERATION, MST.Numeric(1)), "+1") @Test fun unaryMinus() = testLatex("-x", "-x") diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt index 145055494..a7fcbc75b 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt @@ -1,13 +1,13 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast.rendering import space.kscience.kmath.ast.rendering.TestUtils.testMathML import space.kscience.kmath.expressions.MST -import space.kscience.kmath.operations.GroupOps +import space.kscience.kmath.operations.GroupOperations import kotlin.test.Test internal class TestMathML { @@ -47,7 +47,7 @@ internal class TestMathML { @Test fun unaryPlus() = - testMathML(MST.Unary(GroupOps.PLUS_OPERATION, MST.Numeric(1)), "+1") + testMathML(MST.Unary(GroupOperations.PLUS_OPERATION, MST.Numeric(1)), "+1") @Test fun unaryMinus() = testMathML("-x", "-x") diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt index 09ec127c7..4485605a6 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt index bf87b6fd0..6b418821b 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt index ec7436188..ef9f3145a 100644 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt +++ b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt index 521907d2c..2e69a536f 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt index a8b1aa2e1..316fdeeff 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt @@ -1,52 +1,88 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.estree -import space.kscience.kmath.ast.TypedMst -import space.kscience.kmath.ast.evaluateConstants import space.kscience.kmath.estree.internal.ESTreeBuilder import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.MST +import space.kscience.kmath.expressions.MST.* import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.expressions.invoke import space.kscience.kmath.internal.estree.BaseExpression -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Algebra +import space.kscience.kmath.operations.NumericAlgebra +import space.kscience.kmath.operations.bindSymbolOrNull + +@PublishedApi +internal fun MST.compileWith(algebra: Algebra): Expression { + fun ESTreeBuilder.visit(node: MST): BaseExpression = when (node) { + is Symbol -> { + val symbol = algebra.bindSymbolOrNull(node) + + if (symbol != null) + constant(symbol) + else + variable(node.identity) + } + + is Numeric -> constant(node.value) + + is Unary -> when { + algebra is NumericAlgebra && node.value is Numeric -> constant( + algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value))) + + else -> call(algebra.unaryOperationFunction(node.operation), visit(node.value)) + } + + is Binary -> when { + algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> constant( + algebra.binaryOperationFunction(node.operation).invoke( + algebra.number((node.left as Numeric).value), + algebra.number((node.right as Numeric).value) + ) + ) + + algebra is NumericAlgebra && node.left is Numeric -> call( + algebra.leftSideNumberOperationFunction(node.operation), + visit(node.left), + visit(node.right), + ) + + algebra is NumericAlgebra && node.right is Numeric -> call( + algebra.rightSideNumberOperationFunction(node.operation), + visit(node.left), + visit(node.right), + ) + + else -> call( + algebra.binaryOperationFunction(node.operation), + visit(node.left), + visit(node.right), + ) + } + } + + return ESTreeBuilder { visit(this@compileWith) }.instance +} /** * Create a compiled expression with given [MST] and given [algebra]. */ -@OptIn(UnstableKMathAPI::class) -public fun MST.compileToExpression(algebra: Algebra): Expression { - val typed = evaluateConstants(algebra) - if (typed is TypedMst.Constant) return Expression { typed.value } +public fun MST.compileToExpression(algebra: Algebra): Expression = compileWith(algebra) - fun ESTreeBuilder.visit(node: TypedMst): BaseExpression = when (node) { - is TypedMst.Constant -> constant(node.value) - is TypedMst.Variable -> variable(node.symbol) - is TypedMst.Unary -> call(node.function, visit(node.value)) - - is TypedMst.Binary -> call( - node.function, - visit(node.left), - visit(node.right), - ) - } - - return ESTreeBuilder { visit(typed) }.instance -} /** * Compile given MST to expression and evaluate it against [arguments] */ -public fun MST.compile(algebra: Algebra, arguments: Map): T = - compileToExpression(algebra)(arguments) +public inline fun MST.compile(algebra: Algebra, arguments: Map): T = + compileToExpression(algebra).invoke(arguments) + /** * Compile given MST to expression and evaluate it against [arguments] */ -public fun MST.compile(algebra: Algebra, vararg arguments: Pair): T = - compileToExpression(algebra)(*arguments) +public inline fun MST.compile(algebra: Algebra, vararg arguments: Pair): T = + compileToExpression(algebra).invoke(*arguments) diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt index 10a6c4a16..850f20be7 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.estree.internal @@ -61,7 +61,7 @@ internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExp } } - fun variable(name: Symbol): BaseExpression = call(getOrFail, Identifier("arguments"), SimpleLiteral(name.identity)) + fun variable(name: String): BaseExpression = call(getOrFail, Identifier("arguments"), SimpleLiteral(name)) fun call(function: Function, vararg args: BaseExpression): BaseExpression = SimpleCallExpression( optional = false, diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt index eb5c1e3dd..c7faf73e0 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.estree.internal.astring diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt index cca2d83af..c36860654 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ @file:JsModule("astring") diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt index 93b4f6ce6..0a5b059ba 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.internal.astring diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt index 86e0cede7..26186c453 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ @file:Suppress( diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt index 42b6ac7d8..13e3a49e2 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ @file:Suppress( diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt index 523b13b40..8e449627c 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ @file:Suppress("PackageDirectoryMismatch", "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation") diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt index 1f7b09af8..d85857de8 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.internal.emitter diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt index 3aa31f921..122a3a397 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.internal.estree diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt index b62b8c06c..ad079dbd0 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ @file:Suppress("ClassName") diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt index 52be5530f..caab91731 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.internal.stream diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt index 9c012e3a3..5c091e3a1 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.internal.tsstdlib diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt index 0cd395f2c..bb7fd44ca 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ @file:Suppress("UNUSED_TYPEALIAS_PARAMETER", "DEPRECATION") diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt index 90690abed..52dd64a5e 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ @file:JsQualifier("WebAssembly") @@ -201,8 +201,8 @@ internal open external class Module { } @JsName("Instance") -internal open external class Instance(module: Module, importObject: dynamic = definedExternally) { - open var exports: dynamic +internal open external class Instance(module: Module, importObject: Any = definedExternally) { + open var exports: Any } @JsName("Memory") diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt index c5023c384..d59a52701 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ @file:Suppress( 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 aacb62f36..5b6cf65db 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 @@ -1,34 +1,76 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.wasm.internal -import space.kscience.kmath.ast.TypedMst -import space.kscience.kmath.expressions.* +import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.expressions.MST +import space.kscience.kmath.expressions.MST.* +import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.internal.binaryen.* import space.kscience.kmath.internal.webassembly.Instance -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* import space.kscience.kmath.internal.binaryen.Module as BinaryenModule import space.kscience.kmath.internal.webassembly.Module as WasmModule private val spreader = eval("(obj, args) => obj(...args)") -@OptIn(UnstableKMathAPI::class) @Suppress("UnsafeCastFromDynamic") -internal sealed class WasmBuilder>( - protected val binaryenType: Type, - protected val algebra: Algebra, - protected val target: TypedMst, -) { - protected val keys: MutableList = mutableListOf() - protected lateinit var ctx: BinaryenModule +internal sealed class WasmBuilder( + val binaryenType: Type, + val algebra: Algebra, + val target: MST, +) where T : Number { + val keys: MutableList = mutableListOf() + lateinit var ctx: BinaryenModule - abstract val instance: E + open fun visitSymbolic(mst: Symbol): ExpressionRef { + algebra.bindSymbolOrNull(mst)?.let { return visitNumeric(Numeric(it)) } - protected val executable = run { + var idx = keys.indexOf(mst) + + if (idx == -1) { + keys += mst + idx = keys.lastIndex + } + + return ctx.local.get(idx, binaryenType) + } + + abstract fun visitNumeric(mst: Numeric): ExpressionRef + + open fun visitUnary(mst: Unary): ExpressionRef = + error("Unary operation ${mst.operation} not defined in $this") + + open fun visitBinary(mst: Binary): ExpressionRef = + error("Binary operation ${mst.operation} not defined in $this") + + open fun createModule(): BinaryenModule = js("new \$module\$binaryen.Module()") + + fun visit(mst: MST): ExpressionRef = when (mst) { + is Symbol -> visitSymbolic(mst) + is Numeric -> visitNumeric(mst) + + is Unary -> when { + algebra is NumericAlgebra && mst.value is Numeric -> visitNumeric( + Numeric(algebra.unaryOperationFunction(mst.operation)(algebra.number((mst.value as Numeric).value)))) + + else -> visitUnary(mst) + } + + is Binary -> when { + algebra is NumericAlgebra && mst.left is Numeric && mst.right is Numeric -> visitNumeric(Numeric( + algebra.binaryOperationFunction(mst.operation) + .invoke(algebra.number((mst.left as Numeric).value), algebra.number((mst.right as Numeric).value)) + )) + + else -> visitBinary(mst) + } + } + + val instance by lazy { val c = WasmModule(with(createModule()) { ctx = this val expr = visit(target) @@ -49,109 +91,66 @@ internal sealed class WasmBuilder>( res }) - Instance(c, js("{}")).exports.executable - } + val i = Instance(c, js("{}") as Any) + val symbols = keys + keys.clear() - protected abstract fun visitNumber(number: Number): ExpressionRef - - protected open fun visitVariable(node: TypedMst.Variable): ExpressionRef { - var idx = keys.indexOf(node.symbol) - - if (idx == -1) { - keys += node.symbol - idx = keys.lastIndex + Expression { args -> + val params = symbols.map(args::getValue).toTypedArray() + spreader(i.exports.asDynamic().executable, params) as T } - - return ctx.local.get(idx, binaryenType) - } - - protected open fun visitUnary(node: TypedMst.Unary): ExpressionRef = - error("Unary operation ${node.operation} not defined in $this") - - protected open fun visitBinary(mst: TypedMst.Binary): ExpressionRef = - error("Binary operation ${mst.operation} not defined in $this") - - protected open fun createModule(): BinaryenModule = js("new \$module\$binaryen.Module()") - - protected fun visit(node: TypedMst): ExpressionRef = when (node) { - is TypedMst.Constant -> visitNumber( - node.number ?: error("Object constants are not supported by pritimive ASM builder"), - ) - - is TypedMst.Variable -> visitVariable(node) - is TypedMst.Unary -> visitUnary(node) - is TypedMst.Binary -> visitBinary(node) } } -@UnstableKMathAPI -internal class DoubleWasmBuilder(target: TypedMst) : - WasmBuilder(f64, DoubleField, target) { - override val instance by lazy { - object : DoubleExpression { - override val indexer = SimpleSymbolIndexer(keys) +internal class DoubleWasmBuilder(target: MST) : WasmBuilder(f64, DoubleField, target) { + override fun createModule(): BinaryenModule = readBinary(f64StandardFunctions) - override fun invoke(arguments: DoubleArray) = spreader(executable, arguments).unsafeCast() - } + override fun visitNumeric(mst: Numeric): ExpressionRef = ctx.f64.const(mst.value) + + override fun visitUnary(mst: Unary): ExpressionRef = when (mst.operation) { + GroupOperations.MINUS_OPERATION -> ctx.f64.neg(visit(mst.value)) + GroupOperations.PLUS_OPERATION -> visit(mst.value) + PowerOperations.SQRT_OPERATION -> ctx.f64.sqrt(visit(mst.value)) + TrigonometricOperations.SIN_OPERATION -> ctx.call("sin", arrayOf(visit(mst.value)), f64) + TrigonometricOperations.COS_OPERATION -> ctx.call("cos", arrayOf(visit(mst.value)), f64) + TrigonometricOperations.TAN_OPERATION -> ctx.call("tan", arrayOf(visit(mst.value)), f64) + TrigonometricOperations.ASIN_OPERATION -> ctx.call("asin", arrayOf(visit(mst.value)), f64) + TrigonometricOperations.ACOS_OPERATION -> ctx.call("acos", arrayOf(visit(mst.value)), f64) + TrigonometricOperations.ATAN_OPERATION -> ctx.call("atan", arrayOf(visit(mst.value)), f64) + ExponentialOperations.SINH_OPERATION -> ctx.call("sinh", arrayOf(visit(mst.value)), f64) + ExponentialOperations.COSH_OPERATION -> ctx.call("cosh", arrayOf(visit(mst.value)), f64) + ExponentialOperations.TANH_OPERATION -> ctx.call("tanh", arrayOf(visit(mst.value)), f64) + ExponentialOperations.ASINH_OPERATION -> ctx.call("asinh", arrayOf(visit(mst.value)), f64) + ExponentialOperations.ACOSH_OPERATION -> ctx.call("acosh", arrayOf(visit(mst.value)), f64) + ExponentialOperations.ATANH_OPERATION -> ctx.call("atanh", arrayOf(visit(mst.value)), f64) + ExponentialOperations.EXP_OPERATION -> ctx.call("exp", arrayOf(visit(mst.value)), f64) + ExponentialOperations.LN_OPERATION -> ctx.call("log", arrayOf(visit(mst.value)), f64) + else -> super.visitUnary(mst) } - override fun createModule() = readBinary(f64StandardFunctions) - - override fun visitNumber(number: Number) = ctx.f64.const(number.toDouble()) - - override fun visitUnary(node: TypedMst.Unary): ExpressionRef = when (node.operation) { - GroupOps.MINUS_OPERATION -> ctx.f64.neg(visit(node.value)) - GroupOps.PLUS_OPERATION -> visit(node.value) - PowerOperations.SQRT_OPERATION -> ctx.f64.sqrt(visit(node.value)) - TrigonometricOperations.SIN_OPERATION -> ctx.call("sin", arrayOf(visit(node.value)), f64) - TrigonometricOperations.COS_OPERATION -> ctx.call("cos", arrayOf(visit(node.value)), f64) - TrigonometricOperations.TAN_OPERATION -> ctx.call("tan", arrayOf(visit(node.value)), f64) - TrigonometricOperations.ASIN_OPERATION -> ctx.call("asin", arrayOf(visit(node.value)), f64) - TrigonometricOperations.ACOS_OPERATION -> ctx.call("acos", arrayOf(visit(node.value)), f64) - TrigonometricOperations.ATAN_OPERATION -> ctx.call("atan", arrayOf(visit(node.value)), f64) - ExponentialOperations.SINH_OPERATION -> ctx.call("sinh", arrayOf(visit(node.value)), f64) - ExponentialOperations.COSH_OPERATION -> ctx.call("cosh", arrayOf(visit(node.value)), f64) - ExponentialOperations.TANH_OPERATION -> ctx.call("tanh", arrayOf(visit(node.value)), f64) - ExponentialOperations.ASINH_OPERATION -> ctx.call("asinh", arrayOf(visit(node.value)), f64) - ExponentialOperations.ACOSH_OPERATION -> ctx.call("acosh", arrayOf(visit(node.value)), f64) - ExponentialOperations.ATANH_OPERATION -> ctx.call("atanh", arrayOf(visit(node.value)), f64) - ExponentialOperations.EXP_OPERATION -> ctx.call("exp", arrayOf(visit(node.value)), f64) - ExponentialOperations.LN_OPERATION -> ctx.call("log", arrayOf(visit(node.value)), f64) - else -> super.visitUnary(node) - } - - override fun visitBinary(mst: TypedMst.Binary): ExpressionRef = when (mst.operation) { - GroupOps.PLUS_OPERATION -> ctx.f64.add(visit(mst.left), visit(mst.right)) - GroupOps.MINUS_OPERATION -> ctx.f64.sub(visit(mst.left), visit(mst.right)) - RingOps.TIMES_OPERATION -> ctx.f64.mul(visit(mst.left), visit(mst.right)) - FieldOps.DIV_OPERATION -> ctx.f64.div(visit(mst.left), visit(mst.right)) + override fun visitBinary(mst: Binary): ExpressionRef = when (mst.operation) { + GroupOperations.PLUS_OPERATION -> ctx.f64.add(visit(mst.left), visit(mst.right)) + GroupOperations.MINUS_OPERATION -> ctx.f64.sub(visit(mst.left), visit(mst.right)) + RingOperations.TIMES_OPERATION -> ctx.f64.mul(visit(mst.left), visit(mst.right)) + FieldOperations.DIV_OPERATION -> ctx.f64.div(visit(mst.left), visit(mst.right)) PowerOperations.POW_OPERATION -> ctx.call("pow", arrayOf(visit(mst.left), visit(mst.right)), f64) else -> super.visitBinary(mst) } } -@UnstableKMathAPI -internal class IntWasmBuilder(target: TypedMst) : WasmBuilder(i32, IntRing, target) { - override val instance by lazy { - object : IntExpression { - override val indexer = SimpleSymbolIndexer(keys) +internal class IntWasmBuilder(target: MST) : WasmBuilder(i32, IntRing, target) { + override fun visitNumeric(mst: Numeric): ExpressionRef = ctx.i32.const(mst.value) - override fun invoke(arguments: IntArray) = spreader(executable, arguments).unsafeCast() - } + override fun visitUnary(mst: Unary): ExpressionRef = when (mst.operation) { + GroupOperations.MINUS_OPERATION -> ctx.i32.sub(ctx.i32.const(0), visit(mst.value)) + GroupOperations.PLUS_OPERATION -> visit(mst.value) + else -> super.visitUnary(mst) } - override fun visitNumber(number: Number) = ctx.i32.const(number.toInt()) - - override fun visitUnary(node: TypedMst.Unary): ExpressionRef = when (node.operation) { - GroupOps.MINUS_OPERATION -> ctx.i32.sub(ctx.i32.const(0), visit(node.value)) - GroupOps.PLUS_OPERATION -> visit(node.value) - else -> super.visitUnary(node) - } - - override fun visitBinary(mst: TypedMst.Binary): ExpressionRef = when (mst.operation) { - GroupOps.PLUS_OPERATION -> ctx.i32.add(visit(mst.left), visit(mst.right)) - GroupOps.MINUS_OPERATION -> ctx.i32.sub(visit(mst.left), visit(mst.right)) - RingOps.TIMES_OPERATION -> ctx.i32.mul(visit(mst.left), visit(mst.right)) + override fun visitBinary(mst: Binary): ExpressionRef = when (mst.operation) { + GroupOperations.PLUS_OPERATION -> ctx.i32.add(visit(mst.left), visit(mst.right)) + GroupOperations.MINUS_OPERATION -> ctx.i32.sub(visit(mst.left), visit(mst.right)) + RingOperations.TIMES_OPERATION -> ctx.i32.mul(visit(mst.left), visit(mst.right)) else -> super.visitBinary(mst) } } diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt index 21a88b5d0..fe9c22c18 100644 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt +++ b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.wasm.internal 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 f9540f9db..5b28b8782 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 @@ -1,37 +1,47 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ -@file:Suppress("UNUSED_PARAMETER") - package space.kscience.kmath.wasm -import space.kscience.kmath.ast.TypedMst -import space.kscience.kmath.ast.evaluateConstants -import space.kscience.kmath.expressions.* +import space.kscience.kmath.estree.compileWith +import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.expressions.MST +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.expressions.invoke import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing import space.kscience.kmath.wasm.internal.DoubleWasmBuilder import space.kscience.kmath.wasm.internal.IntWasmBuilder +/** + * Compiles an [MST] to WASM in the context of reals. + * + * @author Iaroslav Postovalov + */ +@UnstableKMathAPI +public fun DoubleField.expression(mst: MST): Expression = + DoubleWasmBuilder(mst).instance + +/** + * Compiles an [MST] to WASM in the context of integers. + * + * @author Iaroslav Postovalov + */ +@UnstableKMathAPI +public fun IntRing.expression(mst: MST): Expression = + IntWasmBuilder(mst).instance + /** * Create a compiled expression with given [MST] and given [algebra]. * * @author Iaroslav Postovalov */ @UnstableKMathAPI -public fun MST.compileToExpression(algebra: IntRing): IntExpression { - val typed = evaluateConstants(algebra) +public fun MST.compileToExpression(algebra: IntRing): Expression = compileWith(algebra) - return if (typed is TypedMst.Constant) object : IntExpression { - override val indexer = SimpleSymbolIndexer(emptyList()) - - override fun invoke(arguments: IntArray): Int = typed.value - } else - IntWasmBuilder(typed).instance -} /** * Compile given MST to expression and evaluate it against [arguments]. @@ -40,7 +50,7 @@ public fun MST.compileToExpression(algebra: IntRing): IntExpression { */ @UnstableKMathAPI public fun MST.compile(algebra: IntRing, arguments: Map): Int = - compileToExpression(algebra)(arguments) + compileToExpression(algebra).invoke(arguments) /** @@ -58,16 +68,7 @@ public fun MST.compile(algebra: IntRing, vararg arguments: Pair): I * @author Iaroslav Postovalov */ @UnstableKMathAPI -public fun MST.compileToExpression(algebra: DoubleField): Expression { - val typed = evaluateConstants(algebra) - - return if (typed is TypedMst.Constant) object : DoubleExpression { - override val indexer = SimpleSymbolIndexer(emptyList()) - - override fun invoke(arguments: DoubleArray): Double = typed.value - } else - DoubleWasmBuilder(typed).instance -} +public fun MST.compileToExpression(algebra: DoubleField): Expression = compileWith(algebra) /** @@ -77,7 +78,7 @@ public fun MST.compileToExpression(algebra: DoubleField): Expression { */ @UnstableKMathAPI public fun MST.compile(algebra: DoubleField, arguments: Map): Double = - compileToExpression(algebra)(arguments) + compileToExpression(algebra).invoke(arguments) /** @@ -87,4 +88,4 @@ public fun MST.compile(algebra: DoubleField, arguments: Map): Do */ @UnstableKMathAPI public fun MST.compile(algebra: DoubleField, vararg arguments: Pair): Double = - compileToExpression(algebra)(*arguments) + compileToExpression(algebra).invoke(*arguments) diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt new file mode 100644 index 000000000..f8c429d5a --- /dev/null +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt @@ -0,0 +1,114 @@ +/* + * 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 file. + */ + +package space.kscience.kmath.ast + +import space.kscience.kmath.expressions.* +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.bindSymbol +import space.kscience.kmath.operations.invoke +import kotlin.math.sin +import kotlin.random.Random +import kotlin.test.Ignore +import kotlin.test.Test +import kotlin.time.measureTime +import space.kscience.kmath.estree.compileToExpression as estreeCompileToExpression +import space.kscience.kmath.wasm.compileToExpression as wasmCompileToExpression + +// TODO move to benchmarks when https://github.com/Kotlin/kotlinx-benchmark/pull/38 or similar feature is merged +@Ignore +internal class TestExecutionTime { + private companion object { + private const val times = 1_000_000 + private val x by symbol + private val algebra = DoubleField + + private val functional = algebra.expressionInExtendedField { + bindSymbol(x) * const(2.0) + const(2.0) / bindSymbol(x) - const(16.0) / sin(bindSymbol(x)) + } + + private val node = MstExtendedField { + x * number(2.0) + number(2.0) / x - number(16.0) / sin(x) + } + + private val mst = node.toExpression(algebra) + private val wasm = node.wasmCompileToExpression(algebra) + private val estree = node.estreeCompileToExpression(algebra) + + // In JavaScript, the expression below is implemented like + // _no_name_provided__125.prototype.invoke_178 = function (args) { + // var tmp = getValue(args, raw$_get_x__3(this._$x$delegate_2)) * 2.0 + 2.0 / getValue(args, raw$_get_x__3(this._$x$delegate_2)); + // var tmp0_sin_0_5 = getValue(args, raw$_get_x__3(this._$x$delegate_2)); + // return tmp - 16.0 / Math.sin(tmp0_sin_0_5); + // }; + + private val raw = Expression { args -> + val x = args[x]!! + algebra { x * 2.0 + 2.0 / x - 16.0 / sin(x) } + } + + private val justCalculate = { args: dynamic -> + val x = args[x].unsafeCast() + x * 2.0 + 2.0 / x - 16.0 / sin(x) + } + } + + private fun invokeAndSum(name: String, expr: Expression) { + println(name) + val rng = Random(0) + var sum = 0.0 + measureTime { + repeat(times) { sum += expr(x to rng.nextDouble()) } + }.also(::println) + } + + /** + * [Expression] created with [expressionInExtendedField]. + */ + @Test + fun functionalExpression() = invokeAndSum("functional", functional) + + /** + * [Expression] created with [mstExpression]. + */ + @Test + fun mstExpression() = invokeAndSum("mst", mst) + + /** + * [Expression] created with [wasmCompileToExpression]. + */ + @Test + fun wasmExpression() = invokeAndSum("wasm", wasm) + + /** + * [Expression] created with [estreeCompileToExpression]. + */ + @Test + fun estreeExpression() = invokeAndSum("estree", wasm) + + /** + * [Expression] implemented manually with `kotlin.math`. + */ + @Test + fun rawExpression() = invokeAndSum("raw", raw) + + /** + * Direct computation w/o [Expression]. + */ + @Test + fun justCalculateExpression() { + println("justCalculate") + val rng = Random(0) + var sum = 0.0 + measureTime { + repeat(times) { + val arg = rng.nextDouble() + val o = js("{}") + o["x"] = arg + sum += justCalculate(o) + } + }.also(::println) + } +} diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt index 0d896c6f6..3c2a9bd13 100644 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt index 8ae5fcb36..6c91df866 100644 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.wasm 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 73b9c97a7..2426d6ee4 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 @@ -1,21 +1,20 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ -@file:Suppress("UNUSED_PARAMETER") - package space.kscience.kmath.asm -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.misc.UnstableKMathAPI +import space.kscience.kmath.asm.internal.AsmBuilder +import space.kscience.kmath.asm.internal.buildName +import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.expressions.MST +import space.kscience.kmath.expressions.MST.* +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.expressions.invoke import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.operations.LongRing +import space.kscience.kmath.operations.NumericAlgebra +import space.kscience.kmath.operations.bindSymbolOrNull /** * Compiles given MST to an Expression using AST compiler. @@ -25,171 +24,73 @@ import space.kscience.kmath.operations.LongRing * @return the compiled expression. * @author Alexander Nozik */ -@OptIn(UnstableKMathAPI::class) @PublishedApi internal fun MST.compileWith(type: Class, algebra: Algebra): Expression { - val typed = evaluateConstants(algebra) - if (typed is TypedMst.Constant) return Expression { typed.value } + fun AsmBuilder.visit(node: MST): Unit = when (node) { + is Symbol -> { + val symbol = algebra.bindSymbolOrNull(node) - fun GenericAsmBuilder.variablesVisitor(node: TypedMst): Unit = when (node) { - is TypedMst.Unary -> variablesVisitor(node.value) - - is TypedMst.Binary -> { - variablesVisitor(node.left) - variablesVisitor(node.right) + if (symbol != null) + loadObjectConstant(symbol as Any) + else + loadVariable(node.identity) } - is TypedMst.Variable -> prepareVariable(node.symbol) - is TypedMst.Constant -> Unit - } + is Numeric -> loadNumberConstant(node.value) - fun GenericAsmBuilder.expressionVisitor(node: TypedMst): Unit = when (node) { - is TypedMst.Constant -> if (node.number != null) - loadNumberConstant(node.number) - else - loadObjectConstant(node.value) + is Unary -> when { + algebra is NumericAlgebra && node.value is Numeric -> loadObjectConstant( + algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value))) - is TypedMst.Variable -> loadVariable(node.symbol) - is TypedMst.Unary -> buildCall(node.function) { expressionVisitor(node.value) } + else -> buildCall(algebra.unaryOperationFunction(node.operation)) { visit(node.value) } + } - is TypedMst.Binary -> buildCall(node.function) { - expressionVisitor(node.left) - expressionVisitor(node.right) + is Binary -> when { + algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> loadObjectConstant( + algebra.binaryOperationFunction(node.operation).invoke( + algebra.number((node.left as Numeric).value), + algebra.number((node.right as Numeric).value) + ) + ) + + algebra is NumericAlgebra && node.left is Numeric -> buildCall( + algebra.leftSideNumberOperationFunction(node.operation)) { + visit(node.left) + visit(node.right) + } + + algebra is NumericAlgebra && node.right is Numeric -> buildCall( + algebra.rightSideNumberOperationFunction(node.operation)) { + visit(node.left) + visit(node.right) + } + + else -> buildCall(algebra.binaryOperationFunction(node.operation)) { + visit(node.left) + visit(node.right) + } } } - return GenericAsmBuilder( - type, - buildName("${typed.hashCode()}_${type.simpleName}"), - { variablesVisitor(typed) }, - { expressionVisitor(typed) }, - ).instance + return AsmBuilder(type, buildName(this)) { visit(this@compileWith) }.instance } + /** * Create a compiled expression with given [MST] and given [algebra]. */ public inline fun MST.compileToExpression(algebra: Algebra): Expression = compileWith(T::class.java, algebra) + /** * Compile given MST to expression and evaluate it against [arguments] */ public inline fun MST.compile(algebra: Algebra, arguments: Map): T = - compileToExpression(algebra)(arguments) + compileToExpression(algebra).invoke(arguments) /** * Compile given MST to expression and evaluate it against [arguments] */ public inline fun MST.compile(algebra: Algebra, vararg arguments: Pair): T = - compileToExpression(algebra)(*arguments) - - -/** - * Create a compiled expression with given [MST] and given [algebra]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compileToExpression(algebra: IntRing): IntExpression { - val typed = evaluateConstants(algebra) - - return if (typed is TypedMst.Constant) object : IntExpression { - override val indexer = SimpleSymbolIndexer(emptyList()) - - override fun invoke(arguments: IntArray): Int = typed.value - } else - IntAsmBuilder(typed).instance -} - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: IntRing, arguments: Map): Int = - compileToExpression(algebra)(arguments) - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: IntRing, vararg arguments: Pair): Int = - compileToExpression(algebra)(*arguments) - - -/** - * Create a compiled expression with given [MST] and given [algebra]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compileToExpression(algebra: LongRing): LongExpression { - val typed = evaluateConstants(algebra) - - return if (typed is TypedMst.Constant) object : LongExpression { - override val indexer = SimpleSymbolIndexer(emptyList()) - - override fun invoke(arguments: LongArray): Long = typed.value - } else - LongAsmBuilder(typed).instance -} - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: LongRing, arguments: Map): Long = - compileToExpression(algebra)(arguments) - - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: LongRing, vararg arguments: Pair): Long = - compileToExpression(algebra)(*arguments) - - -/** - * Create a compiled expression with given [MST] and given [algebra]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compileToExpression(algebra: DoubleField): DoubleExpression { - val typed = evaluateConstants(algebra) - - return if (typed is TypedMst.Constant) object : DoubleExpression { - override val indexer = SimpleSymbolIndexer(emptyList()) - - override fun invoke(arguments: DoubleArray): Double = typed.value - } else - DoubleAsmBuilder(typed).instance -} - - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: DoubleField, arguments: Map): Double = - compileToExpression(algebra)(arguments) - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: DoubleField, vararg arguments: Pair): Double = - compileToExpression(algebra)(*arguments) + compileToExpression(algebra).invoke(*arguments) diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt index a85079fc8..de7da30df 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt @@ -1,53 +1,349 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.asm.internal -import org.objectweb.asm.Type -import org.objectweb.asm.Type.getObjectType +import org.objectweb.asm.* +import org.objectweb.asm.Opcodes.* +import org.objectweb.asm.Type.* +import org.objectweb.asm.commons.InstructionAdapter +import space.kscience.kmath.asm.internal.AsmBuilder.ClassLoader import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.expressions.MST +import java.lang.invoke.MethodHandles +import java.lang.invoke.MethodType +import java.util.stream.Collectors.toMap +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract -internal abstract class AsmBuilder { +/** + * ASM Builder is a structure that abstracts building a class designated to unwrap [MST] to plain Java expression. + * This class uses [ClassLoader] for loading the generated class, then it is able to instantiate the new class. + * + * @property T the type of AsmExpression to unwrap. + * @property className the unique class name of new loaded class. + * @property callbackAtInvokeL0 the function to apply to this object when generating invoke method, label 0. + * @author Iaroslav Postovalov + */ +internal class AsmBuilder( + classOfT: Class<*>, + private val className: String, + private val callbackAtInvokeL0: AsmBuilder.() -> Unit, +) { /** - * Internal classloader with alias to define class from byte array. + * Internal classloader of [AsmBuilder] with alias to define class from byte array. */ - class ByteArrayClassLoader(parent: ClassLoader) : ClassLoader(parent) { + private class ClassLoader(parent: java.lang.ClassLoader) : java.lang.ClassLoader(parent) { fun defineClass(name: String?, b: ByteArray): Class<*> = defineClass(name, b, 0, b.size) } - protected val classLoader = ByteArrayClassLoader(javaClass.classLoader) + /** + * The instance of [ClassLoader] used by this builder. + */ + private val classLoader: ClassLoader = ClassLoader(javaClass.classLoader) + + /** + * ASM type for [T]. + */ + private val tType: Type = classOfT.asm + + /** + * ASM type for new class. + */ + private val classType: Type = getObjectType(className.replace(oldChar = '.', newChar = '/')) + + /** + * List of constants to provide to the subclass. + */ + private val constants: MutableList = mutableListOf() + + /** + * Method visitor of `invoke` method of the subclass. + */ + private lateinit var invokeMethodVisitor: InstructionAdapter + + /** + * Subclasses, loads and instantiates [Expression] for given parameters. + * + * The built instance is cached. + */ + @Suppress("UNCHECKED_CAST") + val instance: Expression by lazy { + val hasConstants: Boolean + + val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) { + visit( + V1_8, + ACC_PUBLIC or ACC_FINAL or ACC_SUPER, + classType.internalName, + "${OBJECT_TYPE.descriptor}L${EXPRESSION_TYPE.internalName}<${tType.descriptor}>;", + OBJECT_TYPE.internalName, + arrayOf(EXPRESSION_TYPE.internalName), + ) + + visitMethod( + ACC_PUBLIC or ACC_FINAL, + "invoke", + getMethodDescriptor(tType, MAP_TYPE), + "(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", + null, + ).instructionAdapter { + invokeMethodVisitor = this + visitCode() + val l0 = label() + callbackAtInvokeL0() + areturn(tType) + val l1 = label() + + visitLocalVariable( + "this", + classType.descriptor, + null, + l0, + l1, + 0, + ) + + visitLocalVariable( + "arguments", + MAP_TYPE.descriptor, + "L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${tType.descriptor}>;", + l0, + l1, + 1, + ) + + visitMaxs(0, 2) + visitEnd() + } + + visitMethod( + ACC_PUBLIC or ACC_FINAL or ACC_BRIDGE or ACC_SYNTHETIC, + "invoke", + getMethodDescriptor(OBJECT_TYPE, MAP_TYPE), + null, + null, + ).instructionAdapter { + visitCode() + val l0 = label() + load(0, OBJECT_TYPE) + load(1, MAP_TYPE) + invokevirtual(classType.internalName, "invoke", getMethodDescriptor(tType, MAP_TYPE), false) + areturn(tType) + val l1 = label() + + visitLocalVariable( + "this", + classType.descriptor, + null, + l0, + l1, + 0, + ) + + visitMaxs(0, 2) + visitEnd() + } + + hasConstants = constants.isNotEmpty() + + if (hasConstants) + visitField( + access = ACC_PRIVATE or ACC_FINAL, + name = "constants", + descriptor = OBJECT_ARRAY_TYPE.descriptor, + signature = null, + value = null, + block = FieldVisitor::visitEnd, + ) + + visitMethod( + ACC_PUBLIC, + "", + getMethodDescriptor(VOID_TYPE, *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }), + null, + null, + ).instructionAdapter { + val l0 = label() + load(0, classType) + invokespecial(OBJECT_TYPE.internalName, "", getMethodDescriptor(VOID_TYPE), false) + label() + load(0, classType) + + if (hasConstants) { + label() + load(0, classType) + load(1, OBJECT_ARRAY_TYPE) + putfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) + } + + label() + visitInsn(RETURN) + val l4 = label() + visitLocalVariable("this", classType.descriptor, null, l0, l4, 0) + + if (hasConstants) + visitLocalVariable("constants", OBJECT_ARRAY_TYPE.descriptor, null, l0, l4, 1) + + visitMaxs(0, 3) + visitEnd() + } + + visitEnd() + } + + val cls = classLoader.defineClass(className, classWriter.toByteArray()) + // java.io.File("dump.class").writeBytes(classWriter.toByteArray()) + val l = MethodHandles.publicLookup() + + if (hasConstants) + l.findConstructor(cls, MethodType.methodType(Void.TYPE, Array::class.java)) + .invoke(constants.toTypedArray()) as Expression + else + l.findConstructor(cls, MethodType.methodType(Void.TYPE)).invoke() as Expression + } + + /** + * Loads [java.lang.Object] constant from constants. + */ + fun loadObjectConstant(value: Any, type: Type = tType): Unit = invokeMethodVisitor.run { + val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex + invokeMethodVisitor.load(0, classType) + getfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) + iconst(idx) + visitInsn(AALOAD) + if (type != OBJECT_TYPE) checkcast(type) + } + + /** + * Either loads a numeric constant [value] from the class's constants field or boxes a primitive + * constant from the constant pool. + */ + fun loadNumberConstant(value: Number) { + val boxed = value.javaClass.asm + val primitive = BOXED_TO_PRIMITIVES[boxed] + + if (primitive != null) { + when (primitive) { + BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble()) + FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat()) + LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong()) + INT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) + } + + val r = PRIMITIVES_TO_BOXED.getValue(primitive) + + invokeMethodVisitor.invokestatic( + r.internalName, + "valueOf", + getMethodDescriptor(r, primitive), + false, + ) + + return + } + + loadObjectConstant(value, boxed) + } + + /** + * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. + */ + fun loadVariable(name: String): Unit = invokeMethodVisitor.run { + load(1, MAP_TYPE) + aconst(name) + + invokestatic( + MAP_INTRINSICS_TYPE.internalName, + "getOrFail", + getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE), + false, + ) + + checkcast(tType) + } + + inline fun buildCall(function: Function, parameters: AsmBuilder.() -> Unit) { + contract { callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) } + val `interface` = function.javaClass.interfaces.first { Function::class.java in it.interfaces } + + val arity = `interface`.methods.find { it.name == "invoke" }?.parameterCount + ?: error("Provided function object doesn't contain invoke method") + + val type = getType(`interface`) + loadObjectConstant(function, type) + parameters(this) + + invokeMethodVisitor.invokeinterface( + type.internalName, + "invoke", + getMethodDescriptor(OBJECT_TYPE, *Array(arity) { OBJECT_TYPE }), + ) + + invokeMethodVisitor.checkcast(tType) + } + + companion object { + /** + * Maps JVM primitive numbers boxed ASM types to their primitive ASM types. + */ + private val BOXED_TO_PRIMITIVES: Map by lazy { + hashMapOf( + Byte::class.java.asm to BYTE_TYPE, + Short::class.java.asm to SHORT_TYPE, + Integer::class.java.asm to INT_TYPE, + Long::class.java.asm to LONG_TYPE, + Float::class.java.asm to FLOAT_TYPE, + Double::class.java.asm to DOUBLE_TYPE, + ) + } + + /** + * Maps JVM primitive numbers boxed ASM types to their primitive ASM types. + */ + private val PRIMITIVES_TO_BOXED: Map by lazy { + BOXED_TO_PRIMITIVES.entries.stream().collect( + toMap(Map.Entry::value, Map.Entry::key), + ) + } - protected companion object { /** * ASM type for [Expression]. */ - val EXPRESSION_TYPE: Type = getObjectType("space/kscience/kmath/expressions/Expression") + val EXPRESSION_TYPE: Type by lazy { getObjectType("space/kscience/kmath/expressions/Expression") } /** * ASM type for [java.util.Map]. */ - val MAP_TYPE: Type = getObjectType("java/util/Map") + val MAP_TYPE: Type by lazy { getObjectType("java/util/Map") } /** * ASM type for [java.lang.Object]. */ - val OBJECT_TYPE: Type = getObjectType("java/lang/Object") + val OBJECT_TYPE: Type by lazy { getObjectType("java/lang/Object") } + + /** + * ASM type for array of [java.lang.Object]. + */ + val OBJECT_ARRAY_TYPE: Type by lazy { getType("[Ljava/lang/Object;") } /** * ASM type for [java.lang.String]. */ - val STRING_TYPE: Type = getObjectType("java/lang/String") + val STRING_TYPE: Type by lazy { getObjectType("java/lang/String") } /** * ASM type for MapIntrinsics. */ - val MAP_INTRINSICS_TYPE: Type = getObjectType("space/kscience/kmath/asm/internal/MapIntrinsics") + val MAP_INTRINSICS_TYPE: Type by lazy { getObjectType("space/kscience/kmath/asm/internal/MapIntrinsics") } /** * ASM Type for [space.kscience.kmath.expressions.Symbol]. */ - val SYMBOL_TYPE: Type = getObjectType("space/kscience/kmath/expressions/Symbol") + val SYMBOL_TYPE: Type by lazy { getObjectType("space/kscience/kmath/expressions/Symbol") } } } diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt deleted file mode 100644 index 6cf3d8721..000000000 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/GenericAsmBuilder.kt +++ /dev/null @@ -1,325 +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.asm.internal - -import org.objectweb.asm.* -import org.objectweb.asm.Opcodes.* -import org.objectweb.asm.Type.* -import org.objectweb.asm.commons.InstructionAdapter -import space.kscience.kmath.expressions.* -import java.lang.invoke.MethodHandles -import java.lang.invoke.MethodType -import java.nio.file.Paths -import java.util.stream.Collectors.toMap -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.io.path.writeBytes - -/** - * ASM Builder is a structure that abstracts building a class designated to unwrap [MST] to plain Java expression. - * This class uses [ClassLoader] for loading the generated class, then it is able to instantiate the new class. - * - * @property T the type of AsmExpression to unwrap. - * @property className the unique class name of new loaded class. - * @property expressionResultCallback the function to apply to this object when generating expression value. - * @author Iaroslav Postovalov - */ -internal class GenericAsmBuilder( - classOfT: Class<*>, - private val className: String, - private val variablesPrepareCallback: GenericAsmBuilder.() -> Unit, - private val expressionResultCallback: GenericAsmBuilder.() -> Unit, -) : AsmBuilder() { - /** - * ASM type for [T]. - */ - private val tType: Type = classOfT.asm - - /** - * ASM type for new class. - */ - private val classType: Type = getObjectType(className.replace(oldChar = '.', newChar = '/')) - - /** - * List of constants to provide to the subclass. - */ - private val constants = mutableListOf() - - /** - * Method visitor of `invoke` method of the subclass. - */ - private lateinit var invokeMethodVisitor: InstructionAdapter - - /** - * Local variables indices are indices of symbols in this list. - */ - private val argumentsLocals = mutableListOf() - - /** - * Subclasses, loads and instantiates [Expression] for given parameters. - * - * The built instance is cached. - */ - @Suppress("UNCHECKED_CAST", "UNUSED_VARIABLE") - val instance: Expression by lazy { - val hasConstants: Boolean - - val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) { - visit( - V1_8, - ACC_PUBLIC or ACC_FINAL or ACC_SUPER, - classType.internalName, - "${OBJECT_TYPE.descriptor}L${EXPRESSION_TYPE.internalName}<${tType.descriptor}>;", - OBJECT_TYPE.internalName, - arrayOf(EXPRESSION_TYPE.internalName), - ) - - visitMethod( - ACC_PUBLIC, - "invoke", - getMethodDescriptor(tType, MAP_TYPE), - "(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", - null, - ).instructionAdapter { - invokeMethodVisitor = this - visitCode() - val preparingVariables = label() - variablesPrepareCallback() - val expressionResult = label() - expressionResultCallback() - areturn(tType) - val end = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - preparingVariables, - end, - 0, - ) - - visitLocalVariable( - "arguments", - MAP_TYPE.descriptor, - "L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;", - preparingVariables, - end, - 1, - ) - - visitMaxs(0, 0) - visitEnd() - } - - visitMethod( - ACC_PUBLIC or ACC_BRIDGE or ACC_SYNTHETIC, - "invoke", - getMethodDescriptor(OBJECT_TYPE, MAP_TYPE), - null, - null, - ).instructionAdapter { - visitCode() - val start = label() - load(0, OBJECT_TYPE) - load(1, MAP_TYPE) - invokevirtual(classType.internalName, "invoke", getMethodDescriptor(tType, MAP_TYPE), false) - areturn(tType) - val end = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - start, - end, - 0, - ) - - visitMaxs(0, 0) - visitEnd() - } - - hasConstants = constants.isNotEmpty() - - if (hasConstants) - visitField( - access = ACC_PRIVATE or ACC_FINAL, - name = "constants", - descriptor = OBJECT_ARRAY_TYPE.descriptor, - signature = null, - value = null, - block = FieldVisitor::visitEnd, - ) - - visitMethod( - ACC_PUBLIC or ACC_SYNTHETIC, - "", - getMethodDescriptor(VOID_TYPE, *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }), - null, - null, - ).instructionAdapter { - val l0 = label() - load(0, classType) - invokespecial(OBJECT_TYPE.internalName, "", getMethodDescriptor(VOID_TYPE), false) - label() - load(0, classType) - - if (hasConstants) { - label() - load(0, classType) - load(1, OBJECT_ARRAY_TYPE) - putfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) - } - - label() - areturn(VOID_TYPE) - val l4 = label() - visitLocalVariable("this", classType.descriptor, null, l0, l4, 0) - - if (hasConstants) - visitLocalVariable("constants", OBJECT_ARRAY_TYPE.descriptor, null, l0, l4, 1) - - visitMaxs(0, 0) - visitEnd() - } - - visitEnd() - } - - val binary = classWriter.toByteArray() - val cls = classLoader.defineClass(className, binary) - - if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1") - Paths.get("${className.split('.').last()}.class").writeBytes(binary) - - val l = MethodHandles.publicLookup() - - (if (hasConstants) - l.findConstructor(cls, MethodType.methodType(Void.TYPE, Array::class.java))(constants.toTypedArray()) - else - l.findConstructor(cls, MethodType.methodType(Void.TYPE))()) as Expression - } - - /** - * Loads [java.lang.Object] constant from constants. - */ - fun loadObjectConstant(value: Any, type: Type = tType): Unit = invokeMethodVisitor.run { - val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex - load(0, classType) - getfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) - iconst(idx) - aload(OBJECT_TYPE) - if (type != OBJECT_TYPE) checkcast(type) - } - - /** - * Either loads a numeric constant [value] from the class's constants field or boxes a primitive - * constant from the constant pool. - */ - fun loadNumberConstant(value: Number) { - val boxed = value.javaClass.asm - val primitive = BOXED_TO_PRIMITIVES[boxed] - - if (primitive != null) { - when (primitive) { - BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble()) - FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat()) - LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong()) - INT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - } - - val r = boxed - - invokeMethodVisitor.invokestatic( - r.internalName, - "valueOf", - getMethodDescriptor(r, primitive), - false, - ) - - return - } - - loadObjectConstant(value, boxed) - } - - /** - * Stores value variable [name] into a local. Should be called within [variablesPrepareCallback] before using - * [loadVariable]. - */ - fun prepareVariable(name: Symbol): Unit = invokeMethodVisitor.run { - if (name in argumentsLocals) return@run - load(1, MAP_TYPE) - aconst(name.identity) - - invokestatic( - MAP_INTRINSICS_TYPE.internalName, - "getOrFail", - getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE), - false, - ) - - checkcast(tType) - var idx = argumentsLocals.indexOf(name) - - if (idx == -1) { - argumentsLocals += name - idx = argumentsLocals.lastIndex - } - - store(2 + idx, tType) - } - - /** - * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. The variable should be stored - * with [prepareVariable] first. - */ - fun loadVariable(name: Symbol): Unit = invokeMethodVisitor.load(2 + argumentsLocals.indexOf(name), tType) - - inline fun buildCall(function: Function, parameters: GenericAsmBuilder.() -> Unit) { - contract { callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) } - val `interface` = function.javaClass.interfaces.first { Function::class.java in it.interfaces } - - val arity = `interface`.methods.find { it.name == "invoke" }?.parameterCount - ?: error("Provided function object doesn't contain invoke method") - - val type = getType(`interface`) - loadObjectConstant(function, type) - parameters(this) - - invokeMethodVisitor.invokeinterface( - type.internalName, - "invoke", - getMethodDescriptor(OBJECT_TYPE, *Array(arity) { OBJECT_TYPE }), - ) - - invokeMethodVisitor.checkcast(tType) - } - - private companion object { - /** - * Maps JVM primitive numbers boxed ASM types to their primitive ASM types. - */ - private val BOXED_TO_PRIMITIVES: Map by lazy { - hashMapOf( - Byte::class.java.asm to BYTE_TYPE, - Short::class.java.asm to SHORT_TYPE, - Integer::class.java.asm to INT_TYPE, - Long::class.java.asm to LONG_TYPE, - Float::class.java.asm to FLOAT_TYPE, - Double::class.java.asm to DOUBLE_TYPE, - ) - } - - /** - * ASM type for array of [java.lang.Object]. - */ - val OBJECT_ARRAY_TYPE: Type = getType("[Ljava/lang/Object;") - } -} 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 deleted file mode 100644 index 01bad83e5..000000000 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/PrimitiveAsmBuilder.kt +++ /dev/null @@ -1,516 +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.asm.internal - -import org.objectweb.asm.ClassWriter -import org.objectweb.asm.FieldVisitor -import org.objectweb.asm.Opcodes.* -import org.objectweb.asm.Type -import org.objectweb.asm.Type.* -import org.objectweb.asm.commons.InstructionAdapter -import space.kscience.kmath.ast.TypedMst -import space.kscience.kmath.expressions.* -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import java.lang.invoke.MethodHandles -import java.lang.invoke.MethodType -import java.nio.file.Paths -import kotlin.io.path.writeBytes - -@UnstableKMathAPI -internal sealed class PrimitiveAsmBuilder>( - protected val algebra: NumericAlgebra, - classOfT: Class<*>, - protected val classOfTPrimitive: Class<*>, - expressionParent: Class, - protected val target: TypedMst, -) : AsmBuilder() { - private val className: String = buildName("${target.hashCode()}_${classOfT.simpleName}") - - /** - * ASM type for [tType]. - */ - private val tType: Type = classOfT.asm - - /** - * ASM type for [classOfTPrimitive]. - */ - protected val tTypePrimitive: Type = classOfTPrimitive.asm - - /** - * ASM type for array of [classOfTPrimitive]. - */ - protected val tTypePrimitiveArray: Type = getType("[" + classOfTPrimitive.asm.descriptor) - - /** - * ASM type for expression parent. - */ - private val expressionParentType = expressionParent.asm - - /** - * ASM type for new class. - */ - private val classType: Type = getObjectType(className.replace(oldChar = '.', newChar = '/')) - - /** - * Method visitor of `invoke` method of the subclass. - */ - protected lateinit var invokeMethodVisitor: InstructionAdapter - - /** - * Indexer for arguments in [target]. - */ - private val argumentsIndexer = mutableListOf() - - /** - * Subclasses, loads and instantiates [Expression] for given parameters. - * - * The built instance is cached. - */ - @Suppress("UNCHECKED_CAST") - val instance: E by lazy { - val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) { - visit( - V1_8, - ACC_PUBLIC or ACC_FINAL or ACC_SUPER, - classType.internalName, - "${OBJECT_TYPE.descriptor}${expressionParentType.descriptor}", - OBJECT_TYPE.internalName, - arrayOf(expressionParentType.internalName), - ) - - visitField( - access = ACC_PRIVATE or ACC_FINAL, - name = "indexer", - descriptor = SYMBOL_INDEXER_TYPE.descriptor, - signature = null, - value = null, - block = FieldVisitor::visitEnd, - ) - visitMethod( - ACC_PUBLIC, - "getIndexer", - getMethodDescriptor(SYMBOL_INDEXER_TYPE), - null, - null, - ).instructionAdapter { - visitCode() - val start = label() - load(0, classType) - getfield(classType.internalName, "indexer", SYMBOL_INDEXER_TYPE.descriptor) - areturn(SYMBOL_INDEXER_TYPE) - val end = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - start, - end, - 0, - ) - - visitMaxs(0, 0) - visitEnd() - } - - visitMethod( - ACC_PUBLIC, - "invoke", - getMethodDescriptor(tTypePrimitive, tTypePrimitiveArray), - null, - null, - ).instructionAdapter { - invokeMethodVisitor = this - visitCode() - val start = label() - visitVariables(target, arrayMode = true) - visitExpression(target) - areturn(tTypePrimitive) - val end = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - start, - end, - 0, - ) - - visitLocalVariable( - "arguments", - tTypePrimitiveArray.descriptor, - null, - start, - end, - 1, - ) - - visitMaxs(0, 0) - visitEnd() - } - - visitMethod( - ACC_PUBLIC or ACC_FINAL, - "invoke", - getMethodDescriptor(tType, MAP_TYPE), - "(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", - null, - ).instructionAdapter { - invokeMethodVisitor = this - visitCode() - val start = label() - visitVariables(target, arrayMode = false) - visitExpression(target) - box() - areturn(tType) - val end = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - start, - end, - 0, - ) - - visitLocalVariable( - "arguments", - MAP_TYPE.descriptor, - "L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;", - start, - end, - 1, - ) - - visitMaxs(0, 0) - visitEnd() - } - - visitMethod( - ACC_PUBLIC or ACC_FINAL or ACC_BRIDGE or ACC_SYNTHETIC, - "invoke", - getMethodDescriptor(OBJECT_TYPE, MAP_TYPE), - null, - null, - ).instructionAdapter { - visitCode() - val start = label() - load(0, OBJECT_TYPE) - load(1, MAP_TYPE) - invokevirtual(classType.internalName, "invoke", getMethodDescriptor(tType, MAP_TYPE), false) - areturn(tType) - val end = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - start, - end, - 0, - ) - - visitMaxs(0, 0) - visitEnd() - } - - visitMethod( - ACC_PUBLIC or ACC_SYNTHETIC, - "", - getMethodDescriptor(VOID_TYPE, SYMBOL_INDEXER_TYPE), - null, - null, - ).instructionAdapter { - val start = label() - load(0, classType) - invokespecial(OBJECT_TYPE.internalName, "", getMethodDescriptor(VOID_TYPE), false) - load(0, classType) - load(1, SYMBOL_INDEXER_TYPE) - putfield(classType.internalName, "indexer", SYMBOL_INDEXER_TYPE.descriptor) - areturn(VOID_TYPE) - val end = label() - visitLocalVariable("this", classType.descriptor, null, start, end, 0) - visitLocalVariable("indexer", SYMBOL_INDEXER_TYPE.descriptor, null, start, end, 1) - visitMaxs(0, 0) - visitEnd() - } - - visitEnd() - } - - val binary = classWriter.toByteArray() - val cls = classLoader.defineClass(className, binary) - - if (System.getProperty("space.kscience.kmath.ast.dump.generated.classes") == "1") - Paths.get("${className.split('.').last()}.class").writeBytes(binary) - - MethodHandles - .publicLookup() - .findConstructor(cls, MethodType.methodType(Void.TYPE, SymbolIndexer::class.java)) - .invoke(SimpleSymbolIndexer(argumentsIndexer)) as E - } - - /** - * Loads a numeric constant [value] from the class's constants. - */ - protected fun loadNumberConstant(value: Number) { - when (tTypePrimitive) { - BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble()) - FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat()) - LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong()) - INT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - } - } - - /** - * Stores value variable [name] into a local. Should be called before using [loadVariable]. Should be called only - * once for a variable. - */ - protected fun prepareVariable(name: Symbol, arrayMode: Boolean): Unit = invokeMethodVisitor.run { - var argumentIndex = argumentsIndexer.indexOf(name) - - if (argumentIndex == -1) { - argumentsIndexer += name - argumentIndex = argumentsIndexer.lastIndex - } - - val localIndex = 2 + argumentIndex * tTypePrimitive.size - - if (arrayMode) { - load(1, tTypePrimitiveArray) - iconst(argumentIndex) - aload(tTypePrimitive) - store(localIndex, tTypePrimitive) - } else { - load(1, MAP_TYPE) - aconst(name.identity) - - invokestatic( - MAP_INTRINSICS_TYPE.internalName, - "getOrFail", - getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE), - false, - ) - - checkcast(tType) - unbox() - store(localIndex, tTypePrimitive) - } - } - - /** - * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. The variable should be stored - * with [prepareVariable] first. - */ - protected fun loadVariable(name: Symbol) { - val argumentIndex = argumentsIndexer.indexOf(name) - val localIndex = 2 + argumentIndex * tTypePrimitive.size - invokeMethodVisitor.load(localIndex, tTypePrimitive) - } - - private fun unbox() = invokeMethodVisitor.run { - invokevirtual( - NUMBER_TYPE.internalName, - "${classOfTPrimitive.simpleName}Value", - getMethodDescriptor(tTypePrimitive), - false - ) - } - - private fun box() = invokeMethodVisitor.run { - invokestatic(tType.internalName, "valueOf", getMethodDescriptor(tType, tTypePrimitive), false) - } - - private fun visitVariables( - node: TypedMst, - arrayMode: Boolean, - alreadyLoaded: MutableList = mutableListOf() - ): Unit = when (node) { - is TypedMst.Variable -> if (node.symbol !in alreadyLoaded) { - alreadyLoaded += node.symbol - prepareVariable(node.symbol, arrayMode) - } else Unit - - is TypedMst.Unary -> visitVariables(node.value, arrayMode, alreadyLoaded) - - is TypedMst.Binary -> { - visitVariables(node.left, arrayMode, alreadyLoaded) - visitVariables(node.right, arrayMode, alreadyLoaded) - } - - is TypedMst.Constant -> Unit - } - - private fun visitExpression(node: TypedMst): Unit = when (node) { - is TypedMst.Variable -> loadVariable(node.symbol) - - is TypedMst.Constant -> loadNumberConstant( - node.number ?: error("Object constants are not supported by pritimive ASM builder"), - ) - - is TypedMst.Unary -> visitUnary(node) - is TypedMst.Binary -> visitBinary(node) - } - - protected open fun visitUnary(node: TypedMst.Unary) = visitExpression(node.value) - - protected open fun visitBinary(node: TypedMst.Binary) { - visitExpression(node.left) - visitExpression(node.right) - } - - protected companion object { - /** - * ASM type for [java.lang.Number]. - */ - val NUMBER_TYPE: Type = getObjectType("java/lang/Number") - - /** - * ASM type for [SymbolIndexer]. - */ - val SYMBOL_INDEXER_TYPE: Type = getObjectType("space/kscience/kmath/expressions/SymbolIndexer") - } -} - -@UnstableKMathAPI -internal class DoubleAsmBuilder(target: TypedMst) : PrimitiveAsmBuilder( - DoubleField, - java.lang.Double::class.java, - java.lang.Double.TYPE, - DoubleExpression::class.java, - target, -) { - private fun buildUnaryJavaMathCall(name: String) = invokeMethodVisitor.invokestatic( - MATH_TYPE.internalName, - name, - getMethodDescriptor(tTypePrimitive, tTypePrimitive), - false, - ) - - @Suppress("SameParameterValue") - private fun buildBinaryJavaMathCall(name: String) = invokeMethodVisitor.invokestatic( - MATH_TYPE.internalName, - name, - getMethodDescriptor(tTypePrimitive, tTypePrimitive, tTypePrimitive), - false, - ) - - private fun buildUnaryKotlinMathCall(name: String) = invokeMethodVisitor.invokestatic( - MATH_KT_TYPE.internalName, - name, - getMethodDescriptor(tTypePrimitive, tTypePrimitive), - false, - ) - - override fun visitUnary(node: TypedMst.Unary) { - super.visitUnary(node) - - when (node.operation) { - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(DNEG) - GroupOps.PLUS_OPERATION -> Unit - PowerOperations.SQRT_OPERATION -> buildUnaryJavaMathCall("sqrt") - TrigonometricOperations.SIN_OPERATION -> buildUnaryJavaMathCall("sin") - TrigonometricOperations.COS_OPERATION -> buildUnaryJavaMathCall("cos") - TrigonometricOperations.TAN_OPERATION -> buildUnaryJavaMathCall("tan") - TrigonometricOperations.ASIN_OPERATION -> buildUnaryJavaMathCall("asin") - TrigonometricOperations.ACOS_OPERATION -> buildUnaryJavaMathCall("acos") - TrigonometricOperations.ATAN_OPERATION -> buildUnaryJavaMathCall("atan") - ExponentialOperations.SINH_OPERATION -> buildUnaryJavaMathCall("sqrt") - ExponentialOperations.COSH_OPERATION -> buildUnaryJavaMathCall("cosh") - ExponentialOperations.TANH_OPERATION -> buildUnaryJavaMathCall("tanh") - ExponentialOperations.ASINH_OPERATION -> buildUnaryKotlinMathCall("asinh") - ExponentialOperations.ACOSH_OPERATION -> buildUnaryKotlinMathCall("acosh") - ExponentialOperations.ATANH_OPERATION -> buildUnaryKotlinMathCall("atanh") - ExponentialOperations.EXP_OPERATION -> buildUnaryJavaMathCall("exp") - ExponentialOperations.LN_OPERATION -> buildUnaryJavaMathCall("log") - else -> super.visitUnary(node) - } - } - - override fun visitBinary(node: TypedMst.Binary) { - super.visitBinary(node) - - when (node.operation) { - GroupOps.PLUS_OPERATION -> invokeMethodVisitor.visitInsn(DADD) - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(DSUB) - RingOps.TIMES_OPERATION -> invokeMethodVisitor.visitInsn(DMUL) - FieldOps.DIV_OPERATION -> invokeMethodVisitor.visitInsn(DDIV) - PowerOperations.POW_OPERATION -> buildBinaryJavaMathCall("pow") - else -> super.visitBinary(node) - } - } - - private companion object { - val MATH_TYPE: Type = getObjectType("java/lang/Math") - val MATH_KT_TYPE: Type = getObjectType("kotlin/math/MathKt") - } -} - -@UnstableKMathAPI -internal class IntAsmBuilder(target: TypedMst) : - PrimitiveAsmBuilder( - IntRing, - Integer::class.java, - Integer.TYPE, - IntExpression::class.java, - target - ) { - override fun visitUnary(node: TypedMst.Unary) { - super.visitUnary(node) - - when (node.operation) { - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(INEG) - GroupOps.PLUS_OPERATION -> Unit - else -> super.visitUnary(node) - } - } - - override fun visitBinary(node: TypedMst.Binary) { - super.visitBinary(node) - - when (node.operation) { - GroupOps.PLUS_OPERATION -> invokeMethodVisitor.visitInsn(IADD) - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(ISUB) - RingOps.TIMES_OPERATION -> invokeMethodVisitor.visitInsn(IMUL) - else -> super.visitBinary(node) - } - } -} - -@UnstableKMathAPI -internal class LongAsmBuilder(target: TypedMst) : PrimitiveAsmBuilder( - LongRing, - java.lang.Long::class.java, - java.lang.Long.TYPE, - LongExpression::class.java, - target, -) { - override fun visitUnary(node: TypedMst.Unary) { - super.visitUnary(node) - - when (node.operation) { - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(LNEG) - GroupOps.PLUS_OPERATION -> Unit - else -> super.visitUnary(node) - } - } - - override fun visitBinary(node: TypedMst.Binary) { - super.visitBinary(node) - - when (node.operation) { - GroupOps.PLUS_OPERATION -> invokeMethodVisitor.visitInsn(LADD) - GroupOps.MINUS_OPERATION -> invokeMethodVisitor.visitInsn(LSUB) - RingOps.TIMES_OPERATION -> invokeMethodVisitor.visitInsn(LMUL) - else -> super.visitBinary(node) - } - } -} diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt index 9e880f4fc..5e2e7d8c6 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.asm.internal @@ -55,15 +55,15 @@ internal inline fun MethodVisitor.instructionAdapter(block: InstructionAdapter.( internal fun MethodVisitor.label(): Label = Label().also(::visitLabel) /** - * Creates a class name for [Expression] based with appending [marker] to reduce collisions. + * Creates a class name for [Expression] subclassed to implement [mst] provided. * * These methods help to avoid collisions of class name to prevent loading several classes with the same name. If there * is a colliding class, change [collision] parameter or leave it `0` to check existing classes recursively. * * @author Iaroslav Postovalov */ -internal tailrec fun buildName(marker: String, collision: Int = 0): String { - val name = "space.kscience.kmath.asm.generated.CompiledExpression_${marker}_$collision" +internal tailrec fun buildName(mst: MST, collision: Int = 0): String { + val name = "space.kscience.kmath.asm.generated.CompiledExpression_${mst.hashCode()}_$collision" try { Class.forName(name) @@ -71,7 +71,7 @@ internal tailrec fun buildName(marker: String, collision: Int = 0): String { return name } - return buildName(marker, collision + 1) + return buildName(mst, collision + 1) } @Suppress("FunctionName") diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt index 3a5ef74f7..56cfa4cbf 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt @@ -1,12 +1,13 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ @file:JvmName("MapIntrinsics") package space.kscience.kmath.asm.internal +import space.kscience.kmath.expressions.StringSymbol import space.kscience.kmath.expressions.Symbol /** @@ -14,5 +15,4 @@ import space.kscience.kmath.expressions.Symbol * * @author Iaroslav Postovalov */ -@Suppress("unused") -internal fun Map.getOrFail(key: String): V = getValue(Symbol(key)) +internal fun Map.getOrFail(key: String): V = getValue(StringSymbol(key)) diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt index 556adbe7d..3e5253084 100644 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt +++ b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast.rendering diff --git a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt index 47f1cc476..a0bdd68a0 100644 --- a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt +++ b/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ast @@ -8,7 +8,6 @@ package space.kscience.kmath.ast import space.kscience.kmath.expressions.Expression import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing import kotlin.contracts.InvocationKind @@ -16,21 +15,7 @@ import kotlin.contracts.contract import space.kscience.kmath.asm.compile as asmCompile import space.kscience.kmath.asm.compileToExpression as asmCompileToExpression -private object GenericAsmCompilerTestContext : CompilerTestContext { - override fun MST.compileToExpression(algebra: IntRing): Expression = - asmCompileToExpression(algebra as Algebra) - - override fun MST.compile(algebra: IntRing, arguments: Map): Int = - asmCompile(algebra as Algebra, arguments) - - override fun MST.compileToExpression(algebra: DoubleField): Expression = - asmCompileToExpression(algebra as Algebra) - - override fun MST.compile(algebra: DoubleField, arguments: Map): Double = - asmCompile(algebra as Algebra, arguments) -} - -private object PrimitiveAsmCompilerTestContext : CompilerTestContext { +private object AsmCompilerTestContext : CompilerTestContext { override fun MST.compileToExpression(algebra: IntRing): Expression = asmCompileToExpression(algebra) override fun MST.compile(algebra: IntRing, arguments: Map): Int = asmCompile(algebra, arguments) override fun MST.compileToExpression(algebra: DoubleField): Expression = asmCompileToExpression(algebra) @@ -39,9 +24,7 @@ private object PrimitiveAsmCompilerTestContext : CompilerTestContext { asmCompile(algebra, arguments) } - internal actual inline fun runCompilerTest(action: CompilerTestContext.() -> Unit) { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - action(GenericAsmCompilerTestContext) - action(PrimitiveAsmCompilerTestContext) + action(AsmCompilerTestContext) } diff --git a/kmath-commons/README.md b/kmath-commons/README.md deleted file mode 100644 index a17a39205..000000000 --- a/kmath-commons/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-commons - -Commons math binding for kmath - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-commons:0.3.0-dev-20`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-commons:0.3.0-dev-20' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-commons:0.3.0-dev-20") -} -``` diff --git a/kmath-commons/build.gradle.kts b/kmath-commons/build.gradle.kts index 96c17a215..a208c956c 100644 --- a/kmath-commons/build.gradle.kts +++ b/kmath-commons/build.gradle.kts @@ -9,7 +9,6 @@ dependencies { api(project(":kmath-core")) api(project(":kmath-complex")) api(project(":kmath-coroutines")) - api(project(":kmath-optimization")) api(project(":kmath-stat")) api(project(":kmath-functions")) api("org.apache.commons:commons-math3:3.6.1") diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt index 82694d95a..8fafabf19 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.commons.expressions @@ -9,7 +9,7 @@ import org.apache.commons.math3.analysis.differentiation.DerivativeStructure import space.kscience.kmath.expressions.* import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.NumbersAddOps +import space.kscience.kmath.operations.NumbersAddOperations /** * A field over commons-math [DerivativeStructure]. @@ -22,7 +22,7 @@ public class DerivativeStructureField( public val order: Int, bindings: Map, ) : ExtendedField, ExpressionAlgebra, - NumbersAddOps { + NumbersAddOperations { public val numberOfVariables: Int = bindings.size override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) } @@ -70,12 +70,12 @@ public class DerivativeStructureField( override fun DerivativeStructure.unaryMinus(): DerivativeStructure = negate() - override fun add(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure = left.add(right) + override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b) override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure = a.multiply(value) - override fun multiply(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure = left.multiply(right) - override fun divide(left: DerivativeStructure, right: DerivativeStructure): DerivativeStructure = left.divide(right) + override fun multiply(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.multiply(b) + override fun divide(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.divide(b) override fun sin(arg: DerivativeStructure): DerivativeStructure = arg.sin() override fun cos(arg: DerivativeStructure): DerivativeStructure = arg.cos() override fun tan(arg: DerivativeStructure): DerivativeStructure = arg.tan() @@ -99,19 +99,16 @@ public class DerivativeStructureField( override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.exp() override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.log() - override operator fun DerivativeStructure.plus(other: Number): DerivativeStructure = add(other.toDouble()) - override operator fun DerivativeStructure.minus(other: Number): DerivativeStructure = subtract(other.toDouble()) - override operator fun Number.plus(other: DerivativeStructure): DerivativeStructure = other + this - override operator fun Number.minus(other: DerivativeStructure): DerivativeStructure = other - this -} + override operator fun DerivativeStructure.plus(b: Number): DerivativeStructure = add(b.toDouble()) + override operator fun DerivativeStructure.minus(b: Number): DerivativeStructure = subtract(b.toDouble()) + override operator fun Number.plus(b: DerivativeStructure): DerivativeStructure = b + this + override operator fun Number.minus(b: DerivativeStructure): DerivativeStructure = b - this -/** - * Auto-diff processor based on Commons-math [DerivativeStructure] - */ -public object DSProcessor : AutoDiffProcessor { - override fun differentiate( - function: DerivativeStructureField.() -> DerivativeStructure, - ): DerivativeStructureExpression = DerivativeStructureExpression(function) + public companion object : + AutoDiffProcessor> { + override fun process(function: DerivativeStructureField.() -> DerivativeStructure): DifferentiableExpression = + DerivativeStructureExpression(function) + } } /** diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt index e0a2f4931..58b69b3d8 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.commons.integration @@ -16,7 +16,7 @@ public class CMGaussRuleIntegrator( private var type: GaussRule = GaussRule.LEGANDRE, ) : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { + override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { val range = integrand.getFeature()?.range ?: error("Integration range is not provided") val integrator: GaussIntegrator = getIntegrator(range) @@ -76,8 +76,8 @@ public class CMGaussRuleIntegrator( numPoints: Int = 100, type: GaussRule = GaussRule.LEGANDRE, function: (Double) -> Double, - ): Double = CMGaussRuleIntegrator(numPoints, type).process( + ): Double = CMGaussRuleIntegrator(numPoints, type).integrate( UnivariateIntegrand(function, IntegrationRange(range)) - ).value + ).valueOrNull!! } } \ No newline at end of file diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt index 257429fa7..ee7bda251 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.commons.integration @@ -18,7 +18,7 @@ public class CMIntegrator( public val integratorBuilder: (Integrand) -> org.apache.commons.math3.analysis.integration.UnivariateIntegrator, ) : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { + override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { val integrator = integratorBuilder(integrand) val maxCalls = integrand.getFeature()?.maxCalls ?: defaultMaxCalls val remainingCalls = maxCalls - integrand.calls diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt index aa7e0a638..3f8dccf27 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.commons.linear @@ -10,7 +10,6 @@ import space.kscience.kmath.linear.* import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureFeature import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer import kotlin.reflect.KClass import kotlin.reflect.cast @@ -22,15 +21,12 @@ public class CMMatrix(public val origin: RealMatrix) : Matrix { override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j) } -@JvmInline -public value class CMVector(public val origin: RealVector) : Point { +public class CMVector(public val origin: RealVector) : Point { override val size: Int get() = origin.dimension override operator fun get(index: Int): Double = origin.getEntry(index) override operator fun iterator(): Iterator = origin.toArray().iterator() - - override fun toString(): String = Buffer.toString(this) } public fun RealVector.toPoint(): CMVector = CMVector(this) @@ -99,7 +95,7 @@ public object CMLinearSpace : LinearSpace { v * this @UnstableKMathAPI - override fun computeFeature(structure: Matrix, type: KClass): F? { + override fun getFeature(structure: Matrix, type: KClass): F? { //Return the feature if it is intrinsic to the structure structure.getFeature(type)?.let { return it } @@ -113,22 +109,22 @@ public object CMLinearSpace : LinearSpace { LupDecompositionFeature { private val lup by lazy { LUDecomposition(origin) } override val determinant: Double by lazy { lup.determinant } - override val l: Matrix by lazy> { CMMatrix(lup.l).withFeature(LFeature) } - override val u: Matrix by lazy> { CMMatrix(lup.u).withFeature(UFeature) } + override val l: Matrix by lazy { CMMatrix(lup.l) + LFeature } + override val u: Matrix by lazy { CMMatrix(lup.u) + UFeature } override val p: Matrix by lazy { CMMatrix(lup.p) } } CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy> { + override val l: Matrix by lazy { val cholesky = CholeskyDecomposition(origin) - CMMatrix(cholesky.l).withFeature(LFeature) + CMMatrix(cholesky.l) + LFeature } } QRDecompositionFeature::class -> object : QRDecompositionFeature { private val qr by lazy { QRDecomposition(origin) } - override val q: Matrix by lazy> { CMMatrix(qr.q).withFeature(OrthogonalFeature) } - override val r: Matrix by lazy> { CMMatrix(qr.r).withFeature(UFeature) } + override val q: Matrix by lazy { CMMatrix(qr.q) + OrthogonalFeature } + override val r: Matrix by lazy { CMMatrix(qr.r) + UFeature } } SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt index 9bb5deffd..c5144c482 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt @@ -1,12 +1,11 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.commons.linear import org.apache.commons.math3.linear.* -import space.kscience.kmath.linear.LinearSolver import space.kscience.kmath.linear.Matrix import space.kscience.kmath.linear.Point @@ -18,7 +17,7 @@ public enum class CMDecomposition { CHOLESKY } -private fun CMLinearSpace.solver( +public fun CMLinearSpace.solver( a: Matrix, decomposition: CMDecomposition = CMDecomposition.LUP, ): DecompositionSolver = when (decomposition) { @@ -45,14 +44,3 @@ public fun CMLinearSpace.inverse( a: Matrix, decomposition: CMDecomposition = CMDecomposition.LUP, ): CMMatrix = solver(a, decomposition).inverse.wrap() - - -public fun CMLinearSpace.solver(decomposition: CMDecomposition): LinearSolver = object : LinearSolver { - override fun solve(a: Matrix, b: Matrix): Matrix = solver(a, decomposition).solve(b.toCM().origin).wrap() - - override fun solve(a: Matrix, b: Point): Point = solver(a, decomposition).solve(b.toCM().origin).toPoint() - - override fun inverse(matrix: Matrix): Matrix = solver(matrix, decomposition).inverse.wrap() -} - -public fun CMLinearSpace.lupSolver(): LinearSolver = solver((CMDecomposition.LUP)) \ No newline at end of file diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt new file mode 100644 index 000000000..03a1abafb --- /dev/null +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt @@ -0,0 +1,126 @@ +/* + * 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 file. + */ + +package space.kscience.kmath.commons.optimization + +import org.apache.commons.math3.optim.* +import org.apache.commons.math3.optim.nonlinear.scalar.GoalType +import org.apache.commons.math3.optim.nonlinear.scalar.MultivariateOptimizer +import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction +import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunctionGradient +import org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjugateGradientOptimizer +import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.AbstractSimplex +import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex +import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer +import space.kscience.kmath.expressions.* +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.optimization.* +import kotlin.collections.set +import kotlin.reflect.KClass + +public operator fun PointValuePair.component1(): DoubleArray = point +public operator fun PointValuePair.component2(): Double = value + +@OptIn(UnstableKMathAPI::class) +public class CMOptimization( + override val symbols: List, +) : FunctionOptimization, NoDerivFunctionOptimization, SymbolIndexer, OptimizationFeature { + + private val optimizationData: HashMap, OptimizationData> = HashMap() + private var optimizerBuilder: (() -> MultivariateOptimizer)? = null + public var convergenceChecker: ConvergenceChecker = SimpleValueChecker( + DEFAULT_RELATIVE_TOLERANCE, + DEFAULT_ABSOLUTE_TOLERANCE, + DEFAULT_MAX_ITER + ) + + override var maximize: Boolean + get() = optimizationData[GoalType::class] == GoalType.MAXIMIZE + set(value) { + optimizationData[GoalType::class] = if (value) GoalType.MAXIMIZE else GoalType.MINIMIZE + } + + public fun addOptimizationData(data: OptimizationData) { + optimizationData[data::class] = data + } + + init { + addOptimizationData(MaxEval.unlimited()) + } + + public fun exportOptimizationData(): List = optimizationData.values.toList() + + override fun initialGuess(map: Map) { + addOptimizationData(InitialGuess(map.toDoubleArray())) + } + + override fun function(expression: Expression) { + val objectiveFunction = ObjectiveFunction { + val args = it.toMap() + expression(args) + } + addOptimizationData(objectiveFunction) + } + + override fun diffFunction(expression: DifferentiableExpression) { + function(expression) + val gradientFunction = ObjectiveFunctionGradient { + val args = it.toMap() + DoubleArray(symbols.size) { index -> + expression.derivative(symbols[index])(args) + } + } + addOptimizationData(gradientFunction) + if (optimizerBuilder == null) { + optimizerBuilder = { + NonLinearConjugateGradientOptimizer( + NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES, + convergenceChecker + ) + } + } + } + + public fun simplex(simplex: AbstractSimplex) { + addOptimizationData(simplex) + //Set optimization builder to simplex if it is not present + if (optimizerBuilder == null) { + optimizerBuilder = { SimplexOptimizer(convergenceChecker) } + } + } + + public fun simplexSteps(steps: Map) { + simplex(NelderMeadSimplex(steps.toDoubleArray())) + } + + public fun goal(goalType: GoalType) { + addOptimizationData(goalType) + } + + public fun optimizer(block: () -> MultivariateOptimizer) { + optimizerBuilder = block + } + + override fun update(result: OptimizationResult) { + initialGuess(result.point) + } + + override fun optimize(): OptimizationResult { + val optimizer = optimizerBuilder?.invoke() ?: error("Optimizer not defined") + val (point, value) = optimizer.optimize(*optimizationData.values.toTypedArray()) + return OptimizationResult(point.toMap(), value, setOf(this)) + } + + public companion object : OptimizationProblemFactory { + public const val DEFAULT_RELATIVE_TOLERANCE: Double = 1e-4 + public const val DEFAULT_ABSOLUTE_TOLERANCE: Double = 1e-4 + public const val DEFAULT_MAX_ITER: Int = 1000 + + override fun build(symbols: List): CMOptimization = CMOptimization(symbols) + } +} + +public fun CMOptimization.initialGuess(vararg pairs: Pair): Unit = initialGuess(pairs.toMap()) +public fun CMOptimization.simplexSteps(vararg pairs: Pair): Unit = simplexSteps(pairs.toMap()) diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt deleted file mode 100644 index 11eb6fba8..000000000 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimizer.kt +++ /dev/null @@ -1,145 +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. - */ -@file:OptIn(UnstableKMathAPI::class) -package space.kscience.kmath.commons.optimization - -import org.apache.commons.math3.optim.* -import org.apache.commons.math3.optim.nonlinear.scalar.GoalType -import org.apache.commons.math3.optim.nonlinear.scalar.MultivariateOptimizer -import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction -import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunctionGradient -import org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjugateGradientOptimizer -import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex -import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer -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.misc.UnstableKMathAPI -import space.kscience.kmath.misc.log -import space.kscience.kmath.optimization.* -import kotlin.collections.set -import kotlin.reflect.KClass - -public operator fun PointValuePair.component1(): DoubleArray = point -public operator fun PointValuePair.component2(): Double = value - -public class CMOptimizerEngine(public val optimizerBuilder: () -> MultivariateOptimizer) : OptimizationFeature { - override fun toString(): String = "CMOptimizer($optimizerBuilder)" -} - -/** - * Specify a Commons-maths optimization engine - */ -public fun FunctionOptimizationBuilder.cmEngine(optimizerBuilder: () -> MultivariateOptimizer) { - addFeature(CMOptimizerEngine(optimizerBuilder)) -} - -public class CMOptimizerData(public val data: List OptimizationData>) : OptimizationFeature { - public constructor(vararg data: (SymbolIndexer.() -> OptimizationData)) : this(data.toList()) - - override fun toString(): String = "CMOptimizerData($data)" -} - -/** - * Specify Commons-maths optimization data. - */ -public fun FunctionOptimizationBuilder.cmOptimizationData(data: SymbolIndexer.() -> OptimizationData) { - updateFeature { - val newData = (it?.data ?: emptyList()) + data - CMOptimizerData(newData) - } -} - -public fun FunctionOptimizationBuilder.simplexSteps(vararg steps: Pair) { - //TODO use convergence checker from features - cmEngine { SimplexOptimizer(CMOptimizer.defaultConvergenceChecker) } - cmOptimizationData { NelderMeadSimplex(mapOf(*steps).toDoubleArray()) } -} - -@OptIn(UnstableKMathAPI::class) -public object CMOptimizer : Optimizer> { - - public const val DEFAULT_RELATIVE_TOLERANCE: Double = 1e-4 - public const val DEFAULT_ABSOLUTE_TOLERANCE: Double = 1e-4 - public const val DEFAULT_MAX_ITER: Int = 1000 - - public val defaultConvergenceChecker: SimpleValueChecker = SimpleValueChecker( - DEFAULT_RELATIVE_TOLERANCE, - DEFAULT_ABSOLUTE_TOLERANCE, - DEFAULT_MAX_ITER - ) - - - override suspend fun optimize( - problem: FunctionOptimization, - ): FunctionOptimization { - val startPoint = problem.startPoint - - val parameters = problem.getFeature()?.symbols - ?: problem.getFeature>()?.point?.keys - ?: startPoint.keys - - - withSymbols(parameters) { - val convergenceChecker: ConvergenceChecker = SimpleValueChecker( - DEFAULT_RELATIVE_TOLERANCE, - DEFAULT_ABSOLUTE_TOLERANCE, - DEFAULT_MAX_ITER - ) - - val cmOptimizer: MultivariateOptimizer = problem.getFeature()?.optimizerBuilder?.invoke() - ?: NonLinearConjugateGradientOptimizer( - NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES, - convergenceChecker - ) - - val optimizationData: HashMap, OptimizationData> = HashMap() - - fun addOptimizationData(data: OptimizationData) { - optimizationData[data::class] = data - } - - addOptimizationData(MaxEval.unlimited()) - addOptimizationData(InitialGuess(startPoint.toDoubleArray())) - - //fun exportOptimizationData(): List = optimizationData.values.toList() - - val objectiveFunction = ObjectiveFunction { - val args = startPoint + it.toMap() - val res = problem.expression(args) - res - } - addOptimizationData(objectiveFunction) - - val gradientFunction = ObjectiveFunctionGradient { - val args = startPoint + it.toMap() - val res = DoubleArray(symbols.size) { index -> - problem.expression.derivative(symbols[index])(args) - } - res - } - addOptimizationData(gradientFunction) - - val logger = problem.getFeature() - - for (feature in problem.features) { - when (feature) { - is CMOptimizerData -> feature.data.forEach { dataBuilder -> - addOptimizationData(dataBuilder()) - } - is FunctionOptimizationTarget -> when (feature) { - FunctionOptimizationTarget.MAXIMIZE -> addOptimizationData(GoalType.MAXIMIZE) - FunctionOptimizationTarget.MINIMIZE -> addOptimizationData(GoalType.MINIMIZE) - } - else -> logger?.log { "The feature $feature is unused in optimization" } - } - } - - val (point, value) = cmOptimizer.optimize(*optimizationData.values.toTypedArray()) - return problem.withFeatures(OptimizationResult(point.toMap()), OptimizationValue(value)) - } - } -} diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt new file mode 100644 index 000000000..267f2f1f9 --- /dev/null +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt @@ -0,0 +1,73 @@ +/* + * 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 file. + */ + +package space.kscience.kmath.commons.optimization + +import org.apache.commons.math3.analysis.differentiation.DerivativeStructure +import space.kscience.kmath.commons.expressions.DerivativeStructureField +import space.kscience.kmath.expressions.DifferentiableExpression +import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.optimization.FunctionOptimization +import space.kscience.kmath.optimization.OptimizationResult +import space.kscience.kmath.optimization.noDerivOptimizeWith +import space.kscience.kmath.optimization.optimizeWith +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.asBuffer + +/** + * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation + */ +public fun FunctionOptimization.Companion.chiSquared( + x: Buffer, + y: Buffer, + yErr: Buffer, + model: DerivativeStructureField.(x: DerivativeStructure) -> DerivativeStructure, +): DifferentiableExpression = chiSquared(DerivativeStructureField, x, y, yErr, model) + +/** + * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation + */ +public fun FunctionOptimization.Companion.chiSquared( + x: Iterable, + y: Iterable, + yErr: Iterable, + model: DerivativeStructureField.(x: DerivativeStructure) -> DerivativeStructure, +): DifferentiableExpression = chiSquared( + DerivativeStructureField, + x.toList().asBuffer(), + y.toList().asBuffer(), + yErr.toList().asBuffer(), + model +) + +/** + * Optimize expression without derivatives + */ +public fun Expression.optimize( + vararg symbols: Symbol, + configuration: CMOptimization.() -> Unit, +): OptimizationResult = noDerivOptimizeWith(CMOptimization, symbols = symbols, configuration) + +/** + * Optimize differentiable expression + */ +public fun DifferentiableExpression.optimize( + vararg symbols: Symbol, + configuration: CMOptimization.() -> Unit, +): OptimizationResult = optimizeWith(CMOptimization, symbols = symbols, configuration) + +public fun DifferentiableExpression.minimize( + vararg startPoint: Pair, + configuration: CMOptimization.() -> Unit = {}, +): OptimizationResult { + val symbols = startPoint.map { it.first }.toTypedArray() + return optimize(*symbols){ + maximize = false + initialGuess(startPoint.toMap()) + diffFunction(this@minimize) + configuration() + } +} \ No newline at end of file diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt index 194be6002..28294cf14 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.commons.random @@ -38,7 +38,10 @@ public class CMRandomGeneratorWrapper( override fun nextInt(): Int = generator.nextInt() override fun nextInt(n: Int): Int = generator.nextInt(n) + + @PerformancePitfall override fun nextGaussian(): Double = runBlocking { GaussianSampler(0.0, 1.0).next(generator) } + override fun nextDouble(): Double = generator.nextDouble() override fun nextLong(): Long = generator.nextLong() } diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt index 40168971e..1a99e9fc6 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt +++ b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.commons.transform @@ -10,13 +10,10 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import org.apache.commons.math3.transform.* import space.kscience.kmath.complex.Complex -import space.kscience.kmath.operations.SuspendBufferTransform import space.kscience.kmath.streaming.chunked import space.kscience.kmath.streaming.spread -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.VirtualBuffer -import space.kscience.kmath.structures.asBuffer +import space.kscience.kmath.structures.* + /** diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt index 56252ab34..4ed4f808f 100644 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt +++ b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.commons.expressions @@ -42,8 +42,8 @@ internal class AutoDiffTest { @Test fun autoDifTest() { val f = DerivativeStructureExpression { - val x by binding - val y by binding + val x by binding() + val y by binding() x.pow(2) + 2 * x * y + y.pow(2) + 1 } diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt index c5573fef1..bab3aecb6 100644 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt +++ b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.commons.integration diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt index 0977dc247..2f7f0c9f2 100644 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt +++ b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt @@ -1,47 +1,48 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.commons.optimization import kotlinx.coroutines.runBlocking -import space.kscience.kmath.commons.expressions.DSProcessor import space.kscience.kmath.commons.expressions.DerivativeStructureExpression import space.kscience.kmath.distributions.NormalDistribution -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.Symbol.Companion.y -import space.kscience.kmath.expressions.chiSquaredExpression import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.operations.map -import space.kscience.kmath.optimization.* +import space.kscience.kmath.optimization.FunctionOptimization import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.asBuffer import kotlin.math.pow import kotlin.test.Test internal class OptimizeTest { + val x by symbol + val y by symbol + val normal = DerivativeStructureExpression { - exp(-bindSymbol(x).pow(2) / 2) + exp(-bindSymbol(y).pow(2) / 2) + exp(-bindSymbol(x).pow(2) / 2) + exp(-bindSymbol(y) + .pow(2) / 2) } @Test - fun testGradientOptimization() = runBlocking { - val result = normal.optimizeWith(CMOptimizer, x to 1.0, y to 1.0) - println(result.resultPoint) - println(result.resultValue) + fun testGradientOptimization() { + val result = normal.optimize(x, y) { + initialGuess(x to 1.0, y to 1.0) + // no need to select optimizer. Gradient optimizer is used by default because gradients are provided by function. + } + println(result.point) + println(result.value) } @Test - fun testSimplexOptimization() = runBlocking { - val result = normal.optimizeWith(CMOptimizer, x to 1.0, y to 1.0) { + fun testSimplexOptimization() { + val result = normal.optimize(x, y) { + initialGuess(x to 1.0, y to 1.0) simplexSteps(x to 2.0, y to 0.5) //this sets simplex optimizer } - println(result.resultPoint) - println(result.resultValue) + println(result.point) + println(result.value) } @Test @@ -53,27 +54,21 @@ internal class OptimizeTest { val sigma = 1.0 val generator = NormalDistribution(0.0, sigma) val chain = generator.sample(RandomGenerator.default(112667)) - val x = (1..100).map(Int::toDouble).asBuffer() + val x = (1..100).map(Int::toDouble) val y = x.map { it.pow(2) + it + 1 + chain.next() } - val yErr = DoubleBuffer(x.size) { sigma } + val yErr = List(x.size) { sigma } - val chi2 = DSProcessor.chiSquaredExpression( - x, y, yErr - ) { arg -> + val chi2 = FunctionOptimization.chiSquared(x, y, yErr) { x1 -> val cWithDefault = bindSymbolOrNull(c) ?: one - bindSymbol(a) * arg.pow(2) + bindSymbol(b) * arg + cWithDefault + bindSymbol(a) * x1.pow(2) + bindSymbol(b) * x1 + cWithDefault } - val result: FunctionOptimization = chi2.optimizeWith( - CMOptimizer, - mapOf(a to 1.5, b to 0.9, c to 1.0), - FunctionOptimizationTarget.MINIMIZE - ) + val result = chi2.minimize(a to 1.5, b to 0.9, c to 1.0) println(result) - println("Chi2/dof = ${result.resultValue / (x.size - 3)}") + println("Chi2/dof = ${result.value / (x.size - 3)}") } } diff --git a/kmath-complex/README.md b/kmath-complex/README.md index b55ce0fea..110529b72 100644 --- a/kmath-complex/README.md +++ b/kmath-complex/README.md @@ -8,17 +8,17 @@ Complex and hypercomplex number systems in KMath. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-20`. +The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-14`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-complex:0.3.0-dev-20' + implementation 'space.kscience:kmath-complex:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-complex:0.3.0-dev-20") + implementation("space.kscience:kmath-complex:0.3.0-dev-14") } ``` diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt index 77fe782a9..08bd12205 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.complex @@ -9,7 +9,10 @@ import space.kscience.kmath.memory.MemoryReader import space.kscience.kmath.memory.MemorySpec import space.kscience.kmath.memory.MemoryWriter import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.operations.Norm +import space.kscience.kmath.operations.NumbersAddOperations +import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MemoryBuffer import space.kscience.kmath.structures.MutableBuffer @@ -41,7 +44,7 @@ public val Complex.r: Double * An angle between vector represented by complex number and X axis. */ public val Complex.theta: Double - get() = atan2(im, re) + get() = atan(im / re) private val PI_DIV_2 = Complex(PI / 2, 0) @@ -49,23 +52,11 @@ private val PI_DIV_2 = Complex(PI / 2, 0) * A field of [Complex]. */ @OptIn(UnstableKMathAPI::class) -public object ComplexField : - ExtendedField, - Norm, - NumbersAddOps, +public object ComplexField : ExtendedField, Norm, NumbersAddOperations, ScaleOperations { - override val zero: Complex = 0.0.toComplex() override val one: Complex = 1.0.toComplex() - override fun bindSymbolOrNull(value: String): Complex? = if (value == "i") i else null - - override fun binaryOperationFunction(operation: String): (left: Complex, right: Complex) -> Complex = - when (operation) { - PowerOperations.POW_OPERATION -> ComplexField::power - else -> super.binaryOperationFunction(operation) - } - /** * The imaginary unit. */ @@ -77,33 +68,33 @@ public object ComplexField : override fun scale(a: Complex, value: Double): Complex = Complex(a.re * value, a.im * value) - override fun add(left: Complex, right: Complex): Complex = Complex(left.re + right.re, left.im + right.im) + override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im) // override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble()) - override fun multiply(left: Complex, right: Complex): Complex = - Complex(left.re * right.re - left.im * right.im, left.re * right.im + left.im * right.re) + override fun multiply(a: Complex, b: Complex): Complex = + Complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re) - override fun divide(left: Complex, right: Complex): Complex = when { - abs(right.im) < abs(right.re) -> { - val wr = right.im / right.re - val wd = right.re + wr * right.im + override fun divide(a: Complex, b: Complex): Complex = when { + abs(b.im) < abs(b.re) -> { + val wr = b.im / b.re + val wd = b.re + wr * b.im if (wd.isNaN() || wd == 0.0) throw ArithmeticException("Division by zero or infinity") else - Complex((left.re + left.im * wr) / wd, (left.im - left.re * wr) / wd) + Complex((a.re + a.im * wr) / wd, (a.im - a.re * wr) / wd) } - right.im == 0.0 -> throw ArithmeticException("Division by zero") + b.im == 0.0 -> throw ArithmeticException("Division by zero") else -> { - val wr = right.re / right.im - val wd = right.im + wr * right.re + val wr = b.re / b.im + val wd = b.im + wr * b.re if (wd.isNaN() || wd == 0.0) throw ArithmeticException("Division by zero or infinity") else - Complex((left.re * wr + left.im) / wd, (left.im * wr - left.re) / wd) + Complex((a.re * wr + a.im) / wd, (a.im * wr - a.re) / wd) } } @@ -126,14 +117,10 @@ public object ComplexField : return i * (ln(1 - iArg) - ln(1 + iArg)) / 2 } - override fun power(arg: Complex, pow: Number): Complex = if (arg.im == 0.0) { + override fun power(arg: Complex, pow: Number): Complex = if (arg.im == 0.0) arg.re.pow(pow.toDouble()).toComplex() - } else { + else exp(pow * ln(arg)) - } - - public fun power(arg: Complex, pow: Complex): Complex = exp(pow * ln(arg)) - override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im)) @@ -185,6 +172,8 @@ public object ComplexField : public operator fun Double.times(c: Complex): Complex = Complex(c.re * this, c.im * this) override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg) + + override fun bindSymbolOrNull(value: String): Complex? = if (value == "i") i else null } /** @@ -214,7 +203,6 @@ public data class Complex(val re: Double, val im: Double) { } } -public val Complex.Companion.algebra: ComplexField get() = ComplexField /** * Creates a complex number with real part equal to this real. diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt index 46d4b7c5c..ae4e05631 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt @@ -1,13 +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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.complex import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.* +import space.kscience.kmath.nd.AlgebraND +import space.kscience.kmath.nd.BufferND +import space.kscience.kmath.nd.BufferedFieldND +import space.kscience.kmath.nd.StructureND +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.operations.NumbersAddOperations import space.kscience.kmath.structures.Buffer import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -17,69 +21,104 @@ import kotlin.contracts.contract * An optimized nd-field for complex numbers */ @OptIn(UnstableKMathAPI::class) -public sealed class ComplexFieldOpsND : BufferedFieldOpsND(ComplexField.bufferAlgebra), - ScaleOperations>, ExtendedFieldOps>, PowerOperations> { +public class ComplexFieldND( + shape: IntArray, +) : BufferedFieldND(shape, ComplexField, Buffer.Companion::complex), + NumbersAddOperations>, + ExtendedField> { - override fun StructureND.toBufferND(): BufferND = when (this) { - is BufferND -> this - else -> { - val indexer = indexerBuilder(shape) - BufferND(indexer, Buffer.complex(indexer.linearSize) { offset -> get(indexer.index(offset)) }) - } - } - - //TODO do specialization - - override fun scale(a: StructureND, value: Double): BufferND = - mapInline(a.toBufferND()) { it * value } - - override fun exp(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { exp(it) } - override fun ln(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { ln(it) } - - override fun sin(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { sin(it) } - override fun cos(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { cos(it) } - override fun tan(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { tan(it) } - override fun asin(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { asin(it) } - override fun acos(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { acos(it) } - override fun atan(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { atan(it) } - - override fun sinh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { sinh(it) } - override fun cosh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { cosh(it) } - override fun tanh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { tanh(it) } - override fun asinh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { asinh(it) } - override fun acosh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { acosh(it) } - override fun atanh(arg: StructureND): BufferND = mapInline(arg.toBufferND()) { atanh(it) } - - override fun power(arg: StructureND, pow: Number): StructureND = - mapInline(arg.toBufferND()) { power(it,pow) } - - public companion object : ComplexFieldOpsND() -} - -@UnstableKMathAPI -public val ComplexField.bufferAlgebra: BufferFieldOps - get() = bufferAlgebra(Buffer.Companion::complex) - - -@OptIn(UnstableKMathAPI::class) -public class ComplexFieldND(override val shape: Shape) : - ComplexFieldOpsND(), FieldND, - NumbersAddOps> { + override val zero: BufferND by lazy { produce { zero } } + override val one: BufferND by lazy { produce { one } } override fun number(value: Number): BufferND { - val d = value.toDouble() // minimize conversions - return structureND(shape) { d.toComplex() } + val d = value.toComplex() // minimize conversions + return produce { d } } + +// +// @Suppress("OVERRIDE_BY_INLINE") +// override inline fun map( +// arg: AbstractNDBuffer, +// transform: DoubleField.(Double) -> Double, +// ): RealNDElement { +// check(arg) +// val array = RealBuffer(arg.strides.linearSize) { offset -> DoubleField.transform(arg.buffer[offset]) } +// return BufferedNDFieldElement(this, array) +// } +// +// @Suppress("OVERRIDE_BY_INLINE") +// override inline fun produce(initializer: DoubleField.(IntArray) -> Double): RealNDElement { +// val array = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) } +// return BufferedNDFieldElement(this, array) +// } +// +// @Suppress("OVERRIDE_BY_INLINE") +// override inline fun mapIndexed( +// arg: AbstractNDBuffer, +// transform: DoubleField.(index: IntArray, Double) -> Double, +// ): RealNDElement { +// check(arg) +// return BufferedNDFieldElement( +// this, +// RealBuffer(arg.strides.linearSize) { offset -> +// elementContext.transform( +// arg.strides.index(offset), +// arg.buffer[offset] +// ) +// }) +// } +// +// @Suppress("OVERRIDE_BY_INLINE") +// override inline fun combine( +// a: AbstractNDBuffer, +// b: AbstractNDBuffer, +// transform: DoubleField.(Double, Double) -> Double, +// ): RealNDElement { +// check(a, b) +// val buffer = RealBuffer(strides.linearSize) { offset -> +// elementContext.transform(a.buffer[offset], b.buffer[offset]) +// } +// return BufferedNDFieldElement(this, buffer) +// } + + override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) } + + override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } + + override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } + + override fun sin(arg: StructureND): BufferND = arg.map { sin(it) } + override fun cos(arg: StructureND): BufferND = arg.map { cos(it) } + override fun tan(arg: StructureND): BufferND = arg.map { tan(it) } + override fun asin(arg: StructureND): BufferND = arg.map { asin(it) } + override fun acos(arg: StructureND): BufferND = arg.map { acos(it) } + override fun atan(arg: StructureND): BufferND = arg.map { atan(it) } + + override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) } + override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) } + override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) } + override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) } + override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) } + override fun atanh(arg: StructureND): BufferND = arg.map { atanh(it) } } -public val ComplexField.ndAlgebra: ComplexFieldOpsND get() = ComplexFieldOpsND -public fun ComplexField.ndAlgebra(vararg shape: Int): ComplexFieldND = ComplexFieldND(shape) +/** + * Fast element production using function inlining + */ +public inline fun BufferedFieldND.produceInline(initializer: ComplexField.(Int) -> Complex): BufferND { + contract { callsInPlace(initializer, InvocationKind.EXACTLY_ONCE) } + val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.initializer(offset) } + return BufferND(strides, buffer) +} + + +public fun AlgebraND.Companion.complex(vararg shape: Int): ComplexFieldND = ComplexFieldND(shape) /** * Produce a context for n-dimensional operations inside this real field */ -public inline fun ComplexField.withNdAlgebra(vararg shape: Int, action: ComplexFieldND.() -> R): R { +public inline fun ComplexField.nd(vararg shape: Int, action: ComplexFieldND.() -> R): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } return ComplexFieldND(shape).action() } diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt index 3ef3428c6..e5d7ebd1e 100644 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt +++ b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.complex @@ -44,7 +44,7 @@ public val Quaternion.r: Double */ @OptIn(UnstableKMathAPI::class) public object QuaternionField : Field, Norm, PowerOperations, - ExponentialOperations, NumbersAddOps, ScaleOperations { + ExponentialOperations, NumbersAddOperations, ScaleOperations { override val zero: Quaternion = 0.toQuaternion() override val one: Quaternion = 1.toQuaternion() @@ -63,27 +63,27 @@ public object QuaternionField : Field, Norm, */ public val k: Quaternion = Quaternion(0, 0, 0, 1) - override fun add(left: Quaternion, right: Quaternion): Quaternion = - Quaternion(left.w + right.w, left.x + right.x, left.y + right.y, left.z + right.z) + override fun add(a: Quaternion, b: Quaternion): Quaternion = + Quaternion(a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z) override fun scale(a: Quaternion, value: Double): Quaternion = Quaternion(a.w * value, a.x * value, a.y * value, a.z * value) - override fun multiply(left: Quaternion, right: Quaternion): Quaternion = Quaternion( - left.w * right.w - left.x * right.x - left.y * right.y - left.z * right.z, - left.w * right.x + left.x * right.w + left.y * right.z - left.z * right.y, - left.w * right.y - left.x * right.z + left.y * right.w + left.z * right.x, - left.w * right.z + left.x * right.y - left.y * right.x + left.z * right.w, + override fun multiply(a: Quaternion, b: Quaternion): Quaternion = Quaternion( + a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z, + a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y, + a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x, + a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w, ) - override fun divide(left: Quaternion, right: Quaternion): Quaternion { - val s = right.w * right.w + right.x * right.x + right.y * right.y + right.z * right.z + override fun divide(a: Quaternion, b: Quaternion): Quaternion { + val s = b.w * b.w + b.x * b.x + b.y * b.y + b.z * b.z return Quaternion( - (right.w * left.w + right.x * left.x + right.y * left.y + right.z * left.z) / s, - (right.w * left.x - right.x * left.w - right.y * left.z + right.z * left.y) / s, - (right.w * left.y + right.x * left.z - right.y * left.w - right.z * left.x) / s, - (right.w * left.z - right.x * left.y + right.y * left.x - right.z * left.w) / s, + (b.w * a.w + b.x * a.x + b.y * a.y + b.z * a.z) / s, + (b.w * a.x - b.x * a.w - b.y * a.z + b.z * a.y) / s, + (b.w * a.y + b.x * a.z - b.y * a.w - b.z * a.x) / s, + (b.w * a.z - b.x * a.y + b.y * a.x - b.z * a.w) / s, ) } @@ -158,16 +158,16 @@ public object QuaternionField : Field, Norm, return Quaternion(ln(n), th * arg.x, th * arg.y, th * arg.z) } - override operator fun Number.plus(other: Quaternion): Quaternion = Quaternion(toDouble() + other.w, other.x, other.y, other.z) + override operator fun Number.plus(b: Quaternion): Quaternion = Quaternion(toDouble() + b.w, b.x, b.y, b.z) - override operator fun Number.minus(other: Quaternion): Quaternion = - Quaternion(toDouble() - other.w, -other.x, -other.y, -other.z) + override operator fun Number.minus(b: Quaternion): Quaternion = + Quaternion(toDouble() - b.w, -b.x, -b.y, -b.z) - override operator fun Quaternion.plus(other: Number): Quaternion = Quaternion(w + other.toDouble(), x, y, z) - override operator fun Quaternion.minus(other: Number): Quaternion = Quaternion(w - other.toDouble(), x, y, z) + override operator fun Quaternion.plus(b: Number): Quaternion = Quaternion(w + b.toDouble(), x, y, z) + override operator fun Quaternion.minus(b: Number): Quaternion = Quaternion(w - b.toDouble(), x, y, z) - override operator fun Number.times(arg: Quaternion): Quaternion = - Quaternion(toDouble() * arg.w, toDouble() * arg.x, toDouble() * arg.y, toDouble() * arg.z) + override operator fun Number.times(b: Quaternion): Quaternion = + Quaternion(toDouble() * b.w, toDouble() * b.x, toDouble() * b.y, toDouble() * b.z) override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z) override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg) diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt index 17a077ea7..87239654d 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.complex diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt index cbaaa815b..90e624343 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.complex diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt index 7ad7f883d..a37006f75 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.complex diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt index 4279471d4..00ae5ede1 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.complex diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt index 6784f3516..319460c74 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt +++ b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.complex diff --git a/kmath-core/README.md b/kmath-core/README.md index 31965ef92..4ea493f44 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -15,17 +15,17 @@ performance calculations to code generation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-20`. +The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-14`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-core:0.3.0-dev-20' + implementation 'space.kscience:kmath-core:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -36,6 +36,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-core:0.3.0-dev-20") + implementation("space.kscience:kmath-core:0.3.0-dev-14") } ``` diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts index 4a35a54fb..564d06f49 100644 --- a/kmath-core/build.gradle.kts +++ b/kmath-core/build.gradle.kts @@ -2,17 +2,9 @@ plugins { kotlin("multiplatform") id("ru.mipt.npm.gradle.common") id("ru.mipt.npm.gradle.native") -// id("com.xcporter.metaview") version "0.0.5" } kotlin.sourceSets { - filter { it.name.contains("test", true) } - .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) - .forEach { - it.optIn("space.kscience.kmath.misc.PerformancePitfall") - it.optIn("space.kscience.kmath.misc.UnstableKMathAPI") - } - commonMain { dependencies { api(project(":kmath-memory")) @@ -20,12 +12,6 @@ kotlin.sourceSets { } } -//generateUml { -// classTree { -// -// } -//} - readme { description = "Core classes, algebra definitions, basic linear algebra" maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt index e06b774fd..de7f30680 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.data @@ -25,9 +25,6 @@ public interface ColumnarData { public operator fun get(symbol: Symbol): Buffer? } -@UnstableKMathAPI -public val ColumnarData<*>.indices: IntRange get() = 0 until size - /** * A zero-copy method to represent a [Structure2D] as a two-column x-y data. * There could more than two columns in the structure. diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt index 2fce772cc..f3ecc7e37 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.data @@ -32,43 +32,20 @@ public interface XYColumnarData : ColumnarData { Symbol.y -> y else -> null } - - public companion object{ - @UnstableKMathAPI - public fun of(x: Buffer, y: Buffer): XYColumnarData { - require(x.size == y.size) { "Buffer size mismatch. x buffer size is ${x.size}, y buffer size is ${y.size}" } - return object : XYColumnarData { - override val size: Int = x.size - override val x: Buffer = x - override val y: Buffer = y - } - } - } } - -/** - * Represent a [ColumnarData] as an [XYColumnarData]. The presence or respective columns is checked on creation. - */ +@Suppress("FunctionName") @UnstableKMathAPI -public fun ColumnarData.asXYData( - xSymbol: Symbol, - ySymbol: Symbol, -): XYColumnarData = object : XYColumnarData { - init { - requireNotNull(this@asXYData[xSymbol]){"The column with name $xSymbol is not present in $this"} - requireNotNull(this@asXYData[ySymbol]){"The column with name $ySymbol is not present in $this"} - } - override val size: Int get() = this@asXYData.size - override val x: Buffer get() = this@asXYData[xSymbol]!! - override val y: Buffer get() = this@asXYData[ySymbol]!! - override fun get(symbol: Symbol): Buffer? = when (symbol) { - Symbol.x -> x - Symbol.y -> y - else -> this@asXYData.get(symbol) +public fun XYColumnarData(x: Buffer, y: Buffer): XYColumnarData { + require(x.size == y.size) { "Buffer size mismatch. x buffer size is ${x.size}, y buffer size is ${y.size}" } + return object : XYColumnarData { + override val size: Int = x.size + override val x: Buffer = x + override val y: Buffer = y } } + /** * A zero-copy method to represent a [Structure2D] as a two-column x-y data. * There could more than two columns in the structure. diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt deleted file mode 100644 index 8ddd6406f..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYErrorColumnarData.kt +++ /dev/null @@ -1,44 +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.data - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.structures.Buffer - - -/** - * A [ColumnarData] with additional [Symbol.yError] column for an [Symbol.y] error - * Inherits [XYColumnarData]. - */ -@UnstableKMathAPI -public interface XYErrorColumnarData : XYColumnarData { - public val yErr: Buffer - - override fun get(symbol: Symbol): Buffer = when (symbol) { - Symbol.x -> x - Symbol.y -> y - Symbol.yError -> yErr - else -> error("A column for symbol $symbol not found") - } - - public companion object { - public fun of( - x: Buffer, y: Buffer, yErr: Buffer - ): XYErrorColumnarData { - require(x.size == y.size) { "Buffer size mismatch. x buffer size is ${x.size}, y buffer size is ${y.size}" } - require(y.size == yErr.size) { "Buffer size mismatch. y buffer size is ${x.size}, yErr buffer size is ${y.size}" } - - return object : XYErrorColumnarData { - override val size: Int = x.size - override val x: Buffer = x - override val y: Buffer = y - override val yErr: Buffer = yErr - } - } - } -} - diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt index e99ae0698..42866afc4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.data @@ -10,7 +10,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer /** - * A [ColumnarData] with guaranteed [x], [y] and [z] columns designated by corresponding symbols. + * A [XYColumnarData] with guaranteed [x], [y] and [z] columns designated by corresponding symbols. * Inherits [XYColumnarData]. */ @UnstableKMathAPI diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt index b5a84cf6c..0c4d2307b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.domains diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt index ee1bebde0..aee1d52c5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.domains diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt index bd5514623..7ea3e22c4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.domains diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt index 32a5fc56c..040bb80b0 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.domains diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt index 9020ef8cb..a5add6a0b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.domains diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt index 12b7df0ea..4887f3c74 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt @@ -1,12 +1,10 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.expressions -import space.kscience.kmath.operations.Algebra - /** * Represents expression, which structure can be differentiated. * @@ -66,10 +64,7 @@ public abstract class FirstDerivativeExpression : DifferentiableExpression /** * A factory that converts an expression in autodiff variables to a [DifferentiableExpression] - * @param T type of the constants for the expression - * @param I type of the actual expression state - * @param A type of expression algebra */ -public fun interface AutoDiffProcessor> { - public fun differentiate(function: A.() -> I): DifferentiableExpression +public fun interface AutoDiffProcessor, out R : Expression> { + public fun process(function: A.() -> I): DifferentiableExpression } 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 5ba32f190..c7dafec3b 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 @@ -1,11 +1,10 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.expressions -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Algebra import kotlin.jvm.JvmName import kotlin.properties.ReadOnlyProperty @@ -25,87 +24,12 @@ public fun interface Expression { public operator fun invoke(arguments: Map): T } -/** - * Specialization of [Expression] for [Double] allowing better performance because of using array. - */ -@UnstableKMathAPI -public interface DoubleExpression : Expression { - /** - * The indexer of this expression's arguments that should be used to build array for [invoke]. - * - * Implementations must fulfil the following requirement: for any argument symbol `x` and its value `y`, - * `indexer.indexOf(x) == arguments.indexOf(y)` if `arguments` is the array passed to [invoke]. - */ - public val indexer: SymbolIndexer - - public override operator fun invoke(arguments: Map): Double = - this(DoubleArray(indexer.symbols.size) { arguments.getValue(indexer.symbols[it]) }) - - /** - * Calls this expression from arguments. - * - * @param arguments the array of arguments. - * @return the value. - */ - public operator fun invoke(arguments: DoubleArray): Double -} - -/** - * Specialization of [Expression] for [Int] allowing better performance because of using array. - */ -@UnstableKMathAPI -public interface IntExpression : Expression { - /** - * The indexer of this expression's arguments that should be used to build array for [invoke]. - * - * Implementations must fulfil the following requirement: for any argument symbol `x` and its value `y`, - * `indexer.indexOf(x) == arguments.indexOf(y)` if `arguments` is the array passed to [invoke]. - */ - public val indexer: SymbolIndexer - - public override operator fun invoke(arguments: Map): Int = - this(IntArray(indexer.symbols.size) { arguments.getValue(indexer.symbols[it]) }) - - /** - * Calls this expression from arguments. - * - * @param arguments the array of arguments. - * @return the value. - */ - public operator fun invoke(arguments: IntArray): Int -} - -/** - * Specialization of [Expression] for [Long] allowing better performance because of using array. - */ -@UnstableKMathAPI -public interface LongExpression : Expression { - /** - * The indexer of this expression's arguments that should be used to build array for [invoke]. - * - * Implementations must fulfil the following requirement: for any argument symbol `x` and its value `y`, - * `indexer.indexOf(x) == arguments.indexOf(y)` if `arguments` is the array passed to [invoke]. - */ - public val indexer: SymbolIndexer - - public override operator fun invoke(arguments: Map): Long = - this(LongArray(indexer.symbols.size) { arguments.getValue(indexer.symbols[it]) }) - - /** - * Calls this expression from arguments. - * - * @param arguments the array of arguments. - * @return the value. - */ - public operator fun invoke(arguments: LongArray): Long -} - /** * Calls this expression without providing any arguments. * * @return a value. */ -public operator fun Expression.invoke(): T = this(emptyMap()) +public operator fun Expression.invoke(): T = invoke(emptyMap()) /** * Calls this expression from arguments. @@ -114,13 +38,7 @@ public operator fun Expression.invoke(): T = this(emptyMap()) * @return a value. */ @JvmName("callBySymbol") -public operator fun Expression.invoke(vararg pairs: Pair): T = this( - when (pairs.size) { - 0 -> emptyMap() - 1 -> mapOf(pairs[0]) - else -> hashMapOf(*pairs) - } -) +public operator fun Expression.invoke(vararg pairs: Pair): T = invoke(mapOf(*pairs)) /** * Calls this expression from arguments. @@ -129,78 +47,9 @@ public operator fun Expression.invoke(vararg pairs: Pair): T = * @return a value. */ @JvmName("callByString") -public operator fun Expression.invoke(vararg pairs: Pair): T = this( - when (pairs.size) { - 0 -> emptyMap() +public operator fun Expression.invoke(vararg pairs: Pair): T = + invoke(mapOf(*pairs).mapKeys { StringSymbol(it.key) }) - 1 -> { - val (k, v) = pairs[0] - mapOf(StringSymbol(k) to v) - } - - else -> hashMapOf(*Array>(pairs.size) { - val (k, v) = pairs[it] - StringSymbol(k) to v - }) - } -) - -private val EMPTY_DOUBLE_ARRAY = DoubleArray(0) - -/** - * Calls this expression without providing any arguments. - * - * @return a value. - */ -@UnstableKMathAPI -public operator fun DoubleExpression.invoke(): Double = this(EMPTY_DOUBLE_ARRAY) - -/** - * Calls this expression from arguments. - * - * @param pairs the pairs of arguments to values. - * @return a value. - */ -@UnstableKMathAPI -public operator fun DoubleExpression.invoke(vararg arguments: Double): Double = this(arguments) - -private val EMPTY_INT_ARRAY = IntArray(0) - -/** - * Calls this expression without providing any arguments. - * - * @return a value. - */ -@UnstableKMathAPI -public operator fun IntExpression.invoke(): Int = this(EMPTY_INT_ARRAY) - -/** - * Calls this expression from arguments. - * - * @param pairs the pairs of arguments to values. - * @return a value. - */ -@UnstableKMathAPI -public operator fun IntExpression.invoke(vararg arguments: Int): Int = this(arguments) - -private val EMPTY_LONG_ARRAY = LongArray(0) - -/** - * Calls this expression without providing any arguments. - * - * @return a value. - */ -@UnstableKMathAPI -public operator fun LongExpression.invoke(): Long = this(EMPTY_LONG_ARRAY) - -/** - * Calls this expression from arguments. - * - * @param pairs the pairs of arguments to values. - * @return a value. - */ -@UnstableKMathAPI -public operator fun LongExpression.invoke(vararg arguments: Long): Long = this(arguments) /** * A context for expression construction @@ -219,7 +68,6 @@ public interface ExpressionAlgebra : Algebra { /** * Bind a symbol by name inside the [ExpressionAlgebra] */ -public val ExpressionAlgebra.binding: ReadOnlyProperty - get() = ReadOnlyProperty { _, property -> - bindSymbol(property.name) ?: error("A variable with name ${property.name} does not exist") - } +public fun ExpressionAlgebra.binding(): ReadOnlyProperty = ReadOnlyProperty { _, property -> + bindSymbol(property.name) ?: error("A variable with name ${property.name} does not exist") +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt index 68cc8e791..bb7f36fc5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.expressions @@ -34,12 +34,12 @@ public abstract class FunctionalExpressionAlgebra>( override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = { left, right -> Expression { arguments -> - algebra.binaryOperationFunction(operation)(left(arguments), right(arguments)) + algebra.binaryOperationFunction(operation)(left.invoke(arguments), right.invoke(arguments)) } } override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = { arg -> - Expression { arguments -> algebra.unaryOperation(operation, arg(arguments)) } + Expression { arguments -> algebra.unaryOperationFunction(operation)(arg.invoke(arguments)) } } } @@ -52,13 +52,13 @@ public open class FunctionalExpressionGroup>( override val zero: Expression get() = const(algebra.zero) override fun Expression.unaryMinus(): Expression = - unaryOperation(GroupOps.MINUS_OPERATION, this) + unaryOperation(GroupOperations.MINUS_OPERATION, this) /** * Builds an Expression of addition of two another expressions. */ - override fun add(left: Expression, right: Expression): Expression = - binaryOperation(GroupOps.PLUS_OPERATION, left, right) + override fun add(a: Expression, b: Expression): Expression = + binaryOperation(GroupOperations.PLUS_OPERATION, a, b) // /** // * Builds an Expression of multiplication of expression by number. @@ -88,8 +88,8 @@ public open class FunctionalExpressionRing>( /** * Builds an Expression of multiplication of two expressions. */ - override fun multiply(left: Expression, right: Expression): Expression = - binaryOperationFunction(RingOps.TIMES_OPERATION)(left, right) + override fun multiply(a: Expression, b: Expression): Expression = + binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b) public operator fun Expression.times(arg: T): Expression = this * const(arg) public operator fun T.times(arg: Expression): Expression = arg * this @@ -107,8 +107,8 @@ public open class FunctionalExpressionField>( /** * Builds an Expression of division an expression by another one. */ - override fun divide(left: Expression, right: Expression): Expression = - binaryOperationFunction(FieldOps.DIV_OPERATION)(left, right) + override fun divide(a: Expression, b: Expression): Expression = + binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b) public operator fun Expression.div(arg: T): Expression = this / const(arg) public operator fun T.div(arg: Expression): Expression = arg / this @@ -164,6 +164,8 @@ public open class FunctionalExpressionExtendedField> override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = super.binaryOperationFunction(operation) + + override fun bindSymbol(value: String): Expression = super.bindSymbol(value) } public inline fun > A.expressionInGroup( @@ -190,7 +192,3 @@ public inline fun > A.expressionInField( public inline fun > A.expressionInExtendedField( block: FunctionalExpressionExtendedField.() -> Expression, ): Expression = FunctionalExpressionExtendedField(this).block() - -public inline fun DoubleField.expression( - block: FunctionalExpressionExtendedField.() -> Expression, -): Expression = FunctionalExpressionExtendedField(this).block() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt index 18226119b..fe50902b1 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt @@ -1,13 +1,13 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.expressions import space.kscience.kmath.operations.Algebra import space.kscience.kmath.operations.NumericAlgebra -import space.kscience.kmath.operations.bindSymbolOrNull +import space.kscience.kmath.operations.bindSymbol /** * A Mathematical Syntax Tree (MST) node for mathematical expressions. @@ -24,7 +24,7 @@ public sealed interface MST { public data class Numeric(val value: Number) : MST /** - * A node containing a unary operation. + * A node containing an unary operation. * * @property operation the identifier of operation. * @property value the argument of this operation. @@ -34,7 +34,7 @@ public sealed interface MST { /** * A node containing binary operation. * - * @property operation the identifier of operation. + * @property operation the identifier operation. * @property left the left operand. * @property right the right operand. */ @@ -43,50 +43,66 @@ public sealed interface MST { // TODO add a function with named arguments +/** + * Interprets the [MST] node with this [Algebra]. + * + * @receiver the algebra that provides operations. + * @param node the node to evaluate. + * @return the value of expression. + * @author Alexander Nozik + */ +public fun Algebra.evaluate(node: MST): T = when (node) { + is MST.Numeric -> (this as? NumericAlgebra)?.number(node.value) + ?: error("Numeric nodes are not supported by $this") + + is Symbol -> bindSymbol(node) + + is MST.Unary -> when { + this is NumericAlgebra && node.value is MST.Numeric -> unaryOperationFunction(node.operation)(number(node.value.value)) + else -> unaryOperationFunction(node.operation)(evaluate(node.value)) + } + + is MST.Binary -> when { + this is NumericAlgebra && node.left is MST.Numeric && node.right is MST.Numeric -> + binaryOperationFunction(node.operation)(number(node.left.value), number(node.right.value)) + + this is NumericAlgebra && node.left is MST.Numeric -> + leftSideNumberOperationFunction(node.operation)(node.left.value, evaluate(node.right)) + + this is NumericAlgebra && node.right is MST.Numeric -> + rightSideNumberOperationFunction(node.operation)(evaluate(node.left), node.right.value) + + else -> binaryOperationFunction(node.operation)(evaluate(node.left), evaluate(node.right)) + } +} + +internal class InnerAlgebra(val algebra: Algebra, val arguments: Map) : NumericAlgebra { + override fun bindSymbolOrNull(value: String): T? = algebra.bindSymbolOrNull(value) ?: arguments[StringSymbol(value)] + + override fun unaryOperation(operation: String, arg: T): T = + algebra.unaryOperation(operation, arg) + + override fun binaryOperation(operation: String, left: T, right: T): T = + algebra.binaryOperation(operation, left, right) + + override fun unaryOperationFunction(operation: String): (arg: T) -> T = + algebra.unaryOperationFunction(operation) + + override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = + algebra.binaryOperationFunction(operation) + + @Suppress("UNCHECKED_CAST") + override fun number(value: Number): T = if (algebra is NumericAlgebra<*>) + (algebra as NumericAlgebra).number(value) + else + error("Numeric nodes are not supported by $this") +} /** * Interprets the [MST] node with this [Algebra] and optional [arguments] */ -public fun MST.interpret(algebra: Algebra, arguments: Map): T = when (this) { - is MST.Numeric -> (algebra as NumericAlgebra?)?.number(value) - ?: error("Numeric nodes are not supported by $algebra") - - is Symbol -> algebra.bindSymbolOrNull(this) ?: arguments.getValue(this) - - is MST.Unary -> when { - algebra is NumericAlgebra && this.value is MST.Numeric -> algebra.unaryOperation( - this.operation, - algebra.number(this.value.value), - ) - else -> algebra.unaryOperationFunction(this.operation)(this.value.interpret(algebra, arguments)) - } - - is MST.Binary -> when { - algebra is NumericAlgebra && this.left is MST.Numeric && this.right is MST.Numeric -> algebra.binaryOperation( - this.operation, - algebra.number(this.left.value), - algebra.number(this.right.value), - ) - - algebra is NumericAlgebra && this.left is MST.Numeric -> algebra.leftSideNumberOperation( - this.operation, - this.left.value, - this.right.interpret(algebra, arguments), - ) - - algebra is NumericAlgebra && this.right is MST.Numeric -> algebra.rightSideNumberOperation( - this.operation, - left.interpret(algebra, arguments), - right.value, - ) - - else -> algebra.binaryOperation( - this.operation, - this.left.interpret(algebra, arguments), - this.right.interpret(algebra, arguments), - ) - } -} +public fun MST.interpret(algebra: Algebra, arguments: Map): T = + InnerAlgebra(algebra, arguments).evaluate(this) /** * Interprets the [MST] node with this [Algebra] and optional [arguments] @@ -95,17 +111,12 @@ public fun MST.interpret(algebra: Algebra, arguments: Map): T * @param algebra the algebra that provides operations. * @return the value of expression. */ -public fun MST.interpret(algebra: Algebra, vararg arguments: Pair): T = interpret( - algebra, - when (arguments.size) { - 0 -> emptyMap() - 1 -> mapOf(arguments[0]) - else -> hashMapOf(*arguments) - }, -) +public fun MST.interpret(algebra: Algebra, vararg arguments: Pair): T = + interpret(algebra, mapOf(*arguments)) /** * Interpret this [MST] as expression. */ -public fun MST.toExpression(algebra: Algebra): Expression = - Expression { arguments -> interpret(algebra, arguments) } +public fun MST.toExpression(algebra: Algebra): Expression = Expression { arguments -> + interpret(algebra, arguments) +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt index 4bd2a6c53..bbc74005c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.expressions @@ -31,18 +31,18 @@ public object MstGroup : Group, NumericAlgebra, ScaleOperations { override fun number(value: Number): MST.Numeric = MstNumericAlgebra.number(value) override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - override fun add(left: MST, right: MST): MST.Binary = binaryOperationFunction(GroupOps.PLUS_OPERATION)(left, right) + override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(GroupOperations.PLUS_OPERATION)(a, b) override operator fun MST.unaryPlus(): MST.Unary = - unaryOperationFunction(GroupOps.PLUS_OPERATION)(this) + unaryOperationFunction(GroupOperations.PLUS_OPERATION)(this) override operator fun MST.unaryMinus(): MST.Unary = - unaryOperationFunction(GroupOps.MINUS_OPERATION)(this) + unaryOperationFunction(GroupOperations.MINUS_OPERATION)(this) - override operator fun MST.minus(arg: MST): MST.Binary = - binaryOperationFunction(GroupOps.MINUS_OPERATION)(this, arg) + override operator fun MST.minus(b: MST): MST.Binary = + binaryOperationFunction(GroupOperations.MINUS_OPERATION)(this, b) override fun scale(a: MST, value: Double): MST.Binary = - binaryOperationFunction(RingOps.TIMES_OPERATION)(a, number(value)) + binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, number(value)) override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstNumericAlgebra.binaryOperationFunction(operation) @@ -56,23 +56,23 @@ public object MstGroup : Group, NumericAlgebra, ScaleOperations { */ @Suppress("OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) -public object MstRing : Ring, NumbersAddOps, ScaleOperations { +public object MstRing : Ring, NumbersAddOperations, ScaleOperations { override inline val zero: MST.Numeric get() = MstGroup.zero override val one: MST.Numeric = number(1.0) override fun number(value: Number): MST.Numeric = MstGroup.number(value) override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - override fun add(left: MST, right: MST): MST.Binary = MstGroup.add(left, right) + override fun add(a: MST, b: MST): MST.Binary = MstGroup.add(a, b) override fun scale(a: MST, value: Double): MST.Binary = - MstGroup.binaryOperationFunction(RingOps.TIMES_OPERATION)(a, MstGroup.number(value)) + MstGroup.binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, MstGroup.number(value)) - override fun multiply(left: MST, right: MST): MST.Binary = - binaryOperationFunction(RingOps.TIMES_OPERATION)(left, right) + override fun multiply(a: MST, b: MST): MST.Binary = + binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b) override operator fun MST.unaryPlus(): MST.Unary = MstGroup { +this@unaryPlus } override operator fun MST.unaryMinus(): MST.Unary = MstGroup { -this@unaryMinus } - override operator fun MST.minus(arg: MST): MST.Binary = MstGroup { this@minus - arg } + override operator fun MST.minus(b: MST): MST.Binary = MstGroup { this@minus - b } override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstGroup.binaryOperationFunction(operation) @@ -86,24 +86,24 @@ public object MstRing : Ring, NumbersAddOps, ScaleOperations { */ @Suppress("OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) -public object MstField : Field, NumbersAddOps, ScaleOperations { +public object MstField : Field, NumbersAddOperations, ScaleOperations { override inline val zero: MST.Numeric get() = MstRing.zero override inline val one: MST.Numeric get() = MstRing.one override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) override fun number(value: Number): MST.Numeric = MstRing.number(value) - override fun add(left: MST, right: MST): MST.Binary = MstRing.add(left, right) + override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b) override fun scale(a: MST, value: Double): MST.Binary = - MstGroup.binaryOperationFunction(RingOps.TIMES_OPERATION)(a, MstGroup.number(value)) + MstGroup.binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, MstGroup.number(value)) - override fun multiply(left: MST, right: MST): MST.Binary = MstRing.multiply(left, right) - override fun divide(left: MST, right: MST): MST.Binary = - binaryOperationFunction(FieldOps.DIV_OPERATION)(left, right) + override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b) + override fun divide(a: MST, b: MST): MST.Binary = + binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b) override operator fun MST.unaryPlus(): MST.Unary = MstRing { +this@unaryPlus } override operator fun MST.unaryMinus(): MST.Unary = MstRing { -this@unaryMinus } - override operator fun MST.minus(arg: MST): MST.Binary = MstRing { this@minus - arg } + override operator fun MST.minus(b: MST): MST.Binary = MstRing { this@minus - b } override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstRing.binaryOperationFunction(operation) @@ -134,17 +134,17 @@ public object MstExtendedField : ExtendedField, NumericAlgebra { override fun asinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ASINH_OPERATION)(arg) override fun acosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ACOSH_OPERATION)(arg) override fun atanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ATANH_OPERATION)(arg) - override fun add(left: MST, right: MST): MST.Binary = MstField.add(left, right) + override fun add(a: MST, b: MST): MST.Binary = MstField.add(a, b) override fun sqrt(arg: MST): MST = unaryOperationFunction(PowerOperations.SQRT_OPERATION)(arg) override fun scale(a: MST, value: Double): MST = - binaryOperation(GroupOps.PLUS_OPERATION, a, number(value)) + binaryOperation(GroupOperations.PLUS_OPERATION, a, number(value)) - override fun multiply(left: MST, right: MST): MST.Binary = MstField.multiply(left, right) - override fun divide(left: MST, right: MST): MST.Binary = MstField.divide(left, right) + override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b) + override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b) override operator fun MST.unaryPlus(): MST.Unary = MstField { +this@unaryPlus } override operator fun MST.unaryMinus(): MST.Unary = MstField { -this@unaryMinus } - override operator fun MST.minus(arg: MST): MST.Binary = MstField { this@minus - arg } + override operator fun MST.minus(b: MST): MST.Binary = MstField { this@minus - b } override fun power(arg: MST, pow: Number): MST.Binary = binaryOperationFunction(PowerOperations.POW_OPERATION)(arg, number(pow)) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt index ac8c44446..4a97baac4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.expressions @@ -59,7 +59,7 @@ public fun DerivationResult.grad(vararg variables: Symbol): Point>( public val context: F, bindings: Map, -) : Field>, ExpressionAlgebra>, NumbersAddOps> { +) : Field>, ExpressionAlgebra>, NumbersAddOperations> { override val zero: AutoDiffValue get() = const(context.zero) override val one: AutoDiffValue get() = const(context.one) @@ -168,22 +168,22 @@ public open class SimpleAutoDiffField>( // Basic math (+, -, *, /) - override fun add(left: AutoDiffValue, right: AutoDiffValue): AutoDiffValue = - derive(const { left.value + right.value }) { z -> - left.d += z.d - right.d += z.d + override fun add(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = + derive(const { a.value + b.value }) { z -> + a.d += z.d + b.d += z.d } - override fun multiply(left: AutoDiffValue, right: AutoDiffValue): AutoDiffValue = - derive(const { left.value * right.value }) { z -> - left.d += z.d * right.value - right.d += z.d * left.value + override fun multiply(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = + derive(const { a.value * b.value }) { z -> + a.d += z.d * b.value + b.d += z.d * a.value } - override fun divide(left: AutoDiffValue, right: AutoDiffValue): AutoDiffValue = - derive(const { left.value / right.value }) { z -> - left.d += z.d / right.value - right.d -= z.d * left.value / (right.value * right.value) + override fun divide(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = + derive(const { a.value / b.value }) { z -> + a.d += z.d / b.value + b.d -= z.d * a.value / (b.value * b.value) } override fun scale(a: AutoDiffValue, value: Double): AutoDiffValue = @@ -251,9 +251,7 @@ public class SimpleAutoDiffExpression>( /** * Generate [AutoDiffProcessor] for [SimpleAutoDiffExpression] */ -public fun > simpleAutoDiff( - field: F, -): AutoDiffProcessor, SimpleAutoDiffField> = +public fun > simpleAutoDiff(field: F): AutoDiffProcessor, SimpleAutoDiffField, Expression> = AutoDiffProcessor { function -> SimpleAutoDiffExpression(field, function) } @@ -272,8 +270,8 @@ public fun > SimpleAutoDiffField.sqrt(x: Aut public fun > SimpleAutoDiffField.pow( x: AutoDiffValue, y: Double, -): AutoDiffValue = derive(const { x.value.pow(y) }) { z -> - x.d += z.d * y * x.value.pow(y - 1) +): AutoDiffValue = derive(const { power(x.value, y) }) { z -> + x.d += z.d * y * power(x.value, y - 1) } public fun > SimpleAutoDiffField.pow( @@ -343,7 +341,10 @@ public fun > SimpleAutoDiffField.atanh(x: Au public class SimpleAutoDiffExtendedField>( context: F, bindings: Map, -) : ExtendedField>, ScaleOperations>, SimpleAutoDiffField(context, bindings) { +) : ExtendedField>, ScaleOperations>, + SimpleAutoDiffField(context, bindings) { + + override fun bindSymbol(value: String): AutoDiffValue = super.bindSymbol(value) override fun number(value: Number): AutoDiffValue = const { number(value) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt index 8ab2bec31..d72b94b2a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.expressions @@ -9,8 +9,8 @@ import kotlin.jvm.JvmInline import kotlin.properties.ReadOnlyProperty /** - * A marker interface for a symbol. A symbol must have an identity with equality relation based on it. - * Other properties are to store additional, transient data only. + * A marker interface for a symbol. A symbol must have an identity. + * Ic */ public interface Symbol : MST { /** @@ -19,12 +19,9 @@ public interface Symbol : MST { public val identity: String public companion object { - public val x: Symbol = Symbol("x") - public val xError: Symbol = Symbol("x.error") - public val y: Symbol = Symbol("y") - public val yError: Symbol = Symbol("y.error") - public val z: Symbol = Symbol("z") - public val zError: Symbol = Symbol("z.error") + public val x: StringSymbol = StringSymbol("x") + public val y: StringSymbol = StringSymbol("y") + public val z: StringSymbol = StringSymbol("z") } } @@ -32,15 +29,10 @@ public interface Symbol : MST { * A [Symbol] with a [String] identity */ @JvmInline -internal value class StringSymbol(override val identity: String) : Symbol { +public value class StringSymbol(override val identity: String) : Symbol { override fun toString(): String = identity } -/** - * Create s Symbols with a string identity - */ -public fun Symbol(identity: String): Symbol = StringSymbol(identity) - /** * A delegate to create a symbol with a string identity in this scope */ diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt index bf37e9615..25d2ece51 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.expressions @@ -9,7 +9,6 @@ import space.kscience.kmath.linear.Point import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.structures.BufferFactory -import space.kscience.kmath.structures.DoubleBuffer import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.jvm.JvmInline @@ -48,11 +47,6 @@ public interface SymbolIndexer { return symbols.indices.associate { symbols[it] to get(it) } } - public fun Point.toMap(): Map { - require(size == symbols.size) { "The input array size for indexer should be ${symbols.size} but $size found" } - return symbols.indices.associate { symbols[it] to get(it) } - } - public operator fun Structure2D.get(rowSymbol: Symbol, columnSymbol: Symbol): T = get(indexOf(rowSymbol), indexOf(columnSymbol)) @@ -62,10 +56,6 @@ public interface SymbolIndexer { public fun Map.toPoint(bufferFactory: BufferFactory): Point = bufferFactory(symbols.size) { getValue(symbols[it]) } - public fun Map.toPoint(): DoubleBuffer = - DoubleBuffer(symbols.size) { getValue(symbols[it]) } - - public fun Map.toDoubleArray(): DoubleArray = DoubleArray(symbols.size) { getValue(symbols[it]) } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt deleted file mode 100644 index 907ce4004..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt +++ /dev/null @@ -1,53 +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.expressions - -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.asIterable -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.indices -import kotlin.jvm.JvmName - -/** - * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic - * differentiation. - * - * **WARNING** All elements of [yErr] must be positive. - */ -@JvmName("genericChiSquaredExpression") -public fun , I : Any, A> AutoDiffProcessor.chiSquaredExpression( - x: Buffer, - y: Buffer, - yErr: Buffer, - model: A.(I) -> I, -): DifferentiableExpression where A : ExtendedField, A : ExpressionAlgebra { - require(x.size == y.size) { "X and y buffers should be of the same size" } - require(y.size == yErr.size) { "Y and yErr buffer should of the same size" } - - return differentiate { - var sum = zero - - x.indices.forEach { - val xValue = const(x[it]) - val yValue = const(y[it]) - val yErrValue = const(yErr[it]) - val modelValue = model(xValue) - sum += ((yValue - modelValue) / yErrValue).pow(2) - } - - sum - } -} - -public fun AutoDiffProcessor.chiSquaredExpression( - x: Buffer, - y: Buffer, - yErr: Buffer, - model: A.(I) -> I, -): DifferentiableExpression where A : ExtendedField, A : ExpressionAlgebra { - require(yErr.asIterable().all { it > 0.0 }) { "All errors must be strictly positive" } - return chiSquaredExpression(x, y, yErr, model) -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt index 36cbd9064..5471cb925 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt @@ -1,47 +1,48 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.linear import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.BufferedRingOpsND -import space.kscience.kmath.nd.as2D -import space.kscience.kmath.nd.asND -import space.kscience.kmath.operations.* +import space.kscience.kmath.nd.* +import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.VirtualBuffer import space.kscience.kmath.structures.indices -public class BufferedLinearSpace>( - private val bufferAlgebra: BufferAlgebra +public class BufferedLinearSpace>( + override val elementAlgebra: A, + private val bufferFactory: BufferFactory, ) : LinearSpace { - override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra - private val ndAlgebra = BufferedRingOpsND(bufferAlgebra) + private fun ndRing( + rows: Int, + cols: Int, + ): BufferedRingND = AlgebraND.ring(elementAlgebra, bufferFactory, rows, cols) override fun buildMatrix(rows: Int, columns: Int, initializer: A.(i: Int, j: Int) -> T): Matrix = - ndAlgebra.structureND(intArrayOf(rows, columns)) { (i, j) -> elementAlgebra.initializer(i, j) }.as2D() + ndRing(rows, columns).produce { (i, j) -> elementAlgebra.initializer(i, j) }.as2D() override fun buildVector(size: Int, initializer: A.(Int) -> T): Point = - bufferAlgebra.buffer(size) { elementAlgebra.initializer(it) } + bufferFactory(size) { elementAlgebra.initializer(it) } - @OptIn(PerformancePitfall::class) - override fun Matrix.unaryMinus(): Matrix = ndAlgebra { - asND().map { -it }.as2D() + override fun Matrix.unaryMinus(): Matrix = ndRing(rowNum, colNum).run { + unwrap().map { -it }.as2D() } - override fun Matrix.plus(other: Matrix): Matrix = ndAlgebra { + override fun Matrix.plus(other: Matrix): Matrix = ndRing(rowNum, colNum).run { require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" } - asND().plus(other.asND()).as2D() + unwrap().plus(other.unwrap()).as2D() } - override fun Matrix.minus(other: Matrix): Matrix = ndAlgebra { + override fun Matrix.minus(other: Matrix): Matrix = ndRing(rowNum, colNum).run { require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::minus. Expected $shape but found ${other.shape}" } - asND().minus(other.asND()).as2D() + unwrap().minus(other.unwrap()).as2D() } private fun Buffer.linearize() = if (this is VirtualBuffer) { @@ -84,12 +85,7 @@ public class BufferedLinearSpace>( } } - @OptIn(PerformancePitfall::class) - override fun Matrix.times(value: T): Matrix = ndAlgebra { - asND().map { it * value }.as2D() + override fun Matrix.times(value: T): Matrix = ndRing(rowNum, colNum).run { + unwrap().map { it * value }.as2D() } } - - -public fun > A.linearSpace(bufferFactory: BufferFactory): BufferedLinearSpace = - BufferedLinearSpace(BufferRingOps(this, bufferFactory)) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt deleted file mode 100644 index 4e6debc60..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/DoubleLinearSpace.kt +++ /dev/null @@ -1,110 +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.linear - -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.DoubleFieldOpsND -import space.kscience.kmath.nd.as2D -import space.kscience.kmath.nd.asND -import space.kscience.kmath.operations.DoubleBufferOps -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer - -public object DoubleLinearSpace : LinearSpace { - - override val elementAlgebra: DoubleField get() = DoubleField - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: DoubleField.(i: Int, j: Int) -> Double - ): Matrix = DoubleFieldOpsND.structureND(intArrayOf(rows, columns)) { (i, j) -> - DoubleField.initializer(i, j) - }.as2D() - - override fun buildVector(size: Int, initializer: DoubleField.(Int) -> Double): DoubleBuffer = - DoubleBuffer(size) { DoubleField.initializer(it) } - - override fun Matrix.unaryMinus(): Matrix = DoubleFieldOpsND { - asND().map { -it }.as2D() - } - - override fun Matrix.plus(other: Matrix): Matrix = DoubleFieldOpsND { - require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" } - asND().plus(other.asND()).as2D() - } - - override fun Matrix.minus(other: Matrix): Matrix = DoubleFieldOpsND { - require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::minus. Expected $shape but found ${other.shape}" } - asND().minus(other.asND()).as2D() - } - - // Create a continuous in-memory representation of this vector for better memory layout handling - private fun Buffer.linearize() = if (this is DoubleBuffer) { - this.array - } else { - DoubleArray(size) { get(it) } - } - - @OptIn(PerformancePitfall::class) - override fun Matrix.dot(other: Matrix): Matrix { - require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } - val rows = this@dot.rows.map { it.linearize() } - val columns = other.columns.map { it.linearize() } - return buildMatrix(rowNum, other.colNum) { i, j -> - val r = rows[i] - val c = columns[j] - var res = 0.0 - for (l in r.indices) { - res += r[l] * c[l] - } - res - } - } - - @OptIn(PerformancePitfall::class) - override fun Matrix.dot(vector: Point): DoubleBuffer { - require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" } - val rows = this@dot.rows.map { it.linearize() } - return DoubleBuffer(rowNum) { i -> - val r = rows[i] - var res = 0.0 - for (j in r.indices) { - res += r[j] * vector[j] - } - res - } - - } - - override fun Matrix.times(value: Double): Matrix = DoubleFieldOpsND { - asND().map { it * value }.as2D() - } - - public override fun Point.plus(other: Point): DoubleBuffer = DoubleBufferOps.run { - this@plus + other - } - - public override fun Point.minus(other: Point): DoubleBuffer = DoubleBufferOps.run { - this@minus - other - } - - public override fun Point.times(value: Double): DoubleBuffer = DoubleBufferOps.run { - scale(this@times, value) - } - - public operator fun Point.div(value: Double): DoubleBuffer = DoubleBufferOps.run { - scale(this@div, 1.0 / value) - } - - public override fun Double.times(v: Point): DoubleBuffer = v * this - - -} - -public val DoubleField.linearSpace: DoubleLinearSpace get() = DoubleLinearSpace diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt index fae9e7c91..86a35a6a4 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt @@ -1,10 +1,12 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.linear +import space.kscience.kmath.nd.as1D + /** * A group of methods to solve for *X* in equation *X = A−1 · B*, where *A* and *B* are * matrices or vectors. @@ -28,3 +30,20 @@ public interface LinearSolver { public fun inverse(matrix: Matrix): Matrix } +/** + * Convert matrix to vector if it is possible. + */ +public fun Matrix.asVector(): Point = + if (this.colNum == 1) + as1D() + else + error("Can't convert matrix with more than one column to vector") + +/** + * Creates an n × 1 [VirtualMatrix], where n is the size of the given buffer. + * + * @param T the type of elements contained in the buffer. + * @receiver a buffer. + * @return the new matrix. + */ +public fun Point.asMatrix(): VirtualMatrix = VirtualMatrix(size, 1) { i, _ -> get(i) } 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 715fad07b..bb5a1b530 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 @@ -1,19 +1,13 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.linear import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.MutableStructure2D -import space.kscience.kmath.nd.Structure2D -import space.kscience.kmath.nd.StructureFeature -import space.kscience.kmath.nd.as1D -import space.kscience.kmath.operations.BufferRingOps -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke +import space.kscience.kmath.nd.* +import space.kscience.kmath.operations.* import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.DoubleBuffer @@ -40,7 +34,7 @@ public typealias Point = Buffer * @param T the type of items in the matrices. * @param A the type of ring over [T]. */ -public interface LinearSpace> { +public interface LinearSpace> { public val elementAlgebra: A /** @@ -170,7 +164,7 @@ public interface LinearSpace> { public operator fun T.times(v: Point): Point = v * this /** - * Compute a feature of the structure in this scope. Structure features take precedence other context features. + * Get a feature of the structure in this scope. Structure features take precedence other context features. * * @param F the type of feature. * @param structure the structure. @@ -178,8 +172,7 @@ public interface LinearSpace> { * @return a feature object or `null` if it isn't present. */ @UnstableKMathAPI - public fun computeFeature(structure: Matrix, type: KClass): F? = - structure.getFeature(type) + public fun getFeature(structure: Matrix, type: KClass): F? = structure.getFeature(type) public companion object { @@ -189,10 +182,9 @@ public interface LinearSpace> { public fun > buffered( algebra: A, bufferFactory: BufferFactory = Buffer.Companion::boxing, - ): LinearSpace = BufferedLinearSpace(BufferRingOps(algebra, bufferFactory)) + ): LinearSpace = BufferedLinearSpace(algebra, bufferFactory) - @Deprecated("use DoubleField.linearSpace") - public val double: LinearSpace = buffered(DoubleField, ::DoubleBuffer) + public val real: LinearSpace = buffered(DoubleField, ::DoubleBuffer) /** * Automatic buffered matrix, unboxed if it is possible @@ -210,25 +202,9 @@ public interface LinearSpace> { * @return a feature object or `null` if it isn't present. */ @UnstableKMathAPI -public inline fun LinearSpace.computeFeature(structure: Matrix): F? = - computeFeature(structure, F::class) +public inline fun LinearSpace.getFeature(structure: Matrix): F? = + getFeature(structure, F::class) -public inline operator fun , R> LS.invoke(block: LS.() -> R): R = run(block) +public operator fun , R> LS.invoke(block: LS.() -> R): R = run(block) - -/** - * Convert matrix to vector if it is possible. - */ -public fun Matrix.asVector(): Point = - if (this.colNum == 1) as1D() - else error("Can't convert matrix with more than one column to vector") - -/** - * Creates an n × 1 [VirtualMatrix], where n is the size of the given buffer. - * - * @param T the type of elements contained in the buffer. - * @receiver a buffer. - * @return the new matrix. - */ -public fun Point.asMatrix(): VirtualMatrix = VirtualMatrix(size, 1) { i, _ -> get(i) } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt index fb57f2343..145088b56 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt @@ -1,11 +1,12 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.linear import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.nd.getFeature import space.kscience.kmath.operations.* import space.kscience.kmath.structures.BufferAccessor2D import space.kscience.kmath.structures.DoubleBuffer @@ -33,7 +34,7 @@ public class LupDecomposition( j == i -> elementContext.one else -> elementContext.zero } - }.withFeature(LFeature) + } + LFeature /** @@ -43,7 +44,7 @@ public class LupDecomposition( */ override val u: Matrix = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j -> if (j >= i) lu[i, j] else elementContext.zero - }.withFeature(UFeature) + } + UFeature /** * Returns the P rows permutation matrix. @@ -81,7 +82,7 @@ public fun > LinearSpace>.lup( val m = matrix.colNum val pivot = IntArray(matrix.rowNum) - //TODO just waits for multi-receivers + //TODO just waits for KEEP-176 BufferAccessor2D(matrix.rowNum, matrix.colNum, factory).run { elementAlgebra { val lu = create(matrix) @@ -155,13 +156,10 @@ public inline fun > LinearSpace>.lup( noinline checkSingular: (T) -> Boolean, ): LupDecomposition = lup(MutableBuffer.Companion::auto, matrix, checkSingular) -public fun LinearSpace.lup( - matrix: Matrix, - singularityThreshold: Double = 1e-11, -): LupDecomposition = - lup(::DoubleBuffer, matrix) { it < singularityThreshold } +public fun LinearSpace.lup(matrix: Matrix): LupDecomposition = + lup(::DoubleBuffer, matrix) { it < 1e-11 } -internal fun LupDecomposition.solve( +public fun LupDecomposition.solveWithLup( factory: MutableBufferFactory, matrix: Matrix, ): Matrix { @@ -209,22 +207,41 @@ internal fun LupDecomposition.solve( } } +public inline fun LupDecomposition.solveWithLup(matrix: Matrix): Matrix = + solveWithLup(MutableBuffer.Companion::auto, matrix) + /** - * Produce a generic solver based on LUP decomposition + * Solves a system of linear equations *ax = b** using LUP decomposition. */ @OptIn(UnstableKMathAPI::class) -public fun , F : Field> LinearSpace.lupSolver( - bufferFactory: MutableBufferFactory, - singularityCheck: (T) -> Boolean, -): LinearSolver = object : LinearSolver { - override fun solve(a: Matrix, b: Matrix): Matrix { - // Use existing decomposition if it is provided by matrix - val decomposition = computeFeature(a) ?: lup(bufferFactory, a, singularityCheck) - return decomposition.solve(bufferFactory, b) - } - - override fun inverse(matrix: Matrix): Matrix = solve(matrix, one(matrix.rowNum, matrix.colNum)) +public inline fun > LinearSpace>.solveWithLup( + a: Matrix, + b: Matrix, + noinline bufferFactory: MutableBufferFactory = MutableBuffer.Companion::auto, + noinline checkSingular: (T) -> Boolean, +): Matrix { + // Use existing decomposition if it is provided by matrix + val decomposition = a.getFeature() ?: lup(bufferFactory, a, checkSingular) + return decomposition.solveWithLup(bufferFactory, b) } -public fun LinearSpace.lupSolver(singularityThreshold: Double = 1e-11): LinearSolver = - lupSolver(::DoubleBuffer) { it < singularityThreshold } +public inline fun > LinearSpace>.inverseWithLup( + matrix: Matrix, + noinline bufferFactory: MutableBufferFactory = MutableBuffer.Companion::auto, + noinline checkSingular: (T) -> Boolean, +): Matrix = solveWithLup(matrix, one(matrix.rowNum, matrix.colNum), bufferFactory, checkSingular) + + +@OptIn(UnstableKMathAPI::class) +public fun LinearSpace.solveWithLup(a: Matrix, b: Matrix): Matrix { + // Use existing decomposition if it is provided by matrix + val bufferFactory: MutableBufferFactory = ::DoubleBuffer + val decomposition: LupDecomposition = a.getFeature() ?: lup(bufferFactory, a) { it < 1e-11 } + return decomposition.solveWithLup(bufferFactory, b) +} + +/** + * Inverses a square matrix using LUP decomposition. Non square matrix will throw an error. + */ +public fun LinearSpace.inverseWithLup(matrix: Matrix): Matrix = + solveWithLup(matrix, one(matrix.rowNum, matrix.colNum)) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt index 029612bc5..01dc21198 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt @@ -1,14 +1,12 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.linear import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring -import space.kscience.kmath.structures.BufferAccessor2D -import space.kscience.kmath.structures.MutableBuffer public class MatrixBuilder>( public val linearSpace: LinearSpace, @@ -47,31 +45,4 @@ public inline fun LinearSpace>.column( crossinline builder: (Int) -> T, ): Matrix = buildMatrix(size, 1) { i, _ -> builder(i) } -public fun LinearSpace>.column(vararg values: T): Matrix = column(values.size, values::get) - -public object SymmetricMatrixFeature : MatrixFeature - -/** - * Naive implementation of a symmetric matrix builder, that adds a [SymmetricMatrixFeature] tag. The resulting matrix contains - * full `size^2` number of elements, but caches elements during calls to save [builder] calls. [builder] is always called in the - * upper triangle region meaning that `i <= j` - */ -public fun > MatrixBuilder.symmetric( - builder: (i: Int, j: Int) -> T, -): Matrix { - require(columns == rows) { "In order to build symmetric matrix, number of rows $rows should be equal to number of columns $columns" } - return with(BufferAccessor2D(rows, rows, MutableBuffer.Companion::boxing)) { - val cache = factory(rows * rows) { null } - linearSpace.buildMatrix(rows, rows) { i, j -> - val cached = cache[i, j] - if (cached == null) { - val value = if (i <= j) builder(i, j) else builder(j, i) - cache[i, j] = value - cache[j, i] = value - value - } else { - cached - } - }.withFeature(SymmetricMatrixFeature) - } -} \ No newline at end of file +public fun LinearSpace>.column(vararg values: T): Matrix = column(values.size, values::get) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt index b70e9d8a9..4c2b5c73c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.linear diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt index b1812f49d..e5448899b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt @@ -1,13 +1,13 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.linear -import space.kscience.kmath.misc.FeatureSet import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureFeature +import space.kscience.kmath.nd.getFeature import space.kscience.kmath.operations.Ring import kotlin.reflect.KClass @@ -18,16 +18,18 @@ import kotlin.reflect.KClass */ public class MatrixWrapper internal constructor( public val origin: Matrix, - public val features: FeatureSet, + public val features: Set, ) : Matrix by origin { /** * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the * criteria. */ + @UnstableKMathAPI @Suppress("UNCHECKED_CAST") override fun getFeature(type: KClass): F? = - features.getFeature(type) ?: origin.getFeature(type) + features.singleOrNull(type::isInstance) as? F + ?: origin.getFeature(type) override fun toString(): String = "MatrixWrapper(matrix=$origin, features=$features)" } @@ -43,23 +45,20 @@ public val Matrix.origin: Matrix /** * Add a single feature to a [Matrix] */ -public fun Matrix.withFeature(newFeature: MatrixFeature): MatrixWrapper = if (this is MatrixWrapper) { - MatrixWrapper(origin, features.with(newFeature)) +public operator fun Matrix.plus(newFeature: MatrixFeature): MatrixWrapper = if (this is MatrixWrapper) { + MatrixWrapper(origin, features + newFeature) } else { - MatrixWrapper(this, FeatureSet.of(newFeature)) + MatrixWrapper(this, setOf(newFeature)) } -@Deprecated("To be replaced by withFeature") -public operator fun Matrix.plus(newFeature: MatrixFeature): MatrixWrapper = withFeature(newFeature) - /** * Add a collection of features to a [Matrix] */ -public fun Matrix.withFeatures(newFeatures: Iterable): MatrixWrapper = +public operator fun Matrix.plus(newFeatures: Collection): MatrixWrapper = if (this is MatrixWrapper) { - MatrixWrapper(origin, features.with(newFeatures)) + MatrixWrapper(origin, features + newFeatures) } else { - MatrixWrapper(this, FeatureSet.of(newFeatures)) + MatrixWrapper(this, newFeatures.toSet()) } /** @@ -70,7 +69,7 @@ public fun LinearSpace>.one( columns: Int, ): Matrix = VirtualMatrix(rows, columns) { i, j -> if (i == j) elementAlgebra.one else elementAlgebra.zero -}.withFeature(UnitFeature) +} + UnitFeature /** @@ -81,14 +80,15 @@ public fun LinearSpace>.zero( columns: Int, ): Matrix = VirtualMatrix(rows, columns) { _, _ -> elementAlgebra.zero -}.withFeature(ZeroFeature) +} + ZeroFeature public class TransposedFeature(public val original: Matrix) : MatrixFeature /** * Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A` */ -@Suppress("UNCHECKED_CAST") @OptIn(UnstableKMathAPI::class) -public fun Matrix.transpose(): Matrix = getFeature(TransposedFeature::class)?.original as? Matrix - ?: VirtualMatrix(colNum, rowNum) { i, j -> get(j, i) }.withFeature(TransposedFeature(this)) +public fun Matrix.transpose(): Matrix = getFeature>()?.original ?: (VirtualMatrix( + colNum, + rowNum, +) { i, j -> get(j, i) } + TransposedFeature(this)) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt index fb2b1e547..c3327bc6b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.linear @@ -20,6 +20,3 @@ public class VirtualMatrix( override operator fun get(i: Int, j: Int): T = generator(i, j) } - -public fun MatrixBuilder.virtual(generator: (i: Int, j: Int) -> T): VirtualMatrix = - VirtualMatrix(rows, columns, generator) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt deleted file mode 100644 index 29b7caec6..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/Featured.kt +++ /dev/null @@ -1,61 +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.misc - -import kotlin.jvm.JvmInline -import kotlin.reflect.KClass - -/** - * A entity that contains a set of features defined by their types - */ -public interface Featured { - public fun getFeature(type: FeatureKey): T? -} - -public typealias FeatureKey = KClass - -public interface Feature> { - - /** - * A key used for extraction - */ - @Suppress("UNCHECKED_CAST") - public val key: FeatureKey - get() = this::class as FeatureKey -} - -/** - * A container for a set of features - */ -@JvmInline -public value class FeatureSet> private constructor(public val features: Map, F>) : Featured { - @Suppress("UNCHECKED_CAST") - override fun getFeature(type: FeatureKey): T? = features[type]?.let { it as T } - - public inline fun getFeature(): T? = getFeature(T::class) - - public fun with(feature: T, type: FeatureKey = feature.key): FeatureSet = - FeatureSet(features + (type to feature)) - - public fun with(other: FeatureSet): FeatureSet = FeatureSet(features + other.features) - - public fun with(vararg otherFeatures: F): FeatureSet = - FeatureSet(features + otherFeatures.associateBy { it.key }) - - public fun with(otherFeatures: Iterable): FeatureSet = - FeatureSet(features + otherFeatures.associateBy { it.key }) - - public operator fun iterator(): Iterator = features.values.iterator() - - override fun toString(): String = features.values.joinToString(prefix = "[ ", postfix = " ]") - - - public companion object { - public fun > of(vararg features: F): FeatureSet = FeatureSet(features.associateBy { it.key }) - public fun > of(features: Iterable): FeatureSet = - FeatureSet(features.associateBy { it.key }) - } -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt index 7c612b6a9..a643dc0bf 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.misc @@ -24,7 +24,7 @@ public annotation class UnstableKMathAPI @Retention(value = AnnotationRetention.BINARY) @RequiresOptIn( "Refer to the documentation to use this API in performance-critical code", - RequiresOptIn.Level.WARNING, + RequiresOptIn.Level.WARNING ) public annotation class PerformancePitfall( val message: String = "Potential performance problem" diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt index ee7f1d8be..413f44960 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.misc diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt deleted file mode 100644 index 9dfc564c3..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/logging.kt +++ /dev/null @@ -1,22 +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.misc - -import space.kscience.kmath.misc.Loggable.Companion.INFO - -public fun interface Loggable { - public fun log(tag: String, block: () -> String) - - public companion object { - public const val INFO: String = "INFO" - - public val console: Loggable = Loggable { tag, block -> - println("[$tag] ${block()}") - } - } -} - -public fun Loggable.log(block: () -> String): Unit = log(INFO, block) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt index f879a06d5..e048eb746 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.misc diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt deleted file mode 100644 index a144e49b4..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/sorting.kt +++ /dev/null @@ -1,55 +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 file. - */ - -package space.kscience.kmath.misc - -import kotlin.comparisons.* -import space.kscience.kmath.structures.Buffer - -/** - * Return a new list filled with buffer indices. Indice order is defined by sorting associated buffer value. - * This feature allows to sort buffer values without reordering its content. - * - * @return List of buffer indices, sorted by associated value. - */ -@PerformancePitfall -@UnstableKMathAPI -public fun > Buffer.permSort() : IntArray = _permSortWith(compareBy { get(it) }) - -@PerformancePitfall -@UnstableKMathAPI -public fun > Buffer.permSortDescending() : IntArray = _permSortWith(compareByDescending { get(it) }) - -@PerformancePitfall -@UnstableKMathAPI -public fun > Buffer.permSortBy(selector: (V) -> C) : IntArray = _permSortWith(compareBy { selector(get(it)) }) - -@PerformancePitfall -@UnstableKMathAPI -public fun > Buffer.permSortByDescending(selector: (V) -> C) : IntArray = _permSortWith(compareByDescending { selector(get(it)) }) - -@PerformancePitfall -@UnstableKMathAPI -public fun Buffer.permSortWith(comparator : Comparator) : IntArray = _permSortWith { i1, i2 -> comparator.compare(get(i1), get(i2)) } - -@PerformancePitfall -@UnstableKMathAPI -private fun Buffer._permSortWith(comparator : Comparator) : IntArray { - if (size < 2) return IntArray(size) - - /* TODO: optimisation : keep a constant big array of indices (Ex: from 0 to 4096), then create indice - * arrays more efficiently by copying subpart of cached one. For bigger needs, we could copy entire - * cached array, then fill remaining indices manually. Not done for now, because: - * 1. doing it right would require some statistics about common used buffer sizes. - * 2. Some benchmark would be needed to ensure it would really provide better performance - */ - val packedIndices = IntArray(size) { idx -> idx } - - /* TODO: find an efficient way to sort in-place instead, and return directly the IntArray. - * Not done for now, because no standard utility is provided yet. An open issue exists for this. - * See: https://youtrack.jetbrains.com/issue/KT-37860 - */ - return packedIndices.sortedWith(comparator).toIntArray() -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt index a071c1eb3..b925c2642 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt @@ -1,13 +1,13 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.nd -import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.* import kotlin.reflect.KClass /** @@ -19,67 +19,46 @@ import kotlin.reflect.KClass public class ShapeMismatchException(public val expected: IntArray, public val actual: IntArray) : RuntimeException("Shape ${actual.contentToString()} doesn't fit in expected shape ${expected.contentToString()}.") -public typealias Shape = IntArray - -public fun Shape(shapeFirst: Int, vararg shapeRest: Int): Shape = intArrayOf(shapeFirst, *shapeRest) - -public interface WithShape { - public val shape: Shape - - public val indices: ShapeIndexer get() = DefaultStrides(shape) -} - /** * The base interface for all ND-algebra implementations. * * @param T the type of ND-structure element. * @param C the type of the element context. */ -public interface AlgebraND>: Algebra> { +public interface AlgebraND> { + /** + * The shape of ND-structures this algebra operates on. + */ + public val shape: IntArray + /** * The algebra over elements of ND structure. */ - public val elementAlgebra: C + public val elementContext: C /** - * Produces a new [StructureND] using given initializer function. + * Produces a new NDStructure using given initializer function. */ - public fun structureND(shape: Shape, initializer: C.(IntArray) -> T): StructureND + public fun produce(initializer: C.(IntArray) -> T): StructureND /** * Maps elements from one structure to another one by applying [transform] to them. */ - @PerformancePitfall("Very slow on remote execution algebras") - public fun StructureND.map(transform: C.(T) -> T): StructureND = structureND(shape) { index -> - elementAlgebra.transform(get(index)) - } + public fun StructureND.map(transform: C.(T) -> T): StructureND /** * Maps elements from one structure to another one by applying [transform] to them alongside with their indices. */ - @PerformancePitfall("Very slow on remote execution algebras") - public fun StructureND.mapIndexed(transform: C.(index: IntArray, T) -> T): StructureND = - structureND(shape) { index -> - elementAlgebra.transform(index, get(index)) - } + public fun StructureND.mapIndexed(transform: C.(index: IntArray, T) -> T): StructureND /** * Combines two structures into one. */ - @PerformancePitfall("Very slow on remote execution algebras") - public fun zip(left: StructureND, right: StructureND, transform: C.(T, T) -> T): StructureND { - require(left.shape.contentEquals(right.shape)) { - "Expected left and right of the same shape, but left - ${left.shape} and right - ${right.shape}" - } - return structureND(left.shape) { index -> - elementAlgebra.transform(left[index], right[index]) - } - } + public fun combine(a: StructureND, b: StructureND, transform: C.(T, T) -> T): StructureND /** * Element-wise invocation of function working on [T] on a [StructureND]. */ - @PerformancePitfall public operator fun Function1.invoke(structure: StructureND): StructureND = structure.map { value -> this@invoke(value) } @@ -98,6 +77,7 @@ public interface AlgebraND>: Algebra> { public companion object } + /** * Get a feature of the structure in this scope. Structure features take precedence other context features. * @@ -109,23 +89,46 @@ public interface AlgebraND>: Algebra> { public inline fun AlgebraND.getFeature(structure: StructureND): F? = getFeature(structure, F::class) +/** + * Checks if given elements are consistent with this context. + * + * @param structures the structures to check. + * @return the array of valid structures. + */ +internal fun > AlgebraND.checkShape(vararg structures: StructureND): Array> = + structures + .map(StructureND::shape) + .singleOrNull { !shape.contentEquals(it) } + ?.let>> { throw ShapeMismatchException(shape, it) } + ?: structures + +/** + * Checks if given element is consistent with this context. + * + * @param element the structure to check. + * @return the valid structure. + */ +internal fun > AlgebraND.checkShape(element: StructureND): StructureND { + if (!element.shape.contentEquals(shape)) throw ShapeMismatchException(shape, element.shape) + return element +} + /** * Space of [StructureND]. * * @param T the type of the element contained in ND structure. - * @param A the type of group over structure elements. + * @param S the type of group over structure elements. */ -public interface GroupOpsND> : GroupOps>, AlgebraND { +public interface GroupND> : Group>, AlgebraND { /** * Element-wise addition. * - * @param left the augend. - * @param right the addend. + * @param a the augend. + * @param b the addend. * @return the sum. */ - @OptIn(PerformancePitfall::class) - override fun add(left: StructureND, right: StructureND): StructureND = - zip(left, right) { aValue, bValue -> add(aValue, bValue) } + override fun add(a: StructureND, b: StructureND): StructureND = + combine(a, b) { aValue, bValue -> add(aValue, bValue) } // TODO move to extensions after KEEP-176 @@ -136,7 +139,6 @@ public interface GroupOpsND> : GroupOps>, * @param arg the addend. * @return the sum. */ - @OptIn(PerformancePitfall::class) public operator fun StructureND.plus(arg: T): StructureND = this.map { value -> add(arg, value) } /** @@ -146,7 +148,6 @@ public interface GroupOpsND> : GroupOps>, * @param arg the divisor. * @return the quotient. */ - @OptIn(PerformancePitfall::class) public operator fun StructureND.minus(arg: T): StructureND = this.map { value -> add(arg, -value) } /** @@ -156,7 +157,6 @@ public interface GroupOpsND> : GroupOps>, * @param arg the addend. * @return the sum. */ - @OptIn(PerformancePitfall::class) public operator fun T.plus(arg: StructureND): StructureND = arg.map { value -> add(this@plus, value) } /** @@ -166,33 +166,27 @@ public interface GroupOpsND> : GroupOps>, * @param arg the divisor. * @return the quotient. */ - @OptIn(PerformancePitfall::class) public operator fun T.minus(arg: StructureND): StructureND = arg.map { value -> add(-this@minus, value) } public companion object } -public interface GroupND> : Group>, GroupOpsND, WithShape { - override val zero: StructureND get() = structureND(shape) { elementAlgebra.zero } -} - /** * Ring of [StructureND]. * * @param T the type of the element contained in ND structure. - * @param A the type of ring over structure elements. + * @param R the type of ring over structure elements. */ -public interface RingOpsND> : RingOps>, GroupOpsND { +public interface RingND> : Ring>, GroupND { /** * Element-wise multiplication. * - * @param left the multiplicand. - * @param right the multiplier. + * @param a the multiplicand. + * @param b the multiplier. * @return the product. */ - @OptIn(PerformancePitfall::class) - override fun multiply(left: StructureND, right: StructureND): StructureND = - zip(left, right) { aValue, bValue -> multiply(aValue, bValue) } + override fun multiply(a: StructureND, b: StructureND): StructureND = + combine(a, b) { aValue, bValue -> multiply(aValue, bValue) } //TODO move to extensions after KEEP-176 @@ -203,7 +197,6 @@ public interface RingOpsND> : RingOps>, Gro * @param arg the multiplier. * @return the product. */ - @OptIn(PerformancePitfall::class) public operator fun StructureND.times(arg: T): StructureND = this.map { value -> multiply(arg, value) } /** @@ -213,39 +206,29 @@ public interface RingOpsND> : RingOps>, Gro * @param arg the multiplier. * @return the product. */ - @OptIn(PerformancePitfall::class) public operator fun T.times(arg: StructureND): StructureND = arg.map { value -> multiply(this@times, value) } public companion object } -public interface RingND> : Ring>, RingOpsND, GroupND, WithShape { - override val one: StructureND get() = structureND(shape) { elementAlgebra.one } -} - - /** * Field of [StructureND]. * * @param T the type of the element contained in ND structure. - * @param A the type field over structure elements. + * @param F the type field over structure elements. */ -public interface FieldOpsND> : - FieldOps>, - RingOpsND, - ScaleOperations> { +public interface FieldND> : Field>, RingND { /** * Element-wise division. * - * @param left the dividend. - * @param right the divisor. + * @param a the dividend. + * @param b the divisor. * @return the quotient. */ - @OptIn(PerformancePitfall::class) - override fun divide(left: StructureND, right: StructureND): StructureND = - zip(left, right) { aValue, bValue -> divide(aValue, bValue) } + override fun divide(a: StructureND, b: StructureND): StructureND = + combine(a, b) { aValue, bValue -> divide(aValue, bValue) } - //TODO move to extensions after https://github.com/Kotlin/KEEP/blob/master/proposals/context-receivers.md + //TODO move to extensions after KEEP-176 /** * Divides an ND structure by an element of it. * @@ -253,7 +236,6 @@ public interface FieldOpsND> : * @param arg the divisor. * @return the quotient. */ - @OptIn(PerformancePitfall::class) public operator fun StructureND.div(arg: T): StructureND = this.map { value -> divide(arg, value) } /** @@ -263,13 +245,44 @@ public interface FieldOpsND> : * @param arg the divisor. * @return the quotient. */ - @OptIn(PerformancePitfall::class) public operator fun T.div(arg: StructureND): StructureND = arg.map { divide(it, this@div) } - @OptIn(PerformancePitfall::class) + /** + * Element-wise scaling. + * + * @param a the multiplicand. + * @param value the multiplier. + * @return the product. + */ override fun scale(a: StructureND, value: Double): StructureND = a.map { scale(it, value) } -} -public interface FieldND> : Field>, FieldOpsND, RingND, WithShape { - override val one: StructureND get() = structureND(shape) { elementAlgebra.one } -} \ No newline at end of file +// @ThreadLocal +// public companion object { +// private val realNDFieldCache: MutableMap = hashMapOf() +// +// /** +// * Create a nd-field for [Double] values or pull it from cache if it was created previously. +// */ +// public fun real(vararg shape: Int): RealNDField = realNDFieldCache.getOrPut(shape) { RealNDField(shape) } +// +// /** +// * Create an ND field with boxing generic buffer. +// */ +// public fun > boxing( +// field: F, +// vararg shape: Int, +// bufferFactory: BufferFactory = Buffer.Companion::boxing, +// ): BufferedNDField = BufferedNDField(shape, field, bufferFactory) +// +// /** +// * Create a most suitable implementation for nd-field using reified class. +// */ +// @Suppress("UNCHECKED_CAST") +// public inline fun > auto(field: F, vararg shape: Int): NDField = +// when { +// T::class == Double::class -> real(*shape) as NDField +// T::class == Complex::class -> complex(*shape) as BufferedNDField +// else -> BoxingNDField(shape, field, Buffer.Companion::auto) +// } +// } +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt index b09344d12..9ece51ff8 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt @@ -1,199 +1,142 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ -@file:OptIn(UnstableKMathAPI::class) - package space.kscience.kmath.nd -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.* +import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract public interface BufferAlgebraND> : AlgebraND { - public val indexerBuilder: (IntArray) -> ShapeIndexer - public val bufferAlgebra: BufferAlgebra - override val elementAlgebra: A get() = bufferAlgebra.elementAlgebra + public val strides: Strides + public val bufferFactory: BufferFactory - override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): BufferND { - val indexer = indexerBuilder(shape) - return BufferND( - indexer, - bufferAlgebra.buffer(indexer.linearSize) { offset -> - elementAlgebra.initializer(indexer.index(offset)) - } - ) - } - - public fun StructureND.toBufferND(): BufferND = when (this) { - is BufferND -> this - else -> { - val indexer = indexerBuilder(shape) - BufferND(indexer, bufferAlgebra.buffer(indexer.linearSize) { offset -> get(indexer.index(offset)) }) + override fun produce(initializer: A.(IntArray) -> T): BufferND = BufferND( + strides, + bufferFactory(strides.linearSize) { offset -> + elementContext.initializer(strides.index(offset)) } + ) + + public val StructureND.buffer: Buffer + get() = when { + !shape.contentEquals(this@BufferAlgebraND.shape) -> throw ShapeMismatchException( + this@BufferAlgebraND.shape, + shape + ) + this is BufferND && this.strides == this@BufferAlgebraND.strides -> this.buffer + else -> bufferFactory(strides.linearSize) { offset -> get(strides.index(offset)) } + } + + override fun StructureND.map(transform: A.(T) -> T): BufferND { + val buffer = bufferFactory(strides.linearSize) { offset -> + elementContext.transform(buffer[offset]) + } + return BufferND(strides, buffer) } - @PerformancePitfall - override fun StructureND.map(transform: A.(T) -> T): BufferND = mapInline(toBufferND(), transform) + override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): BufferND { + val buffer = bufferFactory(strides.linearSize) { offset -> + elementContext.transform( + strides.index(offset), + buffer[offset] + ) + } + return BufferND(strides, buffer) + } - @PerformancePitfall - override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): BufferND = - mapIndexedInline(toBufferND(), transform) - - @PerformancePitfall - override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): BufferND = - zipInline(left.toBufferND(), right.toBufferND(), transform) - - public companion object { - public val defaultIndexerBuilder: (IntArray) -> ShapeIndexer = DefaultStrides.Companion::invoke + override fun combine(a: StructureND, b: StructureND, transform: A.(T, T) -> T): BufferND { + val buffer = bufferFactory(strides.linearSize) { offset -> + elementContext.transform(a.buffer[offset], b.buffer[offset]) + } + return BufferND(strides, buffer) } } -public inline fun > BufferAlgebraND.mapInline( - arg: BufferND, - crossinline transform: A.(T) -> T, -): BufferND { - val indexes = arg.indices - val buffer = arg.buffer - return BufferND( - indexes, - bufferAlgebra.run { - bufferFactory(buffer.size) { elementAlgebra.transform(buffer[it]) } - } - ) +public open class BufferedGroupND>( + final override val shape: IntArray, + final override val elementContext: A, + final override val bufferFactory: BufferFactory, +) : GroupND, BufferAlgebraND { + override val strides: Strides = DefaultStrides(shape) + override val zero: BufferND by lazy { produce { zero } } + override fun StructureND.unaryMinus(): StructureND = produce { -get(it) } } -internal inline fun > BufferAlgebraND.mapIndexedInline( - arg: BufferND, - crossinline transform: A.(index: IntArray, arg: T) -> T, -): BufferND { - val indexes = arg.indices - val buffer = arg.buffer - return BufferND( - indexes, - bufferAlgebra.run { - bufferFactory(buffer.size) { elementAlgebra.transform(indexes.index(it), buffer[it]) } - } - ) +public open class BufferedRingND>( + shape: IntArray, + elementContext: R, + bufferFactory: BufferFactory, +) : BufferedGroupND(shape, elementContext, bufferFactory), RingND { + override val one: BufferND by lazy { produce { one } } } -internal inline fun > BufferAlgebraND.zipInline( - l: BufferND, - r: BufferND, - crossinline block: A.(l: T, r: T) -> T, -): BufferND { - require(l.indices == r.indices) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" } - val indexes = l.indices - val lbuffer = l.buffer - val rbuffer = r.buffer - return BufferND( - indexes, - bufferAlgebra.run { - bufferFactory(lbuffer.size) { elementAlgebra.block(lbuffer[it], rbuffer[it]) } - } - ) -} +public open class BufferedFieldND>( + shape: IntArray, + elementContext: R, + bufferFactory: BufferFactory, +) : BufferedRingND(shape, elementContext, bufferFactory), FieldND { -@OptIn(PerformancePitfall::class) -public open class BufferedGroupNDOps>( - override val bufferAlgebra: BufferAlgebra, - override val indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder, -) : GroupOpsND, BufferAlgebraND { - override fun StructureND.unaryMinus(): StructureND = map { -it } -} - -public open class BufferedRingOpsND>( - bufferAlgebra: BufferAlgebra, - indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder, -) : BufferedGroupNDOps(bufferAlgebra, indexerBuilder), RingOpsND - -public open class BufferedFieldOpsND>( - bufferAlgebra: BufferAlgebra, - indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder, -) : BufferedRingOpsND(bufferAlgebra, indexerBuilder), FieldOpsND { - - public constructor( - elementAlgebra: A, - bufferFactory: BufferFactory, - indexerBuilder: (IntArray) -> ShapeIndexer = BufferAlgebraND.defaultIndexerBuilder, - ) : this(BufferFieldOps(elementAlgebra, bufferFactory), indexerBuilder) - - @OptIn(PerformancePitfall::class) override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } } -public val > BufferAlgebra.nd: BufferedGroupNDOps get() = BufferedGroupNDOps(this) -public val > BufferAlgebra.nd: BufferedRingOpsND get() = BufferedRingOpsND(this) -public val > BufferAlgebra.nd: BufferedFieldOpsND get() = BufferedFieldOpsND(this) - - -public fun > BufferAlgebraND.structureND( +// group factories +public fun > AlgebraND.Companion.group( + space: A, + bufferFactory: BufferFactory, vararg shape: Int, - initializer: A.(IntArray) -> T, -): BufferND = structureND(shape, initializer) +): BufferedGroupND = BufferedGroupND(shape, space, bufferFactory) -public fun , A> A.structureND( - initializer: EA.(IntArray) -> T, -): BufferND where A : BufferAlgebraND, A : WithShape = structureND(shape, initializer) +public inline fun , R> A.ndGroup( + noinline bufferFactory: BufferFactory, + vararg shape: Int, + action: BufferedGroupND.() -> R, +): R { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return AlgebraND.group(this, bufferFactory, *shape).run(action) +} -//// group factories -//public fun > A.ndAlgebra( -// bufferAlgebra: BufferAlgebra, -// vararg shape: Int, -//): BufferedGroupNDOps = BufferedGroupNDOps(bufferAlgebra) -// -//@JvmName("withNdGroup") -//public inline fun , R> A.withNdAlgebra( -// noinline bufferFactory: BufferFactory, -// vararg shape: Int, -// action: BufferedGroupNDOps.() -> R, -//): R { -// contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } -// return ndAlgebra(bufferFactory, *shape).run(action) -//} +//ring factories +public fun > AlgebraND.Companion.ring( + ring: A, + bufferFactory: BufferFactory, + vararg shape: Int, +): BufferedRingND = BufferedRingND(shape, ring, bufferFactory) -////ring factories -//public fun > A.ndAlgebra( -// bufferFactory: BufferFactory, -// vararg shape: Int, -//): BufferedRingNDOps = BufferedRingNDOps(shape, this, bufferFactory) -// -//@JvmName("withNdRing") -//public inline fun , R> A.withNdAlgebra( -// noinline bufferFactory: BufferFactory, -// vararg shape: Int, -// action: BufferedRingNDOps.() -> R, -//): R { -// contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } -// return ndAlgebra(bufferFactory, *shape).run(action) -//} -// -////field factories -//public fun > A.ndAlgebra( -// bufferFactory: BufferFactory, -// vararg shape: Int, -//): BufferedFieldNDOps = BufferedFieldNDOps(shape, this, bufferFactory) -// -///** -// * Create a [FieldND] for this [Field] inferring proper buffer factory from the type -// */ -//@UnstableKMathAPI -//@Suppress("UNCHECKED_CAST") -//public inline fun > A.autoNdAlgebra( -// vararg shape: Int, -//): FieldND = when (this) { -// DoubleField -> DoubleFieldND(shape) as FieldND -// else -> BufferedFieldNDOps(shape, this, Buffer.Companion::auto) -//} -// -//@JvmName("withNdField") -//public inline fun , R> A.withNdAlgebra( -// noinline bufferFactory: BufferFactory, -// vararg shape: Int, -// action: BufferedFieldNDOps.() -> R, -//): R { -// contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } -// return ndAlgebra(bufferFactory, *shape).run(action) -//} \ No newline at end of file +public inline fun , R> A.ndRing( + noinline bufferFactory: BufferFactory, + vararg shape: Int, + action: BufferedRingND.() -> R, +): R { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return AlgebraND.ring(this, bufferFactory, *shape).run(action) +} + +//field factories +public fun > AlgebraND.Companion.field( + field: A, + bufferFactory: BufferFactory, + vararg shape: Int, +): BufferedFieldND = BufferedFieldND(shape, field, bufferFactory) + +@Suppress("UNCHECKED_CAST") +public inline fun > AlgebraND.Companion.auto( + field: A, + vararg shape: Int, +): FieldND = when (field) { + DoubleField -> DoubleFieldND(shape) as FieldND + else -> BufferedFieldND(shape, field, Buffer.Companion::auto) +} + +public inline fun , R> A.ndField( + noinline bufferFactory: BufferFactory, + vararg shape: Int, + action: BufferedFieldND.() -> R, +): R { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + return AlgebraND.field(this, bufferFactory, *shape).run(action) +} \ No newline at end of file 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 539499794..694e0ceae 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 @@ -1,10 +1,11 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.nd +import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import space.kscience.kmath.structures.MutableBuffer @@ -14,17 +15,28 @@ import space.kscience.kmath.structures.MutableBufferFactory * Represents [StructureND] over [Buffer]. * * @param T the type of items. - * @param indices The strides to access elements of [Buffer] by linear indices. + * @param strides The strides to access elements of [Buffer] by linear indices. * @param buffer The underlying buffer. */ public open class BufferND( - override val indices: ShapeIndexer, - public open val buffer: Buffer, + public val strides: Strides, + public val buffer: Buffer, ) : StructureND { - override operator fun get(index: IntArray): T = buffer[indices.offset(index)] + init { + if (strides.linearSize != buffer.size) { + error("Expected buffer side of ${strides.linearSize}, but found ${buffer.size}") + } + } - override val shape: IntArray get() = indices.shape + override operator fun get(index: IntArray): T = buffer[strides.offset(index)] + + override val shape: IntArray get() = strides.shape + + @PerformancePitfall + override fun elements(): Sequence> = strides.indices().map { + it to this[it] + } override fun toString(): String = StructureND.toString(this) } @@ -37,7 +49,7 @@ public inline fun StructureND.mapToBuffer( crossinline transform: (T) -> R, ): BufferND { return if (this is BufferND) - BufferND(this.indices, factory.invoke(indices.linearSize) { transform(buffer[it]) }) + BufferND(this.strides, factory.invoke(strides.linearSize) { transform(buffer[it]) }) else { val strides = DefaultStrides(shape) BufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) @@ -49,14 +61,14 @@ public inline fun StructureND.mapToBuffer( * * @param T the type of items. * @param strides The strides to access elements of [MutableBuffer] by linear indices. - * @param buffer The underlying buffer. + * @param mutableBuffer The underlying buffer. */ public class MutableBufferND( - strides: ShapeIndexer, - override val buffer: MutableBuffer, -) : MutableStructureND, BufferND(strides, buffer) { + strides: Strides, + public val mutableBuffer: MutableBuffer, +) : MutableStructureND, BufferND(strides, mutableBuffer) { override fun set(index: IntArray, value: T) { - buffer[indices.offset(index)] = value + mutableBuffer[strides.offset(index)] = value } } @@ -68,7 +80,7 @@ public inline fun MutableStructureND.mapToMutableBuffer( crossinline transform: (T) -> R, ): MutableBufferND { return if (this is MutableBufferND) - MutableBufferND(this.indices, factory.invoke(indices.linearSize) { transform(buffer[it]) }) + 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))) }) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt index d01a8ee95..a448e351e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt @@ -1,223 +1,114 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.nd -import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.operations.NumbersAddOperations +import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.structures.DoubleBuffer import kotlin.contracts.InvocationKind import kotlin.contracts.contract -import kotlin.math.pow as kpow - -public class DoubleBufferND( - indexes: ShapeIndexer, - override val buffer: DoubleBuffer, -) : BufferND(indexes, buffer) - - -public sealed class DoubleFieldOpsND : BufferedFieldOpsND(DoubleField.bufferAlgebra), - ScaleOperations>, ExtendedFieldOps> { - - override fun StructureND.toBufferND(): DoubleBufferND = when (this) { - is DoubleBufferND -> this - else -> { - val indexer = indexerBuilder(shape) - DoubleBufferND(indexer, DoubleBuffer(indexer.linearSize) { offset -> get(indexer.index(offset)) }) - } - } - - protected inline fun mapInline( - arg: DoubleBufferND, - transform: (Double) -> Double, - ): DoubleBufferND { - val indexes = arg.indices - val array = arg.buffer.array - return DoubleBufferND(indexes, DoubleBuffer(indexes.linearSize) { transform(array[it]) }) - } - - private inline fun zipInline( - l: DoubleBufferND, - r: DoubleBufferND, - block: (l: Double, r: Double) -> Double, - ): DoubleBufferND { - require(l.indices == r.indices) { "Zip requires the same shapes, but found ${l.shape} on the left and ${r.shape} on the right" } - val indexes = l.indices - val lArray = l.buffer.array - val rArray = r.buffer.array - return DoubleBufferND(indexes, DoubleBuffer(indexes.linearSize) { block(lArray[it], rArray[it]) }) - } - - @OptIn(PerformancePitfall::class) - override fun StructureND.map(transform: DoubleField.(Double) -> Double): BufferND = - mapInline(toBufferND()) { DoubleField.transform(it) } - - - @OptIn(PerformancePitfall::class) - override fun zip( - left: StructureND, - right: StructureND, - transform: DoubleField.(Double, Double) -> Double, - ): BufferND = zipInline(left.toBufferND(), right.toBufferND()) { l, r -> DoubleField.transform(l, r) } - - override fun structureND(shape: Shape, initializer: DoubleField.(IntArray) -> Double): DoubleBufferND { - val indexer = indexerBuilder(shape) - return DoubleBufferND( - indexer, - DoubleBuffer(indexer.linearSize) { offset -> - elementAlgebra.initializer(indexer.index(offset)) - } - ) - } - - override fun add(left: StructureND, right: StructureND): DoubleBufferND = - zipInline(left.toBufferND(), right.toBufferND()) { l, r -> l + r } - - override fun multiply(left: StructureND, right: StructureND): DoubleBufferND = - zipInline(left.toBufferND(), right.toBufferND()) { l, r -> l * r } - - override fun StructureND.unaryMinus(): DoubleBufferND = mapInline(toBufferND()) { -it } - - override fun StructureND.div(arg: StructureND): DoubleBufferND = - zipInline(toBufferND(), arg.toBufferND()) { l, r -> l / r } - - override fun divide(left: StructureND, right: StructureND): DoubleBufferND = - zipInline(left.toBufferND(), right.toBufferND()) { l: Double, r: Double -> l / r } - - override fun StructureND.div(arg: Double): DoubleBufferND = - mapInline(toBufferND()) { it / arg } - - override fun Double.div(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { this / it } - - override fun StructureND.unaryPlus(): DoubleBufferND = toBufferND() - - override fun StructureND.plus(arg: StructureND): DoubleBufferND = - zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l + r } - - override fun StructureND.minus(arg: StructureND): DoubleBufferND = - zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l - r } - - override fun StructureND.times(arg: StructureND): DoubleBufferND = - zipInline(toBufferND(), arg.toBufferND()) { l: Double, r: Double -> l * r } - - override fun StructureND.times(k: Number): DoubleBufferND = - mapInline(toBufferND()) { it * k.toDouble() } - - override fun StructureND.div(k: Number): DoubleBufferND = - mapInline(toBufferND()) { it / k.toDouble() } - - override fun Number.times(arg: StructureND): DoubleBufferND = arg * this - - override fun StructureND.plus(arg: Double): DoubleBufferND = mapInline(toBufferND()) { it + arg } - - override fun StructureND.minus(arg: Double): StructureND = mapInline(toBufferND()) { it - arg } - - override fun Double.plus(arg: StructureND): StructureND = arg + this - - override fun Double.minus(arg: StructureND): StructureND = mapInline(arg.toBufferND()) { this - it } - - override fun scale(a: StructureND, value: Double): DoubleBufferND = - mapInline(a.toBufferND()) { it * value } - - override fun exp(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.exp(it) } - - override fun ln(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.ln(it) } - - override fun sin(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.sin(it) } - - override fun cos(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.cos(it) } - - override fun tan(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.tan(it) } - - override fun asin(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.asin(it) } - - override fun acos(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.acos(it) } - - override fun atan(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.atan(it) } - - override fun sinh(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.sinh(it) } - - override fun cosh(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.cosh(it) } - - override fun tanh(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.tanh(it) } - - override fun asinh(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.asinh(it) } - - override fun acosh(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.acosh(it) } - - override fun atanh(arg: StructureND): DoubleBufferND = - mapInline(arg.toBufferND()) { kotlin.math.atanh(it) } - - public companion object : DoubleFieldOpsND() -} @OptIn(UnstableKMathAPI::class) -public class DoubleFieldND(override val shape: Shape) : - DoubleFieldOpsND(), FieldND, NumbersAddOps>, +public class DoubleFieldND( + shape: IntArray, +) : BufferedFieldND(shape, DoubleField, ::DoubleBuffer), + NumbersAddOperations>, + ScaleOperations>, ExtendedField> { - override fun power(arg: StructureND, pow: UInt): DoubleBufferND = mapInline(arg.toBufferND()) { - it.kpow(pow.toInt()) - } + override val zero: BufferND by lazy { produce { zero } } + override val one: BufferND by lazy { produce { one } } - override fun power(arg: StructureND, pow: Int): DoubleBufferND = mapInline(arg.toBufferND()) { - it.kpow(pow) - } - - override fun power(arg: StructureND, pow: Number): DoubleBufferND = if(pow.isInteger()){ - power(arg, pow.toInt()) - } else { - val dpow = pow.toDouble() - mapInline(arg.toBufferND()) { - if (it < 0) throw IllegalArgumentException("Can't raise negative $it to a fractional power") - else it.kpow(dpow) - } - } - - override fun sinh(arg: StructureND): DoubleBufferND = super.sinh(arg) - - override fun cosh(arg: StructureND): DoubleBufferND = super.cosh(arg) - - override fun tanh(arg: StructureND): DoubleBufferND = super.tan(arg) - - override fun asinh(arg: StructureND): DoubleBufferND = super.asinh(arg) - - override fun acosh(arg: StructureND): DoubleBufferND = super.acosh(arg) - - override fun atanh(arg: StructureND): DoubleBufferND = super.atanh(arg) - - override fun number(value: Number): DoubleBufferND { + override fun number(value: Number): BufferND { val d = value.toDouble() // minimize conversions - return structureND(shape) { d } + return produce { d } } + + override val StructureND.buffer: DoubleBuffer + get() = when { + !shape.contentEquals(this@DoubleFieldND.shape) -> throw ShapeMismatchException( + this@DoubleFieldND.shape, + shape + ) + this is BufferND && this.strides == this@DoubleFieldND.strides -> this.buffer as DoubleBuffer + else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) } + } + + @Suppress("OVERRIDE_BY_INLINE") + override inline fun StructureND.map( + transform: DoubleField.(Double) -> Double, + ): BufferND { + val buffer = DoubleBuffer(strides.linearSize) { offset -> DoubleField.transform(buffer.array[offset]) } + return BufferND(strides, buffer) + } + + @Suppress("OVERRIDE_BY_INLINE") + override inline fun produce(initializer: DoubleField.(IntArray) -> Double): BufferND { + val array = DoubleArray(strides.linearSize) { offset -> + val index = strides.index(offset) + DoubleField.initializer(index) + } + return BufferND(strides, DoubleBuffer(array)) + } + + @Suppress("OVERRIDE_BY_INLINE") + override inline fun StructureND.mapIndexed( + transform: DoubleField.(index: IntArray, Double) -> Double, + ): BufferND = BufferND( + strides, + buffer = DoubleBuffer(strides.linearSize) { offset -> + DoubleField.transform( + strides.index(offset), + buffer.array[offset] + ) + }) + + @Suppress("OVERRIDE_BY_INLINE") + override inline fun combine( + a: StructureND, + b: StructureND, + transform: DoubleField.(Double, Double) -> Double, + ): BufferND { + val buffer = DoubleBuffer(strides.linearSize) { offset -> + DoubleField.transform(a.buffer.array[offset], b.buffer.array[offset]) + } + return BufferND(strides, buffer) + } + + override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } + + override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) } + + override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } + override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } + + override fun sin(arg: StructureND): BufferND = arg.map { sin(it) } + override fun cos(arg: StructureND): BufferND = arg.map { cos(it) } + override fun tan(arg: StructureND): BufferND = arg.map { tan(it) } + override fun asin(arg: StructureND): BufferND = arg.map { asin(it) } + override fun acos(arg: StructureND): BufferND = arg.map { acos(it) } + override fun atan(arg: StructureND): BufferND = arg.map { atan(it) } + + override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) } + override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) } + override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) } + override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) } + override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) } + override fun atanh(arg: StructureND): BufferND = arg.map { atanh(it) } } -public val DoubleField.ndAlgebra: DoubleFieldOpsND get() = DoubleFieldOpsND - -public fun DoubleField.ndAlgebra(vararg shape: Int): DoubleFieldND = DoubleFieldND(shape) +public fun AlgebraND.Companion.real(vararg shape: Int): DoubleFieldND = DoubleFieldND(shape) /** * Produce a context for n-dimensional operations inside this real field */ -@UnstableKMathAPI -public inline fun DoubleField.withNdAlgebra(vararg shape: Int, action: DoubleFieldND.() -> R): R { +public inline fun DoubleField.nd(vararg shape: Int, action: DoubleFieldND.() -> R): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } return DoubleFieldND(shape).run(action) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt deleted file mode 100644 index c6ff79587..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShapeIndexer.kt +++ /dev/null @@ -1,121 +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.nd - -import kotlin.native.concurrent.ThreadLocal - -/** - * A converter from linear index to multivariate index - */ -public interface ShapeIndexer: Iterable{ - public val shape: Shape - - /** - * Get linear index from multidimensional index - */ - public fun offset(index: IntArray): Int - - /** - * Get multidimensional from linear - */ - public fun index(offset: Int): IntArray - - /** - * The size of linear buffer to accommodate all elements of ND-structure corresponding to strides - */ - public val linearSize: Int - - // TODO introduce a fast way to calculate index of the next element? - - /** - * Iterate over ND indices in a natural order - */ - public fun asSequence(): Sequence - - override fun iterator(): Iterator = asSequence().iterator() - - override fun equals(other: Any?): Boolean - override fun hashCode(): Int -} - -/** - * Linear transformation of indexes - */ -public abstract class Strides: ShapeIndexer { - /** - * Array strides - */ - public abstract val strides: IntArray - - public 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() - - // TODO introduce a fast way to calculate index of the next element? - - /** - * Iterate over ND indices in a natural order - */ - public override fun asSequence(): Sequence = (0 until linearSize).asSequence().map(::index) -} - -/** - * Simple implementation of [Strides]. - */ -public class DefaultStrides private constructor(override val shape: IntArray) : Strides() { - override val linearSize: Int get() = strides[shape.size] - - /** - * Strides for memory access - */ - override val strides: IntArray by lazy { - sequence { - var current = 1 - yield(1) - - shape.forEach { - current *= it - yield(current) - } - }.toList().toIntArray() - } - - override fun index(offset: Int): IntArray { - val res = IntArray(shape.size) - var current = offset - var strideIndex = strides.size - 2 - - while (strideIndex >= 0) { - res[strideIndex] = (current / strides[strideIndex]) - current %= strides[strideIndex] - strideIndex-- - } - - return res - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is DefaultStrides) return false - if (!shape.contentEquals(other.shape)) return false - return true - } - - override fun hashCode(): Int = shape.contentHashCode() - - - public companion object { - /** - * Cached builder for default strides - */ - public operator fun invoke(shape: IntArray): Strides = - defaultStridesCache.getOrPut(shape) { DefaultStrides(shape) } - } -} - -@ThreadLocal -private val defaultStridesCache = HashMap() \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt index 8152adaa5..f96978cfc 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt @@ -1,33 +1,40 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.nd import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.NumbersAddOps +import space.kscience.kmath.operations.NumbersAddOperations import space.kscience.kmath.operations.ShortRing -import space.kscience.kmath.operations.bufferAlgebra +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.ShortBuffer import kotlin.contracts.InvocationKind import kotlin.contracts.contract -public sealed class ShortRingOpsND : BufferedRingOpsND(ShortRing.bufferAlgebra) { - public companion object : ShortRingOpsND() -} - @OptIn(UnstableKMathAPI::class) public class ShortRingND( - override val shape: Shape -) : ShortRingOpsND(), RingND, NumbersAddOps> { + shape: IntArray, +) : BufferedRingND(shape, ShortRing, Buffer.Companion::auto), + NumbersAddOperations> { + + override val zero: BufferND by lazy { produce { zero } } + override val one: BufferND by lazy { produce { one } } override fun number(value: Number): BufferND { val d = value.toShort() // minimize conversions - return structureND(shape) { d } + return produce { d } } } -public inline fun ShortRing.withNdAlgebra(vararg shape: Int, action: ShortRingND.() -> R): R { +/** + * Fast element production using function inlining. + */ +public inline fun BufferedRingND.produceInline(crossinline initializer: ShortRing.(Int) -> Short): BufferND = + BufferND(strides, ShortBuffer(ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) })) + +public inline fun ShortRing.nd(vararg shape: Int, action: ShortRingND.() -> R): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } return ShortRingND(shape).run(action) } 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 4ccb15eef..d0e2354d2 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,15 +1,15 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.nd import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.operations.asSequence import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.structures.asMutableBuffer +import space.kscience.kmath.structures.asSequence import kotlin.jvm.JvmInline /** @@ -67,14 +67,12 @@ private class MutableStructure1DWrapper(val structure: MutableStructureND) structure[intArrayOf(index)] = value } - @OptIn(PerformancePitfall::class) + @PerformancePitfall override fun copy(): MutableBuffer = structure .elements() .map(Pair::second) .toMutableList() .asMutableBuffer() - - override fun toString(): String = Buffer.toString(this) } @@ -109,8 +107,6 @@ internal class MutableBuffer1DWrapper(val buffer: MutableBuffer) : Mutable } override fun copy(): MutableBuffer = buffer.copy() - - override fun toString(): String = Buffer.toString(this) } /** @@ -136,7 +132,7 @@ public fun Buffer.asND(): Structure1D = Buffer1DWrapper(this) /** * Expose inner buffer of this [Structure1D] if possible */ -internal fun Structure1D.asND(): Buffer = when { +internal fun Structure1D.unwrap(): Buffer = when { this is Buffer1DWrapper -> buffer this is Structure1DWrapper && structure is BufferND -> structure.buffer else -> 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 cf8559869..7fb8ea251 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 @@ -1,11 +1,12 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.nd import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableListBuffer import space.kscience.kmath.structures.VirtualBuffer @@ -85,7 +86,7 @@ public interface MutableStructure2D : Structure2D, MutableStructureND { */ @PerformancePitfall override val rows: List> - get() = List(rowNum) { i -> MutableBuffer1DWrapper(MutableListBuffer(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. @@ -100,13 +101,14 @@ public interface MutableStructure2D : Structure2D, MutableStructureND { */ @JvmInline private value class Structure2DWrapper(val structure: StructureND) : Structure2D { - override val shape: Shape get() = structure.shape + 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] + @UnstableKMathAPI override fun getFeature(type: KClass): F? = structure.getFeature(type) @PerformancePitfall @@ -116,8 +118,9 @@ private value class Structure2DWrapper(val structure: StructureND) : S /** * A 2D wrapper for a mutable nd-structure */ -private class MutableStructure2DWrapper(val structure: MutableStructureND) : MutableStructure2D { - override val shape: Shape get() = structure.shape +private class MutableStructure2DWrapper(val structure: MutableStructureND): MutableStructure2D +{ + override val shape: IntArray get() = structure.shape override val rowNum: Int get() = shape[0] override val colNum: Int get() = shape[1] @@ -128,7 +131,7 @@ private class MutableStructure2DWrapper(val structure: MutableStructureND) structure[index] = value } - override operator fun set(i: Int, j: Int, value: T) { + override operator fun set(i: Int, j: Int, value: T){ structure[intArrayOf(i, j)] = value } @@ -151,19 +154,18 @@ public fun StructureND.as2D(): Structure2D = this as? Structure2D ? /** * Represents a [StructureND] as [Structure2D]. Throws runtime error in case of dimension mismatch. */ -public fun MutableStructureND.as2D(): MutableStructure2D = - this as? MutableStructure2D ?: when (shape.size) { - 2 -> MutableStructure2DWrapper(this) - else -> error("Can't create 2d-structure from ${shape.size}d-structure") - } +public fun MutableStructureND.as2D(): MutableStructure2D = this as? MutableStructure2D ?: when (shape.size) { + 2 -> MutableStructure2DWrapper(this) + else -> error("Can't create 2d-structure from ${shape.size}d-structure") +} /** * Expose inner [StructureND] if possible */ -internal fun Structure2D.asND(): StructureND = +internal fun Structure2D.unwrap(): StructureND = if (this is Structure2DWrapper) structure else this -internal fun MutableStructure2D.asND(): MutableStructureND = +internal fun MutableStructure2D.unwrap(): MutableStructureND = if (this is MutableStructure2DWrapper) structure else this 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 d948cf36f..45153f7bd 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 @@ -1,23 +1,22 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.nd import space.kscience.kmath.linear.LinearSpace -import space.kscience.kmath.misc.Feature -import space.kscience.kmath.misc.Featured import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.invoke import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.BufferFactory import kotlin.jvm.JvmName -import kotlin.math.abs +import kotlin.native.concurrent.ThreadLocal import kotlin.reflect.KClass -public interface StructureFeature : Feature +public interface StructureFeature /** * Represents n-dimensional structure i.e., multidimensional container of items of the same type and size. The number @@ -28,12 +27,12 @@ public interface StructureFeature : Feature * * @param T the type of items. */ -public interface StructureND : Featured, WithShape { +public interface StructureND { /** * The shape of structure i.e., non-empty sequence of non-negative integers that specify sizes of dimensions of * this structure. */ - override val shape: Shape + public val shape: IntArray /** * The count of dimensions in this structure. It should be equal to size of [shape]. @@ -54,13 +53,14 @@ public interface StructureND : Featured, WithShape { * @return the lazy sequence of pairs of indices to values. */ @PerformancePitfall - public fun elements(): Sequence> = indices.asSequence().map { it to get(it) } + public fun elements(): Sequence> /** * Feature is some additional structure information that allows to access it special properties or hints. * If the feature is not present, `null` is returned. */ - override fun getFeature(type: KClass): F? = null + @UnstableKMathAPI + public fun getFeature(type: KClass): F? = null public companion object { /** @@ -71,29 +71,13 @@ public interface StructureND : Featured, WithShape { if (st1 === st2) return true // fast comparison of buffers if possible - if (st1 is BufferND && st2 is BufferND && st1.indices == st2.indices) + if (st1 is BufferND && st2 is BufferND && st1.strides == st2.strides) return Buffer.contentEquals(st1.buffer, st2.buffer) //element by element comparison if it could not be avoided return st1.elements().all { (index, value) -> value == st2[index] } } - @PerformancePitfall - public fun contentEquals( - st1: StructureND, - st2: StructureND, - tolerance: Double = 1e-11 - ): Boolean { - if (st1 === st2) return true - - // fast comparison of buffers if possible - if (st1 is BufferND && st2 is BufferND && st1.indices == st2.indices) - return Buffer.contentEquals(st1.buffer, st2.buffer) - - //element by element comparison if it could not be avoided - return st1.elements().all { (index, value) -> abs(value - st2[index]) < tolerance } - } - /** * Debug output to string */ @@ -186,11 +170,11 @@ public fun > LinearSpace>.contentEquals( * Indicates whether some [StructureND] is equal to another one with [absoluteTolerance]. */ @PerformancePitfall -public fun > GroupOpsND>.contentEquals( +public fun > GroupND>.contentEquals( st1: StructureND, st2: StructureND, absoluteTolerance: T, -): Boolean = st1.elements().all { (index, value) -> elementAlgebra { (value - st2[index]) } < absoluteTolerance } +): Boolean = st1.elements().all { (index, value) -> elementContext { (value - st2[index]) } < absoluteTolerance } /** * Indicates whether some [StructureND] is equal to another one with [absoluteTolerance]. @@ -210,8 +194,8 @@ public fun > LinearSpace>.contentEquals( */ public operator fun StructureND.get(vararg index: Int): T = get(index) -//@UnstableKMathAPI -//public inline fun StructureND<*>.getFeature(): T? = getFeature(T::class) +@UnstableKMathAPI +public inline fun StructureND<*>.getFeature(): T? = getFeature(T::class) /** * Represents mutable [StructureND]. @@ -230,10 +214,107 @@ public interface MutableStructureND : StructureND { * Transform a structure element-by element in place. */ @OptIn(PerformancePitfall::class) -public inline fun MutableStructureND.mapInPlace(action: (index: IntArray, t: T) -> T): Unit = +public inline fun MutableStructureND.mapInPlace(action: (IntArray, T) -> T): Unit = elements().forEach { (index, oldValue) -> this[index] = action(index, oldValue) } -public inline fun StructureND.zip( +/** + * A way to convert ND indices to linear one and back. + */ +public interface Strides { + /** + * Shape of NDStructure + */ + public val shape: IntArray + + /** + * Array strides + */ + public val strides: IntArray + + /** + * Get linear index from multidimensional index + */ + 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 + */ + public fun index(offset: Int): IntArray + + /** + * The size of linear buffer to accommodate all elements of ND-structure corresponding to strides + */ + public val linearSize: Int + + // TODO introduce a fast way to calculate index of the next element? + + /** + * Iterate over ND indices in a natural order + */ + public fun indices(): Sequence = (0 until linearSize).asSequence().map(::index) +} + +/** + * Simple implementation of [Strides]. + */ +public class DefaultStrides private constructor(override val shape: IntArray) : Strides { + override val linearSize: Int + get() = strides[shape.size] + + /** + * Strides for memory access + */ + override val strides: IntArray by lazy { + sequence { + var current = 1 + yield(1) + + shape.forEach { + current *= it + yield(current) + } + }.toList().toIntArray() + } + + override fun index(offset: Int): IntArray { + val res = IntArray(shape.size) + var current = offset + var strideIndex = strides.size - 2 + + while (strideIndex >= 0) { + res[strideIndex] = (current / strides[strideIndex]) + current %= strides[strideIndex] + strideIndex-- + } + + return res + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is DefaultStrides) return false + if (!shape.contentEquals(other.shape)) return false + return true + } + + override fun hashCode(): Int = shape.contentHashCode() + + @ThreadLocal + public companion object { + private val defaultStridesCache = HashMap() + + /** + * Cached builder for default strides + */ + public operator fun invoke(shape: IntArray): Strides = + defaultStridesCache.getOrPut(shape) { DefaultStrides(shape) } + } +} + +public inline fun StructureND.combine( struct: StructureND, crossinline block: (T, T) -> T, ): StructureND { diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt deleted file mode 100644 index 53f946fbd..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/algebraNDExtentions.kt +++ /dev/null @@ -1,34 +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.nd - -import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.Group -import space.kscience.kmath.operations.Ring -import kotlin.jvm.JvmName - - -public fun > AlgebraND.structureND( - shapeFirst: Int, - vararg shapeRest: Int, - initializer: A.(IntArray) -> T -): StructureND = structureND(Shape(shapeFirst, *shapeRest), initializer) - -public fun > AlgebraND.zero(shape: Shape): StructureND = structureND(shape) { zero } - -@JvmName("zeroVarArg") -public fun > AlgebraND.zero( - shapeFirst: Int, - vararg shapeRest: Int, -): StructureND = structureND(shapeFirst, *shapeRest) { zero } - -public fun > AlgebraND.one(shape: Shape): StructureND = structureND(shape) { one } - -@JvmName("oneVarArg") -public fun > AlgebraND.one( - shapeFirst: Int, - vararg shapeRest: Int, -): StructureND = structureND(shapeFirst, *shapeRest) { one } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt index 45ba32c13..daff58d9a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt @@ -1,13 +1,11 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.operations import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring.Companion.optimizedPower /** * Stub for DSL the [Algebra] is. @@ -101,14 +99,6 @@ public interface Algebra { */ public fun binaryOperation(operation: String, left: T, right: T): T = binaryOperationFunction(operation)(left, right) - - /** - * Export an algebra element, so it could be accessed even after algebra scope is closed. - * This method must be used on algebras where data is stored externally or any local algebra state is used. - * By default (if not overridden), exports the object itself. - */ - @UnstableKMathAPI - public fun export(arg: T): T = arg } public fun Algebra.bindSymbolOrNull(symbol: Symbol): T? = bindSymbolOrNull(symbol.identity) @@ -127,15 +117,15 @@ public inline operator fun , R> A.invoke(block: A.() -> R): R = r * * @param T the type of element of this semispace. */ -public interface GroupOps : Algebra { +public interface GroupOperations : Algebra { /** * Addition of two elements. * - * @param left the augend. - * @param right the addend. + * @param a the augend. + * @param b the addend. * @return the sum. */ - public fun add(left: T, right: T): T + public fun add(a: T, b: T): T // Operations to be performed in this context. Could be moved to extensions in case of KEEP-176. @@ -159,21 +149,20 @@ public interface GroupOps : Algebra { * Addition of two elements. * * @receiver the augend. - * @param arg the addend. + * @param b the addend. * @return the sum. */ - public operator fun T.plus(arg: T): T = add(this, arg) + public operator fun T.plus(b: T): T = add(this, b) /** * Subtraction of two elements. * * @receiver the minuend. - * @param arg the subtrahend. + * @param b the subtrahend. * @return the difference. */ - public operator fun T.minus(arg: T): T = add(this, -arg) + public operator fun T.minus(b: T): T = add(this, -b) - // Dynamic dispatch of operations override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { PLUS_OPERATION -> { arg -> +arg } MINUS_OPERATION -> { arg -> -arg } @@ -204,7 +193,7 @@ public interface GroupOps : Algebra { * * @param T the type of element of this semispace. */ -public interface Group : GroupOps { +public interface Group : GroupOperations { /** * The neutral element of addition. */ @@ -217,22 +206,22 @@ public interface Group : GroupOps { * * @param T the type of element of this semiring. */ -public interface RingOps : GroupOps { +public interface RingOperations : GroupOperations { /** * Multiplies two elements. * - * @param left the multiplier. - * @param right the multiplicand. + * @param a the multiplier. + * @param b the multiplicand. */ - public fun multiply(left: T, right: T): T + public fun multiply(a: T, b: T): T /** * Multiplies this element by scalar. * * @receiver the multiplier. - * @param arg the multiplicand. + * @param b the multiplicand. */ - public operator fun T.times(arg: T): T = multiply(this, arg) + public operator fun T.times(b: T): T = multiply(this, b) override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { TIMES_OPERATION -> ::multiply @@ -253,45 +242,11 @@ public interface RingOps : GroupOps { * * @param T the type of element of this ring. */ -public interface Ring : Group, RingOps { +public interface Ring : Group, RingOperations { /** * The neutral element of multiplication */ public val one: T - - /** - * Raises [arg] to the integer power [pow]. - */ - public fun power(arg: T, pow: UInt): T = optimizedPower(arg, pow) - - public companion object{ - /** - * Raises [arg] to the non-negative integer power [exponent]. - * - * Special case: 0 ^ 0 is 1. - * - * @receiver the algebra to provide multiplication. - * @param arg the base. - * @param exponent the exponent. - * @return the base raised to the power. - * @author Evgeniy Zhelenskiy - */ - internal fun Ring.optimizedPower(arg: T, exponent: UInt): T = when { - arg == zero && exponent > 0U -> zero - arg == one -> arg - arg == -one -> powWithoutOptimization(arg, exponent % 2U) - else -> powWithoutOptimization(arg, exponent) - } - - private fun Ring.powWithoutOptimization(base: T, exponent: UInt): T = when (exponent) { - 0U -> one - 1U -> base - else -> { - val pre = powWithoutOptimization(base, exponent shr 1).let { it * it } - if (exponent and 1U == 0U) pre else pre * base - } - } - } } /** @@ -301,24 +256,24 @@ public interface Ring : Group, RingOps { * * @param T the type of element of this semifield. */ -public interface FieldOps : RingOps { +public interface FieldOperations : RingOperations { /** * Division of two elements. * - * @param left the dividend. - * @param right the divisor. + * @param a the dividend. + * @param b the divisor. * @return the quotient. */ - public fun divide(left: T, right: T): T + public fun divide(a: T, b: T): T /** * Division of two elements. * * @receiver the dividend. - * @param arg the divisor. + * @param b the divisor. * @return the quotient. */ - public operator fun T.div(arg: T): T = divide(this, arg) + public operator fun T.div(b: T): T = divide(this, b) override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { DIV_OPERATION -> ::divide @@ -340,26 +295,6 @@ public interface FieldOps : RingOps { * * @param T the type of element of this field. */ -public interface Field : Ring, FieldOps, ScaleOperations, NumericAlgebra { +public interface Field : Ring, FieldOperations, ScaleOperations, NumericAlgebra { override fun number(value: Number): T = scale(one, value.toDouble()) - - public fun power(arg: T, pow: Int): T = optimizedPower(arg, pow) - - public companion object{ - /** - * Raises [arg] to the integer power [exponent]. - * - * Special case: 0 ^ 0 is 1. - * - * @receiver the algebra to provide multiplication and division. - * @param arg the base. - * @param exponent the exponent. - * @return the base raised to the power. - * @author Iaroslav Postovalov, Evgeniy Zhelenskiy - */ - private fun Field.optimizedPower(arg: T, exponent: Int): T = when { - exponent < 0 -> one / (this as Ring).optimizedPower(arg, if (exponent == Int.MIN_VALUE) Int.MAX_VALUE.toUInt().inc() else (-exponent).toUInt()) - else -> (this as Ring).optimizedPower(arg, exponent.toUInt()) - } - } } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt new file mode 100644 index 000000000..7669e073a --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt @@ -0,0 +1,128 @@ +/* + * 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 file. + */ + +package space.kscience.kmath.operations + +import space.kscience.kmath.misc.UnstableKMathAPI + +/** + * The generic mathematics elements that is able to store its context + * + * @param C the type of mathematical context for this element. + * @param T the type wrapped by this wrapper. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public interface AlgebraElement> { + /** + * The context this element belongs to. + */ + public val context: C +} +// +///** +// * Divides this element by number. +// * +// * @param k the divisor. +// * @return the quotient. +// */ +//public operator fun , S : Space> T.div(k: Number): T = +// context.multiply(this, 1.0 / k.toDouble()) +// +///** +// * Multiplies this element by number. +// * +// * @param k the multiplicand. +// * @return the product. +// */ +//public operator fun , S : Space> T.times(k: Number): T = +// context.multiply(this, k.toDouble()) + +/** + * Subtracts element from this one. + * + * @param b the subtrahend. + * @return the difference. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public operator fun , S : NumbersAddOperations> T.minus(b: T): T = + context.add(this, context.run { -b }) + +/** + * Adds element to this one. + * + * @receiver the augend. + * @param b the addend. + * @return the sum. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public operator fun , S : Ring> T.plus(b: T): T = + context.add(this, b) + +///** +// * Number times element +// */ +//public operator fun , S : Space> Number.times(element: T): T = +// element.times(this) + +/** + * Multiplies this element by another one. + * + * @receiver the multiplicand. + * @param b the multiplier. + * @return the product. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public operator fun , R : Ring> T.times(b: T): T = + context.multiply(this, b) + + +/** + * Divides this element by another one. + * + * @param b the divisor. + * @return the quotient. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public operator fun , F : Field> T.div(b: T): T = + context.divide(this, b) + + +/** + * The element of [Group]. + * + * @param T the type of space operation results. + * @param I self type of the element. Needed for static type checking. + * @param S the type of space. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public interface GroupElement, S : Group> : AlgebraElement + +/** + * The element of [Ring]. + * + * @param T the type of ring operation results. + * @param I self type of the element. Needed for static type checking. + * @param R the type of ring. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public interface RingElement, R : Ring> : GroupElement + +/** + * The element of [Field]. + * + * @param T the type of field operation results. + * @param I self type of the element. Needed for static type checking. + * @param F the type of field. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public interface FieldElement, F : Field> : RingElement diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt index 99268348b..2dd61270d 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt @@ -1,12 +1,13 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.operations import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.BufferedRingOpsND +import space.kscience.kmath.nd.AlgebraND +import space.kscience.kmath.nd.BufferedRingND import space.kscience.kmath.operations.BigInt.Companion.BASE import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE import space.kscience.kmath.structures.Buffer @@ -26,7 +27,7 @@ private typealias TBase = ULong * @author Peter Klimai */ @OptIn(UnstableKMathAPI::class) -public object BigIntField : Field, NumbersAddOps, ScaleOperations { +public object BigIntField : Field, NumbersAddOperations, ScaleOperations { override val zero: BigInt = BigInt.ZERO override val one: BigInt = BigInt.ONE @@ -34,10 +35,10 @@ public object BigIntField : Field, NumbersAddOps, ScaleOperation @Suppress("EXTENSION_SHADOWED_BY_MEMBER") override fun BigInt.unaryMinus(): BigInt = -this - override fun add(left: BigInt, right: BigInt): BigInt = left.plus(right) + override fun add(a: BigInt, b: BigInt): BigInt = a.plus(b) override fun scale(a: BigInt, value: Double): BigInt = a.times(number(value)) - override fun multiply(left: BigInt, right: BigInt): BigInt = left.times(right) - override fun divide(left: BigInt, right: BigInt): BigInt = left.div(right) + override fun multiply(a: BigInt, b: BigInt): BigInt = a.times(b) + override fun divide(a: BigInt, b: BigInt): BigInt = a.div(b) public operator fun String.unaryPlus(): BigInt = this.parseBigInteger() ?: error("Can't parse $this as big integer") public operator fun String.unaryMinus(): BigInt = @@ -526,21 +527,11 @@ public fun String.parseBigInteger(): BigInt? { } } -public val BigInt.algebra: BigIntField get() = BigIntField - -@Deprecated("Use BigInt::buffer") public inline fun Buffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): Buffer = boxing(size, initializer) -public inline fun BigInt.Companion.buffer(size: Int, initializer: (Int) -> BigInt): Buffer = - Buffer.boxing(size, initializer) - -@Deprecated("Use BigInt::mutableBuffer") public inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): MutableBuffer = boxing(size, initializer) -public inline fun BigInt.mutableBuffer(size: Int, initializer: (Int) -> BigInt): Buffer = - Buffer.boxing(size, initializer) - -public val BigIntField.nd: BufferedRingOpsND - get() = BufferedRingOpsND(BufferRingOps(BigIntField, BigInt::buffer)) +public fun AlgebraND.Companion.bigInt(vararg shape: Int): BufferedRingND = + BufferedRingND(shape, BigIntField, Buffer.Companion::bigInt) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt deleted file mode 100644 index 653552044..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BufferAlgebra.kt +++ /dev/null @@ -1,196 +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.operations - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferFactory -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.ShortBuffer - -public interface WithSize { - public val size: Int -} - -/** - * An algebra over [Buffer] - */ -public interface BufferAlgebra> : Algebra> { - public val elementAlgebra: A - public val bufferFactory: BufferFactory - - public fun buffer(size: Int, vararg elements: T): Buffer { - require(elements.size == size) { "Expected $size elements but found ${elements.size}" } - return bufferFactory(size) { elements[it] } - } - - //TODO move to multi-receiver inline extension - public fun Buffer.map(block: A.(T) -> T): Buffer = mapInline(this, block) - - public fun Buffer.mapIndexed(block: A.(index: Int, arg: T) -> T): Buffer = mapIndexedInline(this, block) - - public fun Buffer.zip(other: Buffer, block: A.(left: T, right: T) -> T): Buffer = - zipInline(this, other, block) - - override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer { - val operationFunction = elementAlgebra.unaryOperationFunction(operation) - return { arg -> bufferFactory(arg.size) { operationFunction(arg[it]) } } - } - - override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer { - val operationFunction = elementAlgebra.binaryOperationFunction(operation) - return { left, right -> - bufferFactory(left.size) { operationFunction(left[it], right[it]) } - } - } -} - -/** - * Inline map - */ -private inline fun > BufferAlgebra.mapInline( - buffer: Buffer, - crossinline block: A.(T) -> T -): Buffer = bufferFactory(buffer.size) { elementAlgebra.block(buffer[it]) } - -/** - * Inline map - */ -private inline fun > BufferAlgebra.mapIndexedInline( - buffer: Buffer, - crossinline block: A.(index: Int, arg: T) -> T -): Buffer = bufferFactory(buffer.size) { elementAlgebra.block(it, buffer[it]) } - -/** - * Inline zip - */ -private inline fun > BufferAlgebra.zipInline( - l: Buffer, - r: Buffer, - crossinline block: A.(l: T, r: T) -> T -): Buffer { - require(l.size == r.size) { "Incompatible buffer sizes. left: ${l.size}, right: ${r.size}" } - return bufferFactory(l.size) { elementAlgebra.block(l[it], r[it]) } -} - -public fun BufferAlgebra.buffer(size: Int, initializer: (Int) -> T): Buffer { - return bufferFactory(size, initializer) -} - -public fun A.buffer(initializer: (Int) -> T): Buffer where A : BufferAlgebra, A : WithSize { - return bufferFactory(size, initializer) -} - -public fun > BufferAlgebra.sin(arg: Buffer): Buffer = - mapInline(arg) { sin(it) } - -public fun > BufferAlgebra.cos(arg: Buffer): Buffer = - mapInline(arg) { cos(it) } - -public fun > BufferAlgebra.tan(arg: Buffer): Buffer = - mapInline(arg) { tan(it) } - -public fun > BufferAlgebra.asin(arg: Buffer): Buffer = - mapInline(arg) { asin(it) } - -public fun > BufferAlgebra.acos(arg: Buffer): Buffer = - mapInline(arg) { acos(it) } - -public fun > BufferAlgebra.atan(arg: Buffer): Buffer = - mapInline(arg) { atan(it) } - -public fun > BufferAlgebra.exp(arg: Buffer): Buffer = - mapInline(arg) { exp(it) } - -public fun > BufferAlgebra.ln(arg: Buffer): Buffer = - mapInline(arg) { ln(it) } - -public fun > BufferAlgebra.sinh(arg: Buffer): Buffer = - mapInline(arg) { sinh(it) } - -public fun > BufferAlgebra.cosh(arg: Buffer): Buffer = - mapInline(arg) { cosh(it) } - -public fun > BufferAlgebra.tanh(arg: Buffer): Buffer = - mapInline(arg) { tanh(it) } - -public fun > BufferAlgebra.asinh(arg: Buffer): Buffer = - mapInline(arg) { asinh(it) } - -public fun > BufferAlgebra.acosh(arg: Buffer): Buffer = - mapInline(arg) { acosh(it) } - -public fun > BufferAlgebra.atanh(arg: Buffer): Buffer = - mapInline(arg) { atanh(it) } - -public fun > BufferAlgebra.pow(arg: Buffer, pow: Number): Buffer = - mapInline(arg) {it.pow(pow) } - - -public open class BufferRingOps>( - override val elementAlgebra: A, - override val bufferFactory: BufferFactory, -) : BufferAlgebra, RingOps>{ - - override fun add(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l + r } - override fun multiply(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l * r } - override fun Buffer.unaryMinus(): Buffer = map { -it } - - override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = - super.unaryOperationFunction(operation) - - override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = - super.binaryOperationFunction(operation) -} - -public val ShortRing.bufferAlgebra: BufferRingOps - get() = BufferRingOps(ShortRing, ::ShortBuffer) - -public open class BufferFieldOps>( - elementAlgebra: A, - bufferFactory: BufferFactory, -) : BufferRingOps(elementAlgebra, bufferFactory), BufferAlgebra, FieldOps>, ScaleOperations> { - - override fun add(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l + r } - override fun multiply(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l * r } - override fun divide(left: Buffer, right: Buffer): Buffer = zipInline(left, right) { l, r -> l / r } - - override fun scale(a: Buffer, value: Double): Buffer = a.map { scale(it, value) } - override fun Buffer.unaryMinus(): Buffer = map { -it } - - override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = - super.binaryOperationFunction(operation) -} - -public class BufferField>( - elementAlgebra: A, - bufferFactory: BufferFactory, - override val size: Int -) : BufferFieldOps(elementAlgebra, bufferFactory), Field>, WithSize { - - override val zero: Buffer = bufferFactory(size) { elementAlgebra.zero } - override val one: Buffer = bufferFactory(size) { elementAlgebra.one } -} - -/** - * Generate full buffer field from given buffer operations - */ -public fun > BufferFieldOps.withSize(size: Int): BufferField = - BufferField(elementAlgebra, bufferFactory, size) - -//Double buffer specialization - -public fun BufferField.buffer(vararg elements: Number): Buffer { - require(elements.size == size) { "Expected $size elements but found ${elements.size}" } - return bufferFactory(size) { elements[it].toDouble() } -} - -public fun > A.bufferAlgebra(bufferFactory: BufferFactory): BufferFieldOps = - BufferFieldOps(this, bufferFactory) - -public val DoubleField.bufferAlgebra: BufferFieldOps - get() = BufferFieldOps(DoubleField, ::DoubleBuffer) - diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt deleted file mode 100644 index f2f7326aa..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferField.kt +++ /dev/null @@ -1,144 +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.operations - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField.pow -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer - -/** - * [ExtendedField] over [DoubleBuffer]. - * - * @property size the size of buffers to operate on. - */ -public class DoubleBufferField(public val size: Int) : ExtendedField>, DoubleBufferOps() { - override val zero: Buffer by lazy { DoubleBuffer(size) { 0.0 } } - override val one: Buffer by lazy { DoubleBuffer(size) { 1.0 } } - - override fun sinh(arg: Buffer): DoubleBuffer = super.sinh(arg) - - override fun cosh(arg: Buffer): DoubleBuffer = super.cosh(arg) - - override fun tanh(arg: Buffer): DoubleBuffer = super.tanh(arg) - - override fun asinh(arg: Buffer): DoubleBuffer = super.asinh(arg) - - override fun acosh(arg: Buffer): DoubleBuffer = super.acosh(arg) - - override fun atanh(arg: Buffer): DoubleBuffer = super.atanh(arg) - - override fun power(arg: Buffer, pow: Number): DoubleBuffer = if (pow.isInteger()) { - arg.mapInline { it.pow(pow.toInt()) } - } else { - arg.mapInline { - if(it<0) throw IllegalArgumentException("Negative argument $it could not be raised to the fractional power") - it.pow(pow.toDouble()) - } - } - - override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = - super.unaryOperationFunction(operation) - - // override fun number(value: Number): Buffer = DoubleBuffer(size) { value.toDouble() } -// -// override fun Buffer.unaryMinus(): Buffer = DoubleBufferOperations.run { -// -this@unaryMinus -// } -// -// override fun add(a: Buffer, b: Buffer): DoubleBuffer { -// require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } -// return DoubleBufferOperations.add(a, b) -// } -// - -// -// override fun multiply(a: Buffer, b: Buffer): DoubleBuffer { -// require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } -// return DoubleBufferOperations.multiply(a, b) -// } -// -// override fun divide(a: Buffer, b: Buffer): DoubleBuffer { -// require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } -// return DoubleBufferOperations.divide(a, b) -// } -// -// override fun sin(arg: Buffer): DoubleBuffer { -// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } -// return DoubleBufferOperations.sin(arg) -// } -// -// override fun cos(arg: Buffer): DoubleBuffer { -// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } -// return DoubleBufferOperations.cos(arg) -// } -// -// override fun tan(arg: Buffer): DoubleBuffer { -// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } -// return DoubleBufferOperations.tan(arg) -// } -// -// override fun asin(arg: Buffer): DoubleBuffer { -// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } -// return DoubleBufferOperations.asin(arg) -// } -// -// override fun acos(arg: Buffer): DoubleBuffer { -// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } -// return DoubleBufferOperations.acos(arg) -// } -// -// override fun atan(arg: Buffer): DoubleBuffer { -// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } -// return DoubleBufferOperations.atan(arg) -// } -// -// override fun sinh(arg: Buffer): DoubleBuffer { -// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } -// return DoubleBufferOperations.sinh(arg) -// } -// -// override fun cosh(arg: Buffer): DoubleBuffer { -// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } -// return DoubleBufferOperations.cosh(arg) -// } -// -// override fun tanh(arg: Buffer): DoubleBuffer { -// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } -// return DoubleBufferOperations.tanh(arg) -// } -// -// override fun asinh(arg: Buffer): DoubleBuffer { -// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } -// return DoubleBufferOperations.asinh(arg) -// } -// -// override fun acosh(arg: Buffer): DoubleBuffer { -// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } -// return DoubleBufferOperations.acosh(arg) -// } -// -// override fun atanh(arg: Buffer): DoubleBuffer { -// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } -// return DoubleBufferOperations.atanh(arg) -// } -// -// override fun power(arg: Buffer, pow: Number): DoubleBuffer { -// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } -// return DoubleBufferOperations.power(arg, pow) -// } -// -// override fun exp(arg: Buffer): DoubleBuffer { -// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } -// return DoubleBufferOperations.exp(arg) -// } -// -// override fun ln(arg: Buffer): DoubleBuffer { -// require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } -// return DoubleBufferOperations.ln(arg) -// } - -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt deleted file mode 100644 index 0ee591acc..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/DoubleBufferOps.kt +++ /dev/null @@ -1,151 +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.operations - -import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferFactory -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.asBuffer - -import kotlin.math.* - -/** - * [ExtendedFieldOps] over [DoubleBuffer]. - */ -public abstract class DoubleBufferOps : BufferAlgebra, ExtendedFieldOps>, - Norm, Double> { - - override val elementAlgebra: DoubleField get() = DoubleField - override val bufferFactory: BufferFactory get() = ::DoubleBuffer - - override fun Buffer.map(block: DoubleField.(Double) -> Double): DoubleBuffer = - mapInline { DoubleField.block(it) } - - override fun unaryOperationFunction(operation: String): (arg: Buffer) -> Buffer = - super.unaryOperationFunction(operation) - - override fun binaryOperationFunction(operation: String): (left: Buffer, right: Buffer) -> Buffer = - super.binaryOperationFunction(operation) - - override fun Buffer.unaryMinus(): DoubleBuffer = mapInline { -it } - - override fun add(left: Buffer, right: Buffer): DoubleBuffer { - require(right.size == left.size) { - "The size of the first buffer ${left.size} should be the same as for second one: ${right.size} " - } - - return if (left is DoubleBuffer && right is DoubleBuffer) { - val aArray = left.array - val bArray = right.array - DoubleBuffer(DoubleArray(left.size) { aArray[it] + bArray[it] }) - } else DoubleBuffer(DoubleArray(left.size) { left[it] + right[it] }) - } - - override fun Buffer.plus(arg: Buffer): DoubleBuffer = add(this, arg) - - override fun Buffer.minus(arg: Buffer): DoubleBuffer { - require(arg.size == this.size) { - "The size of the first buffer ${this.size} should be the same as for second one: ${arg.size} " - } - - return if (this is DoubleBuffer && arg is DoubleBuffer) { - val aArray = this.array - val bArray = arg.array - DoubleBuffer(DoubleArray(this.size) { aArray[it] - bArray[it] }) - } else DoubleBuffer(DoubleArray(this.size) { this[it] - arg[it] }) - } - - // -// override fun multiply(a: Buffer, k: Number): RealBuffer { -// val kValue = k.toDouble() -// -// return if (a is RealBuffer) { -// val aArray = a.array -// RealBuffer(DoubleArray(a.size) { aArray[it] * kValue }) -// } else RealBuffer(DoubleArray(a.size) { a[it] * kValue }) -// } -// -// override fun divide(a: Buffer, k: Number): RealBuffer { -// val kValue = k.toDouble() -// -// return if (a is RealBuffer) { -// val aArray = a.array -// RealBuffer(DoubleArray(a.size) { aArray[it] / kValue }) -// } else RealBuffer(DoubleArray(a.size) { a[it] / kValue }) -// } - - override fun multiply(left: Buffer, right: Buffer): DoubleBuffer { - require(right.size == left.size) { - "The size of the first buffer ${left.size} should be the same as for second one: ${right.size} " - } - - return if (left is DoubleBuffer && right is DoubleBuffer) { - val aArray = left.array - val bArray = right.array - DoubleBuffer(DoubleArray(left.size) { aArray[it] * bArray[it] }) - } else DoubleBuffer(DoubleArray(left.size) { left[it] * right[it] }) - } - - override fun divide(left: Buffer, right: Buffer): DoubleBuffer { - require(right.size == left.size) { - "The size of the first buffer ${left.size} should be the same as for second one: ${right.size} " - } - - return if (left is DoubleBuffer && right is DoubleBuffer) { - val aArray = left.array - val bArray = right.array - DoubleBuffer(DoubleArray(left.size) { aArray[it] / bArray[it] }) - } else DoubleBuffer(DoubleArray(left.size) { left[it] / right[it] }) - } - - override fun sin(arg: Buffer): DoubleBuffer = arg.mapInline(::sin) - - override fun cos(arg: Buffer): DoubleBuffer = arg.mapInline(::cos) - - override fun tan(arg: Buffer): DoubleBuffer = arg.mapInline(::tan) - - override fun asin(arg: Buffer): DoubleBuffer = arg.mapInline(::asin) - - override fun acos(arg: Buffer): DoubleBuffer = arg.mapInline(::acos) - - override fun atan(arg: Buffer): DoubleBuffer = arg.mapInline(::atan) - - override fun sinh(arg: Buffer): DoubleBuffer = arg.mapInline(::sinh) - - override fun cosh(arg: Buffer): DoubleBuffer = arg.mapInline(::cosh) - - override fun tanh(arg: Buffer): DoubleBuffer = arg.mapInline(::tanh) - - override fun asinh(arg: Buffer): DoubleBuffer = arg.mapInline(::asinh) - - override fun acosh(arg: Buffer): DoubleBuffer = arg.mapInline(::acosh) - - override fun atanh(arg: Buffer): DoubleBuffer = arg.mapInline(::atanh) - - override fun exp(arg: Buffer): DoubleBuffer = arg.mapInline(::exp) - - override fun ln(arg: Buffer): DoubleBuffer = arg.mapInline(::ln) - - override fun norm(arg: Buffer): Double = DoubleL2Norm.norm(arg) - - override fun scale(a: Buffer, value: Double): DoubleBuffer = a.mapInline { it * value } - - public companion object : DoubleBufferOps() { - public inline fun Buffer.mapInline(block: (Double) -> Double): DoubleBuffer = - if (this is DoubleBuffer) { - DoubleArray(size) { block(array[it]) }.asBuffer() - } else { - DoubleArray(size) { block(get(it)) }.asBuffer() - } - } -} - -public object DoubleL2Norm : Norm, Double> { - override fun norm(arg: Point): Double = sqrt(arg.fold(0.0) { acc: Double, d: Double -> acc + d.pow(2) }) -} - diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt index 9037525e1..d50f1e79e 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.operations diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt index d0405c705..a3d8f5ffe 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.operations @@ -139,10 +139,10 @@ public interface ScaleOperations : Algebra { * Multiplication of this number by element. * * @receiver the multiplier. - * @param arg the multiplicand. + * @param b the multiplicand. * @return the product. */ - public operator fun Number.times(arg: T): T = arg * this + public operator fun Number.times(b: T): T = b * this } /** @@ -150,38 +150,38 @@ public interface ScaleOperations : Algebra { * TODO to be removed and replaced by extensions after multiple receivers are there */ @UnstableKMathAPI -public interface NumbersAddOps : RingOps, NumericAlgebra { +public interface NumbersAddOperations : Ring, NumericAlgebra { /** * Addition of element and scalar. * * @receiver the augend. - * @param other the addend. + * @param b the addend. */ - public operator fun T.plus(other: Number): T = this + number(other) + public operator fun T.plus(b: Number): T = this + number(b) /** * Addition of scalar and element. * * @receiver the augend. - * @param other the addend. + * @param b the addend. */ - public operator fun Number.plus(other: T): T = other + this + public operator fun Number.plus(b: T): T = b + this /** * Subtraction of element from number. * * @receiver the minuend. - * @param other the subtrahend. + * @param b the subtrahend. * @receiver the difference. */ - public operator fun T.minus(other: Number): T = this - number(other) + public operator fun T.minus(b: Number): T = this - number(b) /** * Subtraction of number from element. * * @receiver the minuend. - * @param other the subtrahend. + * @param b the subtrahend. * @receiver the difference. */ - public operator fun Number.minus(other: T): T = -other + this + public operator fun Number.minus(b: T): T = -b + this } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt index 709506fc4..7f44eda49 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt @@ -1,10 +1,12 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.operations +import space.kscience.kmath.misc.UnstableKMathAPI + /** * A container for trigonometric operations for specific type. * @@ -75,20 +77,55 @@ public interface TrigonometricOperations : Algebra { } /** - * Check if number is an integer from platform point of view + * Computes the sine of [arg]. */ -public expect fun Number.isInteger(): Boolean +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public fun >> sin(arg: T): T = arg.context.sin(arg) + +/** + * Computes the cosine of [arg]. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public fun >> cos(arg: T): T = arg.context.cos(arg) + +/** + * Computes the tangent of [arg]. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public fun >> tan(arg: T): T = arg.context.tan(arg) + +/** + * Computes the inverse sine of [arg]. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public fun >> asin(arg: T): T = arg.context.asin(arg) + +/** + * Computes the inverse cosine of [arg]. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public fun >> acos(arg: T): T = arg.context.acos(arg) + +/** + * Computes the inverse tangent of [arg]. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public fun >> atan(arg: T): T = arg.context.atan(arg) /** * A context extension to include power operations based on exponentiation. * * @param T the type of element of this structure. */ -public interface PowerOperations : FieldOps { - +public interface PowerOperations : Algebra { /** - * Raises [arg] to a power if possible (negative number could not be raised to a fractional power). - * Throws [IllegalArgumentException] if not possible. + * Raises [arg] to the power [pow]. */ public fun power(arg: T, pow: Number): T @@ -115,6 +152,30 @@ public interface PowerOperations : FieldOps { } } +/** + * Raises this element to the power [power]. + * + * @receiver the base. + * @param power the exponent. + * @return the base raised to the power. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public infix fun >> T.pow(power: Double): T = context.power(this, power) + +/** + * Computes the square root of the value [arg]. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public fun >> sqrt(arg: T): T = arg pow 0.5 + +/** + * Computes the square of the value [arg]. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public fun >> sqr(arg: T): T = arg pow 2.0 /** * A container for operations related to `exp` and `ln` functions. @@ -205,6 +266,62 @@ public interface ExponentialOperations : Algebra { } } +/** + * The identifier of exponential function. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public fun >> exp(arg: T): T = arg.context.exp(arg) + +/** + * The identifier of natural logarithm. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public fun >> ln(arg: T): T = arg.context.ln(arg) + + +/** + * Computes the hyperbolic sine of [arg]. + */ +@UnstableKMathAPI +public fun >> sinh(arg: T): T = arg.context.sinh(arg) + +/** + * Computes the hyperbolic cosine of [arg]. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public fun >> cosh(arg: T): T = arg.context.cosh(arg) + +/** + * Computes the hyperbolic tangent of [arg]. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public fun >> tanh(arg: T): T = arg.context.tanh(arg) + +/** + * Computes the inverse hyperbolic sine of [arg]. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public fun >> asinh(arg: T): T = arg.context.asinh(arg) + +/** + * Computes the inverse hyperbolic cosine of [arg]. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public fun >> acosh(arg: T): T = arg.context.acosh(arg) + +/** + * Computes the inverse hyperbolic tangent of [arg]. + */ +@UnstableKMathAPI +@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") +public fun >> atanh(arg: T): T = arg.context.atanh(arg) + /** * A container for norm functional on element. * @@ -218,3 +335,8 @@ public interface Norm { public fun norm(arg: T): R } +/** + * Computes the norm of [arg] (i.e., absolute value or vector length). + */ +@UnstableKMathAPI +public fun >, R> norm(arg: T): R = arg.context.norm(arg) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt index 539440de9..b26ebb2ea 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt @@ -1,60 +1,60 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.operations /** - * Returns the sum of all elements in the iterable in this [Group]. + * Returns the sum of all elements in the iterable in this [Ring]. * * @receiver the algebra that provides addition. * @param data the iterable to sum up. * @return the sum. */ -public fun Group.sum(data: Iterable): T = data.fold(zero) { left, right -> +public fun Ring.sum(data: Iterable): T = data.fold(zero) { left, right -> add(left, right) } //TODO replace by sumOf with multi-receivers /** - * Returns the sum of all elements in the sequence in this [Group]. + * Returns the sum of all elements in the sequence in this [Ring]. * * @receiver the algebra that provides addition. * @param data the sequence to sum up. * @return the sum. */ -public fun Group.sum(data: Sequence): T = data.fold(zero) { left, right -> +public fun Ring.sum(data: Sequence): T = data.fold(zero) { left, right -> add(left, right) } /** - * Returns an average value of elements in the iterable in this [Group]. + * Returns an average value of elements in the iterable in this [Ring]. * * @receiver the algebra that provides addition and division. * @param data the iterable to find average. * @return the average value. * @author Iaroslav Postovalov */ -public fun S.average(data: Iterable): T where S : Group, S : ScaleOperations = +public fun S.average(data: Iterable): T where S : Ring, S : ScaleOperations = sum(data) / data.count() /** - * Returns an average value of elements in the sequence in this [Group]. + * Returns an average value of elements in the sequence in this [Ring]. * * @receiver the algebra that provides addition and division. * @param data the sequence to find average. * @return the average value. * @author Iaroslav Postovalov */ -public fun S.average(data: Sequence): T where S : Group, S : ScaleOperations = +public fun S.average(data: Sequence): T where S : Ring, S : ScaleOperations = sum(data) / data.count() /** * Absolute of the comparable [value] */ -public fun > Group.abs(value: T): T = if (value > zero) value else -value +public fun > Ring.abs(value: T): T = if (value > zero) value else -value /** * Returns the sum of all elements in the iterable in provided space. @@ -63,7 +63,7 @@ public fun > Group.abs(value: T): T = if (value > zero) val * @param group the algebra that provides addition. * @return the sum. */ -public fun Iterable.sumWith(group: Group): T = group.sum(this) +public fun Iterable.sumWith(group: Ring): T = group.sum(this) /** * Returns the sum of all elements in the sequence in provided space. @@ -72,27 +72,70 @@ public fun Iterable.sumWith(group: Group): T = group.sum(this) * @param group the algebra that provides addition. * @return the sum. */ -public fun Sequence.sumWith(group: Group): T = group.sum(this) +public fun Sequence.sumWith(group: Ring): T = group.sum(this) /** - * Returns an average value of elements in the iterable in this [Group]. + * Returns an average value of elements in the iterable in this [Ring]. * * @receiver the iterable to find average. * @param space the algebra that provides addition and division. * @return the average value. * @author Iaroslav Postovalov */ -public fun Iterable.averageWith(space: S): T where S : Group, S : ScaleOperations = +public fun Iterable.averageWith(space: S): T where S : Ring, S : ScaleOperations = space.average(this) /** - * Returns an average value of elements in the sequence in this [Group]. + * Returns an average value of elements in the sequence in this [Ring]. * * @receiver the sequence to find average. * @param space the algebra that provides addition and division. * @return the average value. * @author Iaroslav Postovalov */ -public fun Sequence.averageWith(space: S): T where S : Group, S : ScaleOperations = +public fun Sequence.averageWith(space: S): T where S : Ring, S : ScaleOperations = space.average(this) +/** + * Raises [arg] to the non-negative integer power [exponent]. + * + * Special case: 0 ^ 0 is 1. + * + * @receiver the algebra to provide multiplication. + * @param arg the base. + * @param exponent the exponent. + * @return the base raised to the power. + * @author Evgeniy Zhelenskiy + */ +public fun Ring.power(arg: T, exponent: UInt): T = when { + arg == zero && exponent > 0U -> zero + arg == one -> arg + arg == -one -> powWithoutOptimization(arg, exponent % 2U) + else -> powWithoutOptimization(arg, exponent) +} + +private fun Ring.powWithoutOptimization(base: T, exponent: UInt): T = when (exponent) { + 0U -> one + 1U -> base + else -> { + val pre = powWithoutOptimization(base, exponent shr 1).let { it * it } + if (exponent and 1U == 0U) pre else pre * base + } +} + + +/** + * Raises [arg] to the integer power [exponent]. + * + * Special case: 0 ^ 0 is 1. + * + * @receiver the algebra to provide multiplication and division. + * @param arg the base. + * @param exponent the exponent. + * @return the base raised to the power. + * @author Iaroslav Postovalov, Evgeniy Zhelenskiy + */ +public fun Field.power(arg: T, exponent: Int): T = when { + exponent < 0 -> one / (this as Ring).power(arg, if (exponent == Int.MIN_VALUE) Int.MAX_VALUE.toUInt().inc() else (-exponent).toUInt()) + else -> (this as Ring).power(arg, exponent.toUInt()) +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt index 07a137415..e75d815cf 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.operations @@ -10,11 +10,11 @@ import kotlin.math.pow as kpow /** * Advanced Number-like semifield that implements basic operations. */ -public interface ExtendedFieldOps : - FieldOps, +public interface ExtendedFieldOperations : + FieldOperations, TrigonometricOperations, - ExponentialOperations, - ScaleOperations { + PowerOperations, + ExponentialOperations { override fun tan(arg: T): T = sin(arg) / cos(arg) override fun tanh(arg: T): T = sinh(arg) / cosh(arg) @@ -25,6 +25,7 @@ public interface ExtendedFieldOps : TrigonometricOperations.ACOS_OPERATION -> ::acos TrigonometricOperations.ASIN_OPERATION -> ::asin TrigonometricOperations.ATAN_OPERATION -> ::atan + PowerOperations.SQRT_OPERATION -> ::sqrt ExponentialOperations.EXP_OPERATION -> ::exp ExponentialOperations.LN_OPERATION -> ::ln ExponentialOperations.COSH_OPERATION -> ::cosh @@ -33,14 +34,14 @@ public interface ExtendedFieldOps : ExponentialOperations.ACOSH_OPERATION -> ::acosh ExponentialOperations.ASINH_OPERATION -> ::asinh ExponentialOperations.ATANH_OPERATION -> ::atanh - else -> super.unaryOperationFunction(operation) + else -> super.unaryOperationFunction(operation) } } /** * Advanced Number-like field that implements basic operations. */ -public interface ExtendedField : ExtendedFieldOps, Field, PowerOperations, NumericAlgebra { +public interface ExtendedField : ExtendedFieldOperations, Field, NumericAlgebra, ScaleOperations { override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2.0 override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2.0 override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) @@ -48,11 +49,6 @@ public interface ExtendedField : ExtendedFieldOps, Field, PowerOperatio override fun acosh(arg: T): T = ln(arg + sqrt((arg - one) * (arg + one))) override fun atanh(arg: T): T = (ln(arg + one) - ln(one - arg)) / 2.0 - override fun unaryOperationFunction(operation: String): (arg: T) -> T { - return if (operation == PowerOperations.SQRT_OPERATION) ::sqrt - else super.unaryOperationFunction(operation) - } - override fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = when (operation) { PowerOperations.POW_OPERATION -> ::power @@ -72,14 +68,14 @@ public object DoubleField : ExtendedField, Norm, ScaleOp override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = when (operation) { - PowerOperations.POW_OPERATION -> { l, r -> l.kpow(r) } + PowerOperations.POW_OPERATION -> ::power else -> super.binaryOperationFunction(operation) } - override inline fun add(left: Double, right: Double): Double = left + right + override inline fun add(a: Double, b: Double): Double = a + b - override inline fun multiply(left: Double, right: Double): Double = left * right - override inline fun divide(left: Double, right: Double): Double = left / right + override inline fun multiply(a: Double, b: Double): Double = a * b + override inline fun divide(a: Double, b: Double): Double = a / b override inline fun scale(a: Double, value: Double): Double = a * value @@ -97,27 +93,20 @@ public object DoubleField : ExtendedField, Norm, ScaleOp override inline fun acosh(arg: Double): Double = kotlin.math.acosh(arg) override inline fun atanh(arg: Double): Double = kotlin.math.atanh(arg) - override fun sqrt(arg: Double): Double = kotlin.math.sqrt(arg) - override fun power(arg: Double, pow: Number): Double = when { - pow.isInteger() -> arg.kpow(pow.toInt()) - arg < 0 -> throw IllegalArgumentException("Can't raise negative $arg to a fractional power $pow") - else -> arg.kpow(pow.toDouble()) - } - + override inline fun sqrt(arg: Double): Double = kotlin.math.sqrt(arg) + override inline fun power(arg: Double, pow: Number): Double = arg.kpow(pow.toDouble()) override inline fun exp(arg: Double): Double = kotlin.math.exp(arg) override inline fun ln(arg: Double): Double = kotlin.math.ln(arg) override inline fun norm(arg: Double): Double = abs(arg) override inline fun Double.unaryMinus(): Double = -this - override inline fun Double.plus(arg: Double): Double = this + arg - override inline fun Double.minus(arg: Double): Double = this - arg - override inline fun Double.times(arg: Double): Double = this * arg - override inline fun Double.div(arg: Double): Double = this / arg + override inline fun Double.plus(b: Double): Double = this + b + override inline fun Double.minus(b: Double): Double = this - b + override inline fun Double.times(b: Double): Double = this * b + override inline fun Double.div(b: Double): Double = this / b } -public val Double.Companion.algebra: DoubleField get() = DoubleField - /** * A field for [Float] without boxing. Does not produce appropriate field element. */ @@ -130,16 +119,16 @@ public object FloatField : ExtendedField, Norm { override fun binaryOperationFunction(operation: String): (left: Float, right: Float) -> Float = when (operation) { - PowerOperations.POW_OPERATION -> { l, r -> l.kpow(r) } + PowerOperations.POW_OPERATION -> ::power else -> super.binaryOperationFunction(operation) } - override inline fun add(left: Float, right: Float): Float = left + right + override inline fun add(a: Float, b: Float): Float = a + b override fun scale(a: Float, value: Double): Float = a * value.toFloat() - override inline fun multiply(left: Float, right: Float): Float = left * right + override inline fun multiply(a: Float, b: Float): Float = a * b - override inline fun divide(left: Float, right: Float): Float = left / right + override inline fun divide(a: Float, b: Float): Float = a / b override inline fun sin(arg: Float): Float = kotlin.math.sin(arg) override inline fun cos(arg: Float): Float = kotlin.math.cos(arg) @@ -157,21 +146,18 @@ public object FloatField : ExtendedField, Norm { override inline fun sqrt(arg: Float): Float = kotlin.math.sqrt(arg) override inline fun power(arg: Float, pow: Number): Float = arg.kpow(pow.toFloat()) - override inline fun exp(arg: Float): Float = kotlin.math.exp(arg) override inline fun ln(arg: Float): Float = kotlin.math.ln(arg) override inline fun norm(arg: Float): Float = abs(arg) override inline fun Float.unaryMinus(): Float = -this - override inline fun Float.plus(arg: Float): Float = this + arg - override inline fun Float.minus(arg: Float): Float = this - arg - override inline fun Float.times(arg: Float): Float = this * arg - override inline fun Float.div(arg: Float): Float = this / arg + override inline fun Float.plus(b: Float): Float = this + b + override inline fun Float.minus(b: Float): Float = this - b + override inline fun Float.times(b: Float): Float = this * b + override inline fun Float.div(b: Float): Float = this / b } -public val Float.Companion.algebra: FloatField get() = FloatField - /** * A field for [Int] without boxing. Does not produce corresponding ring element. */ @@ -184,18 +170,16 @@ public object IntRing : Ring, Norm, NumericAlgebra { get() = 1 override fun number(value: Number): Int = value.toInt() - override inline fun add(left: Int, right: Int): Int = left + right - override inline fun multiply(left: Int, right: Int): Int = left * right + override inline fun add(a: Int, b: Int): Int = a + b + override inline fun multiply(a: Int, b: Int): Int = a * b override inline fun norm(arg: Int): Int = abs(arg) override inline fun Int.unaryMinus(): Int = -this - override inline fun Int.plus(arg: Int): Int = this + arg - override inline fun Int.minus(arg: Int): Int = this - arg - override inline fun Int.times(arg: Int): Int = this * arg + override inline fun Int.plus(b: Int): Int = this + b + override inline fun Int.minus(b: Int): Int = this - b + override inline fun Int.times(b: Int): Int = this * b } -public val Int.Companion.algebra: IntRing get() = IntRing - /** * A field for [Short] without boxing. Does not produce appropriate ring element. */ @@ -208,18 +192,16 @@ public object ShortRing : Ring, Norm, NumericAlgebra get() = 1 override fun number(value: Number): Short = value.toShort() - override inline fun add(left: Short, right: Short): Short = (left + right).toShort() - override inline fun multiply(left: Short, right: Short): Short = (left * right).toShort() + override inline fun add(a: Short, b: Short): Short = (a + b).toShort() + override inline fun multiply(a: Short, b: Short): Short = (a * b).toShort() override fun norm(arg: Short): Short = if (arg > 0) arg else (-arg).toShort() override inline fun Short.unaryMinus(): Short = (-this).toShort() - override inline fun Short.plus(arg: Short): Short = (this + arg).toShort() - override inline fun Short.minus(arg: Short): Short = (this - arg).toShort() - override inline fun Short.times(arg: Short): Short = (this * arg).toShort() + override inline fun Short.plus(b: Short): Short = (this + b).toShort() + override inline fun Short.minus(b: Short): Short = (this - b).toShort() + override inline fun Short.times(b: Short): Short = (this * b).toShort() } -public val Short.Companion.algebra: ShortRing get() = ShortRing - /** * A field for [Byte] without boxing. Does not produce appropriate ring element. */ @@ -232,18 +214,16 @@ public object ByteRing : Ring, Norm, NumericAlgebra { get() = 1 override fun number(value: Number): Byte = value.toByte() - override inline fun add(left: Byte, right: Byte): Byte = (left + right).toByte() - override inline fun multiply(left: Byte, right: Byte): Byte = (left * right).toByte() + override inline fun add(a: Byte, b: Byte): Byte = (a + b).toByte() + override inline fun multiply(a: Byte, b: Byte): Byte = (a * b).toByte() override fun norm(arg: Byte): Byte = if (arg > 0) arg else (-arg).toByte() override inline fun Byte.unaryMinus(): Byte = (-this).toByte() - override inline fun Byte.plus(arg: Byte): Byte = (this + arg).toByte() - override inline fun Byte.minus(arg: Byte): Byte = (this - arg).toByte() - override inline fun Byte.times(arg: Byte): Byte = (this * arg).toByte() + override inline fun Byte.plus(b: Byte): Byte = (this + b).toByte() + override inline fun Byte.minus(b: Byte): Byte = (this - b).toByte() + override inline fun Byte.times(b: Byte): Byte = (this * b).toByte() } -public val Byte.Companion.algebra: ByteRing get() = ByteRing - /** * A field for [Double] without boxing. Does not produce appropriate ring element. */ @@ -256,14 +236,12 @@ public object LongRing : Ring, Norm, NumericAlgebra { get() = 1L override fun number(value: Number): Long = value.toLong() - override inline fun add(left: Long, right: Long): Long = left + right - override inline fun multiply(left: Long, right: Long): Long = left * right + override inline fun add(a: Long, b: Long): Long = a + b + override inline fun multiply(a: Long, b: Long): Long = a * b override fun norm(arg: Long): Long = abs(arg) override inline fun Long.unaryMinus(): Long = (-this) - override inline fun Long.plus(arg: Long): Long = (this + arg) - override inline fun Long.minus(arg: Long): Long = (this - arg) - override inline fun Long.times(arg: Long): Long = (this * arg) + override inline fun Long.plus(b: Long): Long = (this + b) + override inline fun Long.minus(b: Long): Long = (this - b) + override inline fun Long.times(b: Long): Long = (this * b) } - -public val Long.Companion.algebra: LongRing get() = LongRing diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt deleted file mode 100644 index 3528b0460..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ArrayBuffer.kt +++ /dev/null @@ -1,34 +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.structures - -/** - * [MutableBuffer] implementation over [Array]. - * - * @param T the type of elements contained in the buffer. - * @property array The underlying array. - */ -public class ArrayBuffer(internal val array: Array) : MutableBuffer { - // Can't inline because array is invariant - override val size: Int get() = array.size - - override operator fun get(index: Int): T = array[index] - - override operator fun set(index: Int, value: T) { - array[index] = value - } - - override operator fun iterator(): Iterator = array.iterator() - override fun copy(): MutableBuffer = ArrayBuffer(array.copyOf()) - - override fun toString(): String = Buffer.toString(this) -} - - -/** - * Returns an [ArrayBuffer] that wraps the original array. - */ -public fun Array.asBuffer(): ArrayBuffer = ArrayBuffer(this) \ No newline at end of file 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 58c6d5ded..6a97d18c2 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 @@ -1,11 +1,10 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures -import space.kscience.kmath.operations.asSequence import kotlin.jvm.JvmInline import kotlin.reflect.KClass @@ -46,13 +45,7 @@ public interface Buffer { */ public operator fun iterator(): Iterator - override fun toString(): String - public companion object { - - public fun toString(buffer: Buffer<*>): String = - buffer.asSequence().joinToString(prefix = "[", separator = ", ", postfix = "]") - /** * Check the element-by-element match of content of two buffers. */ @@ -105,6 +98,170 @@ public interface Buffer { */ public val Buffer<*>.indices: IntRange get() = 0 until size +/** + * A generic mutable random-access structure for both primitives and objects. + * + * @param T the type of elements contained in the buffer. + */ +public interface MutableBuffer : Buffer { + /** + * Sets the array element at the specified [index] to the specified [value]. + */ + public operator fun set(index: Int, value: T) + + /** + * Returns a shallow copy of the buffer. + */ + public fun copy(): MutableBuffer + + public companion object { + /** + * Creates a [DoubleBuffer] with the specified [size], where each element is calculated by calling the specified + * [initializer] function. + */ + public inline fun double(size: Int, initializer: (Int) -> Double): DoubleBuffer = + DoubleBuffer(size, initializer) + + /** + * Creates a [ShortBuffer] with the specified [size], where each element is calculated by calling the specified + * [initializer] function. + */ + public inline fun short(size: Int, initializer: (Int) -> Short): ShortBuffer = + ShortBuffer(size, initializer) + + /** + * Creates a [IntBuffer] with the specified [size], where each element is calculated by calling the specified + * [initializer] function. + */ + public inline fun int(size: Int, initializer: (Int) -> Int): IntBuffer = + IntBuffer(size, initializer) + + /** + * Creates a [LongBuffer] with the specified [size], where each element is calculated by calling the specified + * [initializer] function. + */ + public inline fun long(size: Int, initializer: (Int) -> Long): LongBuffer = + LongBuffer(size, initializer) + + + /** + * Creates a [FloatBuffer] with the specified [size], where each element is calculated by calling the specified + * [initializer] function. + */ + public inline fun float(size: Int, initializer: (Int) -> Float): FloatBuffer = + FloatBuffer(size, initializer) + + + /** + * Create a boxing mutable buffer of given type + */ + public inline fun boxing(size: Int, initializer: (Int) -> T): MutableBuffer = + MutableListBuffer(MutableList(size, initializer)) + + /** + * Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used + * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. + * + * The [size] is specified, and each element is calculated by calling the specified [initializer] function. + */ + @Suppress("UNCHECKED_CAST") + public inline fun auto(type: KClass, size: Int, initializer: (Int) -> T): MutableBuffer = + when (type) { + Double::class -> double(size) { initializer(it) as Double } as MutableBuffer + Short::class -> short(size) { initializer(it) as Short } as MutableBuffer + Int::class -> int(size) { initializer(it) as Int } as MutableBuffer + Float::class -> float(size) { initializer(it) as Float } as MutableBuffer + Long::class -> long(size) { initializer(it) as Long } as MutableBuffer + else -> boxing(size, initializer) + } + + /** + * Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used + * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. + * + * The [size] is specified, and each element is calculated by calling the specified [initializer] function. + */ + @Suppress("UNCHECKED_CAST") + public inline fun auto(size: Int, initializer: (Int) -> T): MutableBuffer = + auto(T::class, size, initializer) + } +} + +/** + * [Buffer] implementation over [List]. + * + * @param T the type of elements contained in the buffer. + * @property list The underlying list. + */ +public class ListBuffer(public val list: List) : Buffer { + + public constructor(size: Int, initializer: (Int) -> T) : this(List(size, initializer)) + + override val size: Int get() = list.size + + override operator fun get(index: Int): T = list[index] + override operator fun iterator(): Iterator = list.iterator() +} + +/** + * Returns an [ListBuffer] that wraps the original list. + */ +public fun List.asBuffer(): ListBuffer = ListBuffer(this) + +/** + * [MutableBuffer] implementation over [MutableList]. + * + * @param T the type of elements contained in the buffer. + * @property list The underlying list. + */ +@JvmInline +public value class MutableListBuffer(public val list: MutableList) : MutableBuffer { + + public constructor(size: Int, initializer: (Int) -> T) : this(MutableList(size, initializer)) + + override val size: Int get() = list.size + + override operator fun get(index: Int): T = list[index] + + override operator fun set(index: Int, value: T) { + list[index] = value + } + + override operator fun iterator(): Iterator = list.iterator() + 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]. + * + * @param T the type of elements contained in the buffer. + * @property array The underlying array. + */ +public class ArrayBuffer(internal val array: Array) : MutableBuffer { + // Can't inline because array is invariant + override val size: Int get() = array.size + + override operator fun get(index: Int): T = array[index] + + override operator fun set(index: Int, value: T) { + array[index] = value + } + + override operator fun iterator(): Iterator = array.iterator() + override fun copy(): MutableBuffer = ArrayBuffer(array.copyOf()) +} + + +/** + * Returns an [ArrayBuffer] that wraps the original array. + */ +public fun Array.asBuffer(): ArrayBuffer = ArrayBuffer(this) + /** * Immutable wrapper for [MutableBuffer]. * @@ -133,8 +290,6 @@ public class VirtualBuffer(override val size: Int, private val generator: } override operator fun iterator(): Iterator = (0 until size).asSequence().map(generator).iterator() - - override fun toString(): String = Buffer.toString(this) } /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt index 4d04a5235..5f1f8a738 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures @@ -13,7 +13,7 @@ import space.kscience.kmath.nd.as2D /** * A context that allows to operate on a [MutableBuffer] as on 2d array */ -internal class BufferAccessor2D( +internal class BufferAccessor2D( val rowNum: Int, val colNum: Int, val factory: MutableBufferFactory, @@ -49,8 +49,6 @@ internal class BufferAccessor2D( override fun copy(): MutableBuffer = factory(colNum) { get(it) } override operator fun iterator(): Iterator = (0 until colNum).map(::get).iterator() - override fun toString(): String = Buffer.toString(this) - } /** diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt index f4388a477..b94a36bab 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures @@ -25,12 +25,6 @@ public value class DoubleBuffer(public val array: DoubleArray) : MutableBuffer> { + override fun Buffer.unaryMinus(): DoubleBuffer = if (this is DoubleBuffer) { + DoubleBuffer(size) { -array[it] } + } else { + DoubleBuffer(size) { -get(it) } + } + + override fun add(a: Buffer, b: Buffer): DoubleBuffer { + require(b.size == a.size) { + "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " + } + + return if (a is DoubleBuffer && b is DoubleBuffer) { + val aArray = a.array + val bArray = b.array + DoubleBuffer(DoubleArray(a.size) { aArray[it] + bArray[it] }) + } else DoubleBuffer(DoubleArray(a.size) { a[it] + b[it] }) + } +// +// override fun multiply(a: Buffer, k: Number): RealBuffer { +// val kValue = k.toDouble() +// +// return if (a is RealBuffer) { +// val aArray = a.array +// RealBuffer(DoubleArray(a.size) { aArray[it] * kValue }) +// } else RealBuffer(DoubleArray(a.size) { a[it] * kValue }) +// } +// +// override fun divide(a: Buffer, k: Number): RealBuffer { +// val kValue = k.toDouble() +// +// return if (a is RealBuffer) { +// val aArray = a.array +// RealBuffer(DoubleArray(a.size) { aArray[it] / kValue }) +// } else RealBuffer(DoubleArray(a.size) { a[it] / kValue }) +// } + + override fun multiply(a: Buffer, b: Buffer): DoubleBuffer { + require(b.size == a.size) { + "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " + } + + return if (a is DoubleBuffer && b is DoubleBuffer) { + val aArray = a.array + val bArray = b.array + DoubleBuffer(DoubleArray(a.size) { aArray[it] * bArray[it] }) + } else + DoubleBuffer(DoubleArray(a.size) { a[it] * b[it] }) + } + + override fun divide(a: Buffer, b: Buffer): DoubleBuffer { + require(b.size == a.size) { + "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " + } + + return if (a is DoubleBuffer && b is DoubleBuffer) { + val aArray = a.array + val bArray = b.array + DoubleBuffer(DoubleArray(a.size) { aArray[it] / bArray[it] }) + } else DoubleBuffer(DoubleArray(a.size) { a[it] / b[it] }) + } + + override fun sin(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { sin(array[it]) }) + } else DoubleBuffer(DoubleArray(arg.size) { sin(arg[it]) }) + + override fun cos(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { cos(array[it]) }) + } else DoubleBuffer(DoubleArray(arg.size) { cos(arg[it]) }) + + override fun tan(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { tan(array[it]) }) + } else DoubleBuffer(DoubleArray(arg.size) { tan(arg[it]) }) + + override fun asin(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { asin(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { asin(arg[it]) }) + + override fun acos(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { acos(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { acos(arg[it]) }) + + override fun atan(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { atan(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { atan(arg[it]) }) + + override fun sinh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { sinh(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { sinh(arg[it]) }) + + override fun cosh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { cosh(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { cosh(arg[it]) }) + + override fun tanh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { tanh(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { tanh(arg[it]) }) + + override fun asinh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { asinh(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { asinh(arg[it]) }) + + override fun acosh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { acosh(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { acosh(arg[it]) }) + + override fun atanh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { atanh(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { atanh(arg[it]) }) + + override fun power(arg: Buffer, pow: Number): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) }) + } else + DoubleBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) }) + + override fun exp(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { exp(array[it]) }) + } else DoubleBuffer(DoubleArray(arg.size) { exp(arg[it]) }) + + override fun ln(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { ln(array[it]) }) + } else + DoubleBuffer(DoubleArray(arg.size) { ln(arg[it]) }) +} + +/** + * [ExtendedField] over [DoubleBuffer]. + * + * @property size the size of buffers to operate on. + */ +public class DoubleBufferField(public val size: Int) : ExtendedField> { + override val zero: Buffer by lazy { DoubleBuffer(size) { 0.0 } } + override val one: Buffer by lazy { DoubleBuffer(size) { 1.0 } } + + override fun number(value: Number): Buffer = DoubleBuffer(size) { value.toDouble() } + + override fun Buffer.unaryMinus(): Buffer = DoubleBufferFieldOperations.run { + -this@unaryMinus + } + + override fun add(a: Buffer, b: Buffer): DoubleBuffer { + require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } + return DoubleBufferFieldOperations.add(a, b) + } + + override fun scale(a: Buffer, value: Double): DoubleBuffer { + require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } + + return if (a is DoubleBuffer) { + val aArray = a.array + DoubleBuffer(DoubleArray(a.size) { aArray[it] * value }) + } else DoubleBuffer(DoubleArray(a.size) { a[it] * value }) + } + + override fun multiply(a: Buffer, b: Buffer): DoubleBuffer { + require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } + return DoubleBufferFieldOperations.multiply(a, b) + } + + override fun divide(a: Buffer, b: Buffer): DoubleBuffer { + require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } + return DoubleBufferFieldOperations.divide(a, b) + } + + override fun sin(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.sin(arg) + } + + override fun cos(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.cos(arg) + } + + override fun tan(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.tan(arg) + } + + override fun asin(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.asin(arg) + } + + override fun acos(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.acos(arg) + } + + override fun atan(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.atan(arg) + } + + override fun sinh(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.sinh(arg) + } + + override fun cosh(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.cosh(arg) + } + + override fun tanh(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.tanh(arg) + } + + override fun asinh(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.asinh(arg) + } + + override fun acosh(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.acosh(arg) + } + + override fun atanh(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.atanh(arg) + } + + override fun power(arg: Buffer, pow: Number): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.power(arg, pow) + } + + override fun exp(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.exp(arg) + } + + override fun ln(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return DoubleBufferFieldOperations.ln(arg) + } +} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt index b3c537280..665558829 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures @@ -53,10 +53,8 @@ public fun FlaggedBuffer<*>.isMissing(index: Int): Boolean = hasFlag(index, Valu /** * A [Double] buffer that supports flags for each value like `NaN` or Missing. */ -public class FlaggedDoubleBuffer( - public val values: DoubleArray, - public val flags: ByteArray -) : FlaggedBuffer, Buffer { +public class FlaggedDoubleBuffer(public val values: DoubleArray, public val flags: ByteArray) : FlaggedBuffer, + Buffer { init { require(values.size == flags.size) { "Values and flags must have the same dimensions" } } @@ -70,8 +68,6 @@ public class FlaggedDoubleBuffer( override operator fun iterator(): Iterator = values.indices.asSequence().map { if (isValid(it)) values[it] else null }.iterator() - - override fun toString(): String = Buffer.toString(this) } public inline fun FlaggedDoubleBuffer.forEachValid(block: (Double) -> Unit) { 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 e7e98fc71..dc7903cbf 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 @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures 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 35b722e2b..ca078746c 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 @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt deleted file mode 100644 index 65d9dc77d..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ListBuffer.kt +++ /dev/null @@ -1,60 +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.structures - -import kotlin.jvm.JvmInline - -/** - * [Buffer] implementation over [List]. - * - * @param T the type of elements contained in the buffer. - * @property list The underlying list. - */ -public class ListBuffer(public val list: List) : Buffer { - - public constructor(size: Int, initializer: (Int) -> T) : this(List(size, initializer)) - - override val size: Int get() = list.size - - override operator fun get(index: Int): T = list[index] - override operator fun iterator(): Iterator = list.iterator() - - override fun toString(): String = Buffer.toString(this) -} - - -/** - * Returns an [ListBuffer] that wraps the original list. - */ -public fun List.asBuffer(): ListBuffer = ListBuffer(this) - -/** - * [MutableBuffer] implementation over [MutableList]. - * - * @param T the type of elements contained in the buffer. - * @property list The underlying list. - */ -@JvmInline -public value class MutableListBuffer(public val list: MutableList) : MutableBuffer { - - public constructor(size: Int, initializer: (Int) -> T) : this(MutableList(size, initializer)) - - override val size: Int get() = list.size - - override operator fun get(index: Int): T = list[index] - - override operator fun set(index: Int, value: T) { - list[index] = value - } - - override operator fun iterator(): Iterator = list.iterator() - override fun copy(): MutableBuffer = MutableListBuffer(ArrayList(list)) -} - -/** - * Returns an [MutableListBuffer] that wraps the original list. - */ -public fun MutableList.asMutableBuffer(): MutableListBuffer = MutableListBuffer(this) 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 c69f4646d..a0b5c78fa 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 @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt index 1dadaf7d4..996785570 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures @@ -22,8 +22,6 @@ public open class MemoryBuffer(protected val memory: Memory, protected override operator fun get(index: Int): T = reader.read(spec, spec.objectSize * index) override operator fun iterator(): Iterator = (0 until size).asSequence().map { get(it) }.iterator() - override fun toString(): String = Buffer.toString(this) - public companion object { public fun create(spec: MemorySpec, size: Int): MemoryBuffer = MemoryBuffer(Memory.allocate(size * spec.objectSize), spec) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt deleted file mode 100644 index 429c1a64b..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MutableBuffer.kt +++ /dev/null @@ -1,97 +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.structures - -import kotlin.reflect.KClass - -/** - * A generic mutable random-access structure for both primitives and objects. - * - * @param T the type of elements contained in the buffer. - */ -public interface MutableBuffer : Buffer { - /** - * Sets the array element at the specified [index] to the specified [value]. - */ - public operator fun set(index: Int, value: T) - - /** - * Returns a shallow copy of the buffer. - */ - public fun copy(): MutableBuffer - - public companion object { - /** - * Creates a [DoubleBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun double(size: Int, initializer: (Int) -> Double): DoubleBuffer = - DoubleBuffer(size, initializer) - - /** - * Creates a [ShortBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun short(size: Int, initializer: (Int) -> Short): ShortBuffer = - ShortBuffer(size, initializer) - - /** - * Creates a [IntBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun int(size: Int, initializer: (Int) -> Int): IntBuffer = - IntBuffer(size, initializer) - - /** - * Creates a [LongBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun long(size: Int, initializer: (Int) -> Long): LongBuffer = - LongBuffer(size, initializer) - - - /** - * Creates a [FloatBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun float(size: Int, initializer: (Int) -> Float): FloatBuffer = - FloatBuffer(size, initializer) - - - /** - * Create a boxing mutable buffer of given type - */ - public inline fun boxing(size: Int, initializer: (Int) -> T): MutableBuffer = - MutableListBuffer(MutableList(size, initializer)) - - /** - * Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used - * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. - * - * The [size] is specified, and each element is calculated by calling the specified [initializer] function. - */ - @Suppress("UNCHECKED_CAST") - public inline fun auto(type: KClass, size: Int, initializer: (Int) -> T): MutableBuffer = - when (type) { - Double::class -> double(size) { initializer(it) as Double } as MutableBuffer - Short::class -> short(size) { initializer(it) as Short } as MutableBuffer - Int::class -> int(size) { initializer(it) as Int } as MutableBuffer - Float::class -> float(size) { initializer(it) as Float } as MutableBuffer - Long::class -> long(size) { initializer(it) as Long } as MutableBuffer - else -> boxing(size, initializer) - } - - /** - * Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used - * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. - * - * The [size] is specified, and each element is calculated by calling the specified [initializer] function. - */ - @Suppress("UNCHECKED_CAST") - public inline fun auto(size: Int, initializer: (Int) -> T): MutableBuffer = - auto(T::class, size, initializer) - } -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt index 20691511b..1d2b0188a 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt similarity index 96% rename from kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt index 31b0c2841..bc3f5b64b 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/bufferOperation.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt @@ -1,12 +1,11 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ -package space.kscience.kmath.operations +package space.kscience.kmath.structures import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.structures.* /** * Typealias for buffer transformations. diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt index 80c5943cf..034839041 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.expressions @@ -16,7 +16,7 @@ class ExpressionFieldTest { @Test fun testExpression() { val expression = with(FunctionalExpressionField(DoubleField)) { - val x by binding + val x by binding() x * x + 2 * x + one } @@ -27,7 +27,7 @@ class ExpressionFieldTest { @Test fun separateContext() { fun FunctionalExpressionField.expression(): Expression { - val x by binding + val x by binding() return x * x + 2 * x + one } @@ -38,7 +38,7 @@ class ExpressionFieldTest { @Test fun valueExpression() { val expressionBuilder: FunctionalExpressionField.() -> Expression = { - val x by binding + val x by binding() x * x + 2 * x + one } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt index 156334b2e..8bf852653 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.expressions diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt index 201890933..7d8ff6202 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.expressions diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt index 70e010f2e..98b0bf02a 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.linear @@ -8,7 +8,6 @@ package space.kscience.kmath.linear import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.algebra import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -22,37 +21,39 @@ fun assertMatrixEquals(expected: StructureND, actual: StructureND = VirtualMatrix(6, 6) { row, col -> when { col == 0 -> .50 @@ -50,7 +48,7 @@ class MatrixTest { infix fun Matrix.pow(power: Int): Matrix { var res = this repeat(power - 1) { - res = res dot this@pow + res = LinearSpace.real.run { res dot this@pow } } return res } @@ -59,18 +57,19 @@ class MatrixTest { } @Test - fun test2DDot() = Double.algebra.linearSpace.run { + fun test2DDot() { val firstMatrix = StructureND.auto(2, 3) { (i, j) -> (i + j).toDouble() }.as2D() val secondMatrix = StructureND.auto(3, 2) { (i, j) -> (i + j).toDouble() }.as2D() + LinearSpace.real.run { // val firstMatrix = produce(2, 3) { i, j -> (i + j).toDouble() } // val secondMatrix = produce(3, 2) { i, j -> (i + j).toDouble() } - val result = firstMatrix dot secondMatrix - assertEquals(2, result.rowNum) - assertEquals(2, result.colNum) - assertEquals(8.0, result[0, 1]) - assertEquals(8.0, result[1, 0]) - assertEquals(14.0, result[1, 1]) - + val result = firstMatrix dot secondMatrix + assertEquals(2, result.rowNum) + assertEquals(2, result.colNum) + assertEquals(8.0, result[0, 1]) + assertEquals(8.0, result[1, 0]) + assertEquals(14.0, result[1, 1]) + } } } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt index e5f3f337f..aa7abd8ff 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.misc diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt deleted file mode 100644 index 0a2bb9138..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/PermSortTest.kt +++ /dev/null @@ -1,103 +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 file. - */ - -package space.kscience.kmath.misc - -import space.kscience.kmath.misc.PermSortTest.Platform.* -import kotlin.random.Random -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -import space.kscience.kmath.structures.IntBuffer -import space.kscience.kmath.structures.asBuffer -import kotlin.test.assertContentEquals - -class PermSortTest { - - private enum class Platform { - ANDROID, JVM, JS, NATIVE, WASM - } - - private val platforms = Platform.values().asBuffer() - - /** - * Permutation on empty buffer should immediately return an empty array. - */ - @Test - fun testOnEmptyBuffer() { - val emptyBuffer = IntBuffer(0) {it} - var permutations = emptyBuffer.permSort() - assertTrue(permutations.isEmpty(), "permutation on an empty buffer should return an empty result") - permutations = emptyBuffer.permSortDescending() - assertTrue(permutations.isEmpty(), "permutation on an empty buffer should return an empty result") - } - - @Test - fun testOnSingleValueBuffer() { - testPermutation(1) - } - - @Test - fun testOnSomeValues() { - testPermutation(10) - } - - @Test - fun testPermSortBy() { - val permutations = platforms.permSortBy { it.name } - val expected = listOf(ANDROID, JS, JVM, NATIVE, WASM) - assertContentEquals(expected, permutations.map { platforms[it] }, "Ascending PermSort by name") - } - - @Test - fun testPermSortByDescending() { - val permutations = platforms.permSortByDescending { it.name } - val expected = listOf(WASM, NATIVE, JVM, JS, ANDROID) - assertContentEquals(expected, permutations.map { platforms[it] }, "Descending PermSort by name") - } - - @Test - fun testPermSortWith() { - var permutations = platforms.permSortWith { p1, p2 -> p1.name.length.compareTo(p2.name.length) } - val expected = listOf(JS, JVM, WASM, NATIVE, ANDROID) - assertContentEquals(expected, permutations.map { platforms[it] }, "PermSort using custom ascending comparator") - - permutations = platforms.permSortWith(compareByDescending { it.name.length }) - assertContentEquals(expected.reversed(), permutations.map { platforms[it] }, "PermSort using custom descending comparator") - } - - private fun testPermutation(bufferSize: Int) { - - val seed = Random.nextLong() - println("Test randomization seed: $seed") - - val buffer = Random(seed).buffer(bufferSize) - val indices = buffer.permSort() - - assertEquals(bufferSize, indices.size) - // Ensure no doublon is present in indices - assertEquals(indices.toSet().size, indices.size) - - for (i in 0 until (bufferSize-1)) { - val current = buffer[indices[i]] - val next = buffer[indices[i+1]] - assertTrue(current <= next, "Permutation indices not properly sorted") - } - - val descIndices = buffer.permSortDescending() - assertEquals(bufferSize, descIndices.size) - // Ensure no doublon is present in indices - assertEquals(descIndices.toSet().size, descIndices.size) - - for (i in 0 until (bufferSize-1)) { - val current = buffer[descIndices[i]] - val next = buffer[descIndices[i+1]] - assertTrue(current >= next, "Permutation indices not properly sorted in descending order") - } - } - - private fun Random.buffer(size : Int) = IntBuffer(size) { nextInt() } -} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt index 0527f5252..75100b116 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.operations diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt index eec3dc3bf..c121c86ae 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.operations diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt index 85f368f3e..78dcdfe19 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.operations diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt index 26d6af224..11b8b161c 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.operations diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt index 76171fedd..9be75d68e 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.operations diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt index b7b89d107..f623b00e8 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt @@ -1,14 +1,13 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures +import space.kscience.kmath.nd.AlgebraND import space.kscience.kmath.nd.get -import space.kscience.kmath.nd.ndAlgebra -import space.kscience.kmath.nd.structureND -import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.nd.real import space.kscience.kmath.operations.invoke import space.kscience.kmath.testutils.FieldVerifier import kotlin.test.Test @@ -17,12 +16,12 @@ import kotlin.test.assertEquals internal class NDFieldTest { @Test fun verify() { - (DoubleField.ndAlgebra(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) } + (AlgebraND.real(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) } } @Test fun testStrides() { - val ndArray = DoubleField.ndAlgebra.structureND(10, 10) { (it[0] + it[1]).toDouble() } + val ndArray = AlgebraND.real(10, 10).produce { (it[0] + it[1]).toDouble() } assertEquals(ndArray[5, 5], 10.0) } } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt index d33eb5112..86e9bb083 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt @@ -1,16 +1,14 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures -import space.kscience.kmath.linear.linearSpace +import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Norm -import space.kscience.kmath.operations.algebra import space.kscience.kmath.operations.invoke import kotlin.math.abs import kotlin.math.pow @@ -19,9 +17,9 @@ import kotlin.test.assertEquals @Suppress("UNUSED_VARIABLE") class NumberNDFieldTest { - val algebra = DoubleField.ndAlgebra - val array1 = algebra.structureND(3, 3) { (i, j) -> (i + j).toDouble() } - val array2 = algebra.structureND(3, 3) { (i, j) -> (i - j).toDouble() } + val algebra = AlgebraND.real(3, 3) + val array1 = algebra.produce { (i, j) -> (i + j).toDouble() } + val array2 = algebra.produce { (i, j) -> (i - j).toDouble() } @Test fun testSum() { @@ -40,18 +38,17 @@ class NumberNDFieldTest { } @Test - fun testGeneration() = Double.algebra.linearSpace.run { + fun testGeneration() { - val array = buildMatrix(3, 3) { i, j -> + val array = LinearSpace.real.buildMatrix(3, 3) { i, j -> (i * 10 + j).toDouble() } - for (i in 0..2) { + for (i in 0..2) for (j in 0..2) { val expected = (i * 10 + j).toDouble() assertEquals(expected, array[i, j], "Error at index [$i, $j]") } - } } @Test @@ -74,7 +71,7 @@ class NumberNDFieldTest { @Test fun combineTest() { - val division = array1.zip(array2, Double::div) + val division = array1.combine(array2, Double::div) } object L2Norm : Norm, Double> { @@ -86,7 +83,7 @@ class NumberNDFieldTest { @Test fun testInternalContext() { algebra { - (DoubleField.ndAlgebra(*array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } } + (AlgebraND.real(*array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } } } } } diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt index ddd8fc3ea..544e05707 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.testutils diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt index 20a7b6a72..d0a312bb2 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.testutils diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt index daf18834a..3b0b49f31 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.testutils diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt index 951197fc6..4afa97ce5 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.testutils diff --git a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt index 68a3c995b..a24243cb4 100644 --- a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.misc diff --git a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt deleted file mode 100644 index 24b81322e..000000000 --- a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/operations/isInteger.kt +++ /dev/null @@ -1,11 +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.operations - -/** - * Check if number is an integer - */ -public actual fun Number.isInteger(): Boolean = js("Number").isInteger(this) as Boolean \ No newline at end of file diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt index 5ba0dbc9b..c50919e88 100644 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.misc diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt index 6e22c2381..69dd858c4 100644 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.operations @@ -18,9 +18,9 @@ public object JBigIntegerField : Ring, NumericAlgebra { override val one: BigInteger get() = BigInteger.ONE override fun number(value: Number): BigInteger = BigInteger.valueOf(value.toLong()) - override fun add(left: BigInteger, right: BigInteger): BigInteger = left.add(right) - override operator fun BigInteger.minus(arg: BigInteger): BigInteger = subtract(arg) - override fun multiply(left: BigInteger, right: BigInteger): BigInteger = left.multiply(right) + override fun add(a: BigInteger, b: BigInteger): BigInteger = a.add(b) + override operator fun BigInteger.minus(b: BigInteger): BigInteger = subtract(b) + override fun multiply(a: BigInteger, b: BigInteger): BigInteger = a.multiply(b) override operator fun BigInteger.unaryMinus(): BigInteger = negate() } @@ -39,15 +39,15 @@ public abstract class JBigDecimalFieldBase internal constructor( override val one: BigDecimal get() = BigDecimal.ONE - override fun add(left: BigDecimal, right: BigDecimal): BigDecimal = left.add(right) - override operator fun BigDecimal.minus(arg: BigDecimal): BigDecimal = subtract(arg) + override fun add(a: BigDecimal, b: BigDecimal): BigDecimal = a.add(b) + override operator fun BigDecimal.minus(b: BigDecimal): BigDecimal = subtract(b) override fun number(value: Number): BigDecimal = BigDecimal.valueOf(value.toDouble()) override fun scale(a: BigDecimal, value: Double): BigDecimal = a.multiply(value.toBigDecimal(mathContext), mathContext) - override fun multiply(left: BigDecimal, right: BigDecimal): BigDecimal = left.multiply(right, mathContext) - override fun divide(left: BigDecimal, right: BigDecimal): BigDecimal = left.divide(right, mathContext) + override fun multiply(a: BigDecimal, b: BigDecimal): BigDecimal = a.multiply(b, mathContext) + override fun divide(a: BigDecimal, b: BigDecimal): BigDecimal = a.divide(b, mathContext) override fun power(arg: BigDecimal, pow: Number): BigDecimal = arg.pow(pow.toInt(), mathContext) override fun sqrt(arg: BigDecimal): BigDecimal = arg.sqrt(mathContext) override operator fun BigDecimal.unaryMinus(): BigDecimal = negate(mathContext) diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt deleted file mode 100644 index b2f9b957b..000000000 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/isInteger.kt +++ /dev/null @@ -1,11 +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.operations - -/** - * Check if number is an integer - */ -public actual fun Number.isInteger(): Boolean = (this is Int) || (this is Long) || (this is Short) || (this.toDouble() % 1 == 0.0) \ No newline at end of file diff --git a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt index 68a3c995b..a24243cb4 100644 --- a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.misc diff --git a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt deleted file mode 100644 index b2f9b957b..000000000 --- a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/operations/isInteger.kt +++ /dev/null @@ -1,11 +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.operations - -/** - * Check if number is an integer - */ -public actual fun Number.isInteger(): Boolean = (this is Int) || (this is Long) || (this is Short) || (this.toDouble() % 1 == 0.0) \ No newline at end of file diff --git a/kmath-coroutines/README.md b/kmath-coroutines/README.md deleted file mode 100644 index 0d83a6c60..000000000 --- a/kmath-coroutines/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-coroutines - - - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-coroutines:0.3.0-dev-20`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-coroutines:0.3.0-dev-20' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-coroutines:0.3.0-dev-20") -} -``` diff --git a/kmath-coroutines/build.gradle.kts b/kmath-coroutines/build.gradle.kts index aa30c412b..317691ae5 100644 --- a/kmath-coroutines/build.gradle.kts +++ b/kmath-coroutines/build.gradle.kts @@ -7,9 +7,9 @@ plugins { kotlin.sourceSets { all { with(languageSettings) { - optIn("kotlinx.coroutines.InternalCoroutinesApi") - optIn("kotlinx.coroutines.ExperimentalCoroutinesApi") - optIn("kotlinx.coroutines.FlowPreview") + useExperimentalAnnotation("kotlinx.coroutines.InternalCoroutinesApi") + useExperimentalAnnotation("kotlinx.coroutines.ExperimentalCoroutinesApi") + useExperimentalAnnotation("kotlinx.coroutines.FlowPreview") } } diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt index 87aebff61..a41a30f55 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.chains diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt index 25e20291e..7b4d1f2af 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.chains diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt index ac0327d0b..f13d9907c 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.chains diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt index 994255e38..403472f28 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.chains @@ -10,7 +10,6 @@ import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.flow import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -import space.kscience.kmath.misc.UnstableKMathAPI /** * A not-necessary-Markov chain of some type @@ -125,22 +124,20 @@ public fun Chain.filter(block: (T) -> Boolean): Chain = object : Chain /** * Map the whole chain */ -@UnstableKMathAPI -public fun Chain.combine(mapper: suspend (Chain) -> R): Chain = object : Chain { - override suspend fun next(): R = mapper(this@combine) - override suspend fun fork(): Chain = this@combine.fork().combine(mapper) +public fun Chain.collect(mapper: suspend (Chain) -> R): Chain = object : Chain { + override suspend fun next(): R = mapper(this@collect) + override suspend fun fork(): Chain = this@collect.fork().collect(mapper) } -@UnstableKMathAPI -public fun Chain.combineWithState( +public fun Chain.collectWithState( state: S, stateFork: (S) -> S, mapper: suspend S.(Chain) -> R, ): Chain = object : Chain { - override suspend fun next(): R = state.mapper(this@combineWithState) + override suspend fun next(): R = state.mapper(this@collectWithState) override suspend fun fork(): Chain = - this@combineWithState.fork().combineWithState(stateFork(state), stateFork, mapper) + this@collectWithState.fork().collectWithState(stateFork(state), stateFork, mapper) } /** diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt index 7bf54d50f..1821daac9 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.chains @@ -10,12 +10,12 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.runningReduce import kotlinx.coroutines.flow.scan -import space.kscience.kmath.operations.GroupOps +import space.kscience.kmath.operations.GroupOperations import space.kscience.kmath.operations.Ring import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke -public fun Flow.cumulativeSum(group: GroupOps): Flow = +public fun Flow.cumulativeSum(group: GroupOperations): Flow = group { runningReduce { sum, element -> sum + element } } @ExperimentalCoroutinesApi diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt index 1f17efe49..3b90222dd 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.coroutines diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt index 4d4493aa4..914139a3e 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.streaming diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt index abe1c9df9..4b12b031d 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt +++ b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.streaming @@ -69,8 +69,6 @@ public class RingBuffer( @Suppress("NOTHING_TO_INLINE") private inline fun Int.forward(n: Int): Int = (this + n) % (buffer.size) - override fun toString(): String = Buffer.toString(this) - public companion object { public inline fun build(size: Int, empty: T): RingBuffer { val buffer = MutableBuffer.auto(size) { empty } as MutableBuffer diff --git a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt index dd6e39071..0e36706cf 100644 --- a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt +++ b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.chains diff --git a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt index ac9eb773a..3eb6f3aa6 100644 --- a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt +++ b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.structures @@ -28,7 +28,7 @@ public class LazyStructureND( @OptIn(PerformancePitfall::class) override fun elements(): Sequence> { val strides = DefaultStrides(shape) - val res = runBlocking { strides.asSequence().toList().map { index -> index to await(index) } } + val res = runBlocking { strides.indices().toList().map { index -> index to await(index) } } return res.asSequence() } } diff --git a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt index 9b67f7253..057ac5feb 100644 --- a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt +++ b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.streaming diff --git a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt index 305b97e5d..14081b0f5 100644 --- a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt +++ b/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt @@ -1,13 +1,13 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.streaming import kotlinx.coroutines.flow.* import kotlinx.coroutines.runBlocking -import space.kscience.kmath.operations.asSequence +import space.kscience.kmath.structures.asSequence import kotlin.test.Test import kotlin.test.assertEquals diff --git a/kmath-dimensions/README.md b/kmath-dimensions/README.md deleted file mode 100644 index 52097cf40..000000000 --- a/kmath-dimensions/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-dimensions - -A proof of concept module for adding type-safe dimensions to structures - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-dimensions:0.3.0-dev-20`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-dimensions:0.3.0-dev-20' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-dimensions:0.3.0-dev-20") -} -``` diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index e57c22834..53482f020 100644 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.dimensions diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt index f04536f04..70dc1001d 100644 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt +++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt @@ -1,15 +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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.dimensions -import space.kscience.kmath.linear.* +import space.kscience.kmath.linear.LinearSpace +import space.kscience.kmath.linear.Matrix +import space.kscience.kmath.linear.Point +import space.kscience.kmath.linear.transpose import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.algebra import kotlin.jvm.JvmInline /** @@ -149,7 +151,7 @@ public value class DMatrixContext>(public val context: context.run { (this@transpose as Matrix).transpose() }.coerce() public companion object { - public val real: DMatrixContext = DMatrixContext(Double.algebra.linearSpace) + public val real: DMatrixContext = DMatrixContext(LinearSpace.real) } } diff --git a/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt b/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt index 59260fe73..efa3170a3 100644 --- a/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt +++ b/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.dimensions diff --git a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index 610e8b4c0..324c78108 100644 --- a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.dimensions diff --git a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index e6d8b3b35..8fc683ed6 100644 --- a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ @file:JvmName("DimensionJVM") diff --git a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index 64edbe935..001d68935 100644 --- a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ b/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.dimensions diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md index 3fe6d9e1a..f88f53000 100644 --- a/kmath-ejml/README.md +++ b/kmath-ejml/README.md @@ -9,17 +9,17 @@ EJML based linear algebra implementation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-20`. +The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-14`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-ejml:0.3.0-dev-20' + implementation 'space.kscience:kmath-ejml:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ejml:0.3.0-dev-20") + implementation("space.kscience:kmath-ejml:0.3.0-dev-14") } ``` diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt index 32030dfe3..022a7874e 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt @@ -1,16 +1,13 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ejml -import space.kscience.kmath.linear.InverseMatrixFeature import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.Matrix import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.Structure2D import space.kscience.kmath.operations.Ring /** @@ -39,9 +36,4 @@ public abstract class EjmlLinearSpace, out M : org.ejml ): EjmlMatrix public abstract override fun buildVector(size: Int, initializer: A.(Int) -> T): EjmlVector - - @Suppress("UNCHECKED_CAST") - @UnstableKMathAPI - public fun EjmlMatrix.inverse(): Structure2D = - computeFeature(this, InverseMatrixFeature::class)?.inverse as Structure2D } diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt index 27fd3fc53..9ad0f9c77 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ejml diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt index 37995c27e..a6de1b657 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ejml diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt index dce739dc2..492d16510 100644 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt +++ b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt @@ -204,7 +204,7 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace): EjmlDoubleVector = v * this @UnstableKMathAPI - override fun computeFeature(structure: Matrix, type: KClass): F? { + override fun getFeature(structure: Matrix, type: KClass): F? { structure.getFeature(type)?.let { return it } val origin = structure.toEjml().origin @@ -239,10 +239,10 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) + qr.getQ(null, false).wrapMatrix() + OrthogonalFeature } - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } + override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix() + UFeature } } CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { @@ -250,7 +250,7 @@ public object EjmlLinearSpaceDDRM : EjmlLinearSpace by lazy { - lup.getLower(null).wrapMatrix().withFeature(LFeature) + lup.getLower(null).wrapMatrix() + LFeature } override val u: Matrix by lazy { - lup.getUpper(null).wrapMatrix().withFeature(UFeature) + lup.getUpper(null).wrapMatrix() + UFeature } override val p: Matrix by lazy { lup.getRowPivot(null).wrapMatrix() } @@ -438,7 +438,7 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace): EjmlFloatVector = v * this @UnstableKMathAPI - override fun computeFeature(structure: Matrix, type: KClass): F? { + override fun getFeature(structure: Matrix, type: KClass): F? { structure.getFeature(type)?.let { return it } val origin = structure.toEjml().origin @@ -473,10 +473,10 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) + qr.getQ(null, false).wrapMatrix() + OrthogonalFeature } - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } + override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix() + UFeature } } CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { @@ -484,7 +484,7 @@ public object EjmlLinearSpaceFDRM : EjmlLinearSpace by lazy { - lup.getLower(null).wrapMatrix().withFeature(LFeature) + lup.getLower(null).wrapMatrix() + LFeature } override val u: Matrix by lazy { - lup.getUpper(null).wrapMatrix().withFeature(UFeature) + lup.getUpper(null).wrapMatrix() + UFeature } override val p: Matrix by lazy { lup.getRowPivot(null).wrapMatrix() } @@ -680,7 +680,7 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace): EjmlDoubleVector = v * this @UnstableKMathAPI - override fun computeFeature(structure: Matrix, type: KClass): F? { + override fun getFeature(structure: Matrix, type: KClass): F? { structure.getFeature(type)?.let { return it } val origin = structure.toEjml().origin @@ -691,10 +691,10 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) + qr.getQ(null, false).wrapMatrix() + OrthogonalFeature } - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } + override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix() + UFeature } } CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { @@ -702,7 +702,7 @@ public object EjmlLinearSpaceDSCC : EjmlLinearSpace by lazy { - lu.getLower(null).wrapMatrix().withFeature(LFeature) + lu.getLower(null).wrapMatrix() + LFeature } override val u: Matrix by lazy { - lu.getUpper(null).wrapMatrix().withFeature(UFeature) + lu.getUpper(null).wrapMatrix() + UFeature } override val inverse: Matrix by lazy { @@ -909,7 +909,7 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace): EjmlFloatVector = v * this @UnstableKMathAPI - override fun computeFeature(structure: Matrix, type: KClass): F? { + override fun getFeature(structure: Matrix, type: KClass): F? { structure.getFeature(type)?.let { return it } val origin = structure.toEjml().origin @@ -920,10 +920,10 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace by lazy { - qr.getQ(null, false).wrapMatrix().withFeature(OrthogonalFeature) + qr.getQ(null, false).wrapMatrix() + OrthogonalFeature } - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix().withFeature(UFeature) } + override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix() + UFeature } } CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { @@ -931,7 +931,7 @@ public object EjmlLinearSpaceFSCC : EjmlLinearSpace by lazy { - lu.getLower(null).wrapMatrix().withFeature(LFeature) + lu.getLower(null).wrapMatrix() + LFeature } override val u: Matrix by lazy { - lu.getUpper(null).wrapMatrix().withFeature(UFeature) + lu.getUpper(null).wrapMatrix() + UFeature } override val inverse: Matrix by lazy { diff --git a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt index 209bb5b27..08afa4c68 100644 --- a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt +++ b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ejml @@ -9,11 +9,12 @@ import org.ejml.data.DMatrixRMaj import org.ejml.dense.row.CommonOps_DDRM import org.ejml.dense.row.RandomMatrices_DDRM import org.ejml.dense.row.factory.DecompositionFactory_DDRM -import space.kscience.kmath.linear.* +import space.kscience.kmath.linear.DeterminantFeature +import space.kscience.kmath.linear.LupDecompositionFeature +import space.kscience.kmath.linear.getFeature import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.algebra import kotlin.random.Random import kotlin.random.asJavaRandom import kotlin.test.* @@ -58,9 +59,9 @@ internal class EjmlMatrixTest { fun features() { val m = randomMatrix val w = EjmlDoubleMatrix(m) - val det: DeterminantFeature = EjmlLinearSpaceDDRM.computeFeature(w) ?: fail() + val det: DeterminantFeature = EjmlLinearSpaceDDRM.getFeature(w) ?: fail() assertEquals(CommonOps_DDRM.det(m), det.determinant) - val lup: LupDecompositionFeature = EjmlLinearSpaceDDRM.computeFeature(w) ?: fail() + val lup: LupDecompositionFeature = EjmlLinearSpaceDDRM.getFeature(w) ?: fail() val ludecompositionF64 = DecompositionFactory_DDRM.lu(m.numRows, m.numCols) .also { it.decompose(m.copy()) } @@ -81,24 +82,4 @@ internal class EjmlMatrixTest { val m = randomMatrix assertSame(m, EjmlDoubleMatrix(m).origin) } - - @Test - fun inverse() = EjmlLinearSpaceDDRM { - val random = Random(1224) - val dim = 20 - - val space = Double.algebra.linearSpace - - //creating invertible matrix - val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } - val l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 } - val matrix = space { l dot u } - val inverted = matrix.toEjml().inverse() - - val res = matrix dot inverted - - println(StructureND.toString(res)) - - assertTrue { StructureND.contentEquals(one(dim, dim), res, 1e-3) } - } } diff --git a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt index 9592bfa6c..c87a01436 100644 --- a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt +++ b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.ejml diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index 197190dcd..d449b4540 100644 --- a/kmath-for-real/README.md +++ b/kmath-for-real/README.md @@ -9,17 +9,17 @@ Specialization of KMath APIs for Double numbers. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-20`. +The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-14`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-for-real:0.3.0-dev-20' + implementation 'space.kscience:kmath-for-real:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-for-real:0.3.0-dev-20") + implementation("space.kscience:kmath-for-real:0.3.0-dev-14") } ``` diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt index 671e272ab..16889aea4 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ @file:OptIn(PerformancePitfall::class) @@ -12,10 +12,9 @@ import space.kscience.kmath.linear.* import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.algebra -import space.kscience.kmath.operations.asIterable import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer +import space.kscience.kmath.structures.asIterable import kotlin.math.pow /* @@ -33,18 +32,18 @@ import kotlin.math.pow public typealias RealMatrix = Matrix public fun realMatrix(rowNum: Int, colNum: Int, initializer: DoubleField.(i: Int, j: Int) -> Double): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum, initializer) + LinearSpace.real.buildMatrix(rowNum, colNum, initializer) @OptIn(UnstableKMathAPI::class) public fun realMatrix(rowNum: Int, colNum: Int): MatrixBuilder = - Double.algebra.linearSpace.matrix(rowNum, colNum) + LinearSpace.real.matrix(rowNum, colNum) public fun Array.toMatrix(): RealMatrix { - return Double.algebra.linearSpace.buildMatrix(size, this[0].size) { row, col -> this@toMatrix[row][col] } + return LinearSpace.real.buildMatrix(size, this[0].size) { row, col -> this@toMatrix[row][col] } } public fun Sequence.toMatrix(): RealMatrix = toList().let { - Double.algebra.linearSpace.buildMatrix(it.size, it[0].size) { row, col -> it[row][col] } + LinearSpace.real.buildMatrix(it.size, it[0].size) { row, col -> it[row][col] } } public fun RealMatrix.repeatStackVertical(n: Int): RealMatrix = @@ -57,37 +56,37 @@ public fun RealMatrix.repeatStackVertical(n: Int): RealMatrix = */ public operator fun RealMatrix.times(double: Double): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> + LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> get(row, col) * double } public operator fun RealMatrix.plus(double: Double): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> + LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> get(row, col) + double } public operator fun RealMatrix.minus(double: Double): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> + LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> get(row, col) - double } public operator fun RealMatrix.div(double: Double): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> + LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> get(row, col) / double } public operator fun Double.times(matrix: RealMatrix): RealMatrix = - Double.algebra.linearSpace.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> + LinearSpace.real.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> this@times * matrix[row, col] } public operator fun Double.plus(matrix: RealMatrix): RealMatrix = - Double.algebra.linearSpace.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> + LinearSpace.real.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> this@plus + matrix[row, col] } public operator fun Double.minus(matrix: RealMatrix): RealMatrix = - Double.algebra.linearSpace.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> + LinearSpace.real.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> this@minus - matrix[row, col] } @@ -102,20 +101,20 @@ public operator fun Double.minus(matrix: RealMatrix): RealMatrix = @UnstableKMathAPI public operator fun RealMatrix.times(other: RealMatrix): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> this@times[row, col] * other[row, col] } + LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> this@times[row, col] * other[row, col] } public operator fun RealMatrix.plus(other: RealMatrix): RealMatrix = - Double.algebra.linearSpace.run { this@plus + other } + LinearSpace.real.run { this@plus + other } public operator fun RealMatrix.minus(other: RealMatrix): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { row, col -> this@minus[row, col] - other[row, col] } + LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> this@minus[row, col] - other[row, col] } /* * Operations on columns */ public inline fun RealMatrix.appendColumn(crossinline mapper: (Buffer) -> Double): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum + 1) { row, col -> + LinearSpace.real.buildMatrix(rowNum, colNum + 1) { row, col -> if (col < colNum) get(row, col) else @@ -123,7 +122,7 @@ public inline fun RealMatrix.appendColumn(crossinline mapper: (Buffer) - } public fun RealMatrix.extractColumns(columnRange: IntRange): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, columnRange.count()) { row, col -> + LinearSpace.real.buildMatrix(rowNum, columnRange.count()) { row, col -> this@extractColumns[row, columnRange.first + col] } @@ -156,14 +155,14 @@ public fun RealMatrix.max(): Double? = elements().map { (_, value) -> value }.ma public fun RealMatrix.average(): Double = elements().map { (_, value) -> value }.average() public inline fun RealMatrix.map(crossinline transform: (Double) -> Double): RealMatrix = - Double.algebra.linearSpace.buildMatrix(rowNum, colNum) { i, j -> + LinearSpace.real.buildMatrix(rowNum, colNum) { i, j -> transform(get(i, j)) } /** * Inverse a square real matrix using LUP decomposition */ -public fun RealMatrix.inverseWithLup(): RealMatrix = Double.algebra.linearSpace.lupSolver().inverse(this) +public fun RealMatrix.inverseWithLup(): RealMatrix = LinearSpace.real.inverseWithLup(this) //extended operations diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt similarity index 90% rename from kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt rename to kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt index 7b9740c35..d942c31f2 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt @@ -1,18 +1,20 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.real import space.kscience.kmath.linear.Point import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleL2Norm +import space.kscience.kmath.operations.Norm import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableBuffer.Companion.double import space.kscience.kmath.structures.asBuffer +import space.kscience.kmath.structures.fold import space.kscience.kmath.structures.indices import kotlin.math.pow +import kotlin.math.sqrt public typealias DoubleVector = Point @@ -103,4 +105,8 @@ public fun DoubleVector.sum(): Double { return res } -public val DoubleVector.norm: Double get() = DoubleL2Norm.norm(this) \ No newline at end of file +public object VectorL2Norm : Norm { + override fun norm(arg: DoubleVector): Double = sqrt(arg.fold(0.0) { acc: Double, d: Double -> acc + d.pow(2) }) +} + +public val DoubleVector.norm: Double get() = VectorL2Norm.norm(this) \ No newline at end of file diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt index dc5c58be0..f42a47a27 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt @@ -1,18 +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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.real +import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.linear.linearSpace -import space.kscience.kmath.operations.algebra /** * Optimized dot product for real matrices */ -public infix fun Matrix.dot(other: Matrix): Matrix = Double.algebra.linearSpace.run { +public infix fun Matrix.dot(other: Matrix): Matrix = LinearSpace.real.run { this@dot dot other } \ No newline at end of file diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt index 1926ef02c..fba999e6c 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.real diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt index 52362f4b4..b2c3209c2 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.real @@ -13,8 +13,8 @@ import space.kscience.kmath.structures.DoubleBuffer * Map one [BufferND] using function without indices. */ public inline fun BufferND.mapInline(crossinline transform: DoubleField.(Double) -> Double): BufferND { - val array = DoubleArray(indices.linearSize) { offset -> DoubleField.transform(buffer[offset]) } - return BufferND(indices, DoubleBuffer(array)) + val array = DoubleArray(strides.linearSize) { offset -> DoubleField.transform(buffer[offset]) } + return BufferND(strides, DoubleBuffer(array)) } /** diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt index 4a0e8de1d..1400ed0b7 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt @@ -1,16 +1,16 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.real -import space.kscience.kmath.linear.linearSpace +import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.matrix import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.algebra +import space.kscience.kmath.real.* import space.kscience.kmath.structures.contentEquals import kotlin.test.Test import kotlin.test.assertEquals @@ -59,13 +59,13 @@ internal class DoubleMatrixTest { } @Test - fun testMatrixAndDouble() = Double.algebra.linearSpace.run { + fun testMatrixAndDouble() { val matrix1 = realMatrix(2, 3)( 1.0, 0.0, 3.0, 4.0, 6.0, 2.0 ) val matrix2 = (matrix1 * 2.5 + 1.0 - 2.0) / 2.0 - val expectedResult = matrix(2, 3)( + val expectedResult = LinearSpace.real.matrix(2, 3)( 0.75, -0.5, 3.25, 4.5, 7.0, 2.0 ) @@ -159,8 +159,8 @@ internal class DoubleMatrixTest { } @Test - fun testAllElementOperations() = Double.algebra.linearSpace.run { - val matrix1 = matrix(2, 4)( + fun testAllElementOperations() { + val matrix1 = LinearSpace.real.matrix(2, 4)( -1.0, 0.0, 3.0, 15.0, 4.0, -6.0, 7.0, -11.0 ) diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt index e77b96c12..9a254a0b0 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt @@ -1,14 +1,14 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.real +import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.asMatrix -import space.kscience.kmath.linear.linearSpace import space.kscience.kmath.linear.transpose -import space.kscience.kmath.operations.algebra +import space.kscience.kmath.real.plus import space.kscience.kmath.structures.DoubleBuffer import kotlin.test.Test import kotlin.test.assertEquals @@ -30,12 +30,12 @@ internal class DoubleVectorTest { } @Test - fun testDot() = Double.algebra.linearSpace.run { + fun testDot() { val vector1 = DoubleBuffer(5) { it.toDouble() } val vector2 = DoubleBuffer(5) { 5 - it.toDouble() } val matrix1 = vector1.asMatrix() val matrix2 = vector2.asMatrix().transpose() - val product = matrix1 dot matrix2 + val product = LinearSpace.real.run { matrix1 dot matrix2 } assertEquals(5.0, product[1, 0]) assertEquals(6.0, product[2, 2]) } diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt index 8fed8d10e..ec1ed8f50 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.real diff --git a/kmath-functions/README.md b/kmath-functions/README.md index 6379ad0b5..d0beae2c8 100644 --- a/kmath-functions/README.md +++ b/kmath-functions/README.md @@ -11,17 +11,17 @@ Functions and interpolations. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-20`. +The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-14`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-functions:0.3.0-dev-20' + implementation 'space.kscience:kmath-functions:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -32,6 +32,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-functions:0.3.0-dev-20") + implementation("space.kscience:kmath-functions:0.3.0-dev-14") } ``` diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt index 16af7f555..4225a7572 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.functions diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt index a36d36f52..54b285a70 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.functions @@ -104,12 +104,12 @@ public class PolynomialSpace( Polynomial(coefficients.map { -it }) } - override fun add(left: Polynomial, right: Polynomial): Polynomial { - val dim = max(left.coefficients.size, right.coefficients.size) + override fun add(a: Polynomial, b: Polynomial): Polynomial { + val dim = max(a.coefficients.size, b.coefficients.size) return ring { Polynomial(List(dim) { index -> - left.coefficients.getOrElse(index) { zero } + right.coefficients.getOrElse(index) { zero } + a.coefficients.getOrElse(index) { zero } + b.coefficients.getOrElse(index) { zero } }) } } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt index 88b24c756..52b7e50db 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.functions diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt index 9785d7744..dc3f41861 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.integration @@ -53,7 +53,7 @@ public class GaussIntegrator( } } - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand = with(algebra) { + override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand = with(algebra) { val f = integrand.function val (points, weights) = buildRule(integrand) var res = zero @@ -73,8 +73,7 @@ public class GaussIntegrator( } /** - * Create a Gauss integrator for this field. By default, uses Legendre rule to compute points and weights. - * Custom rules could be provided by [GaussIntegratorRuleFactory] feature. + * Create a Gauss-Legendre integrator for this field. * @see [GaussIntegrator] */ public val Field.gaussIntegrator: GaussIntegrator get() = GaussIntegrator(this) @@ -98,7 +97,7 @@ public fun GaussIntegrator.integrate( val ranges = UnivariateIntegrandRanges( (0 until intervals).map { i -> (range.start + rangeSize * i)..(range.start + rangeSize * (i + 1)) to order } ) - return process( + return integrate( UnivariateIntegrand( function, IntegrationRange(range), diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt index 778d85e66..b09129626 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt @@ -1,14 +1,14 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.integration -import space.kscience.kmath.operations.map import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.asBuffer +import space.kscience.kmath.structures.map import kotlin.jvm.Synchronized import kotlin.math.ulp import kotlin.native.concurrent.ThreadLocal diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt index 05e2e5c55..0fdfee6c6 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt @@ -1,22 +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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.integration -import space.kscience.kmath.misc.Feature -import space.kscience.kmath.misc.FeatureSet -import space.kscience.kmath.misc.Featured import kotlin.reflect.KClass -public interface IntegrandFeature : Feature { +public interface IntegrandFeature { override fun toString(): String } -public interface Integrand : Featured { - public val features: FeatureSet - override fun getFeature(type: KClass): T? = features.getFeature(type) +public interface Integrand { + public val features: Set + public fun getFeature(type: KClass): T? } public inline fun Integrand.getFeature(): T? = getFeature(T::class) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt index 1cf15b42f..18c428667 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.integration @@ -12,5 +12,5 @@ public interface Integrator { /** * Runs one integration pass and return a new [Integrand] with a new set of features. */ - public fun process(integrand: I): I + public fun integrate(integrand: I): I } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt index 96b81aaa6..fcc0a8d62 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt @@ -1,26 +1,34 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.integration import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.FeatureSet +import kotlin.reflect.KClass public class MultivariateIntegrand internal constructor( - override val features: FeatureSet, + private val featureMap: Map, IntegrandFeature>, public val function: (Point) -> T, ) : Integrand { + override val features: Set get() = featureMap.values.toSet() + + @Suppress("UNCHECKED_CAST") + override fun getFeature(type: KClass): T? = featureMap[type] as? T + + public operator fun plus(pair: Pair, F>): MultivariateIntegrand = + MultivariateIntegrand(featureMap + pair, function) + public operator fun plus(feature: F): MultivariateIntegrand = - MultivariateIntegrand(features.with(feature), function) + plus(feature::class to feature) } @Suppress("FunctionName") public fun MultivariateIntegrand( vararg features: IntegrandFeature, function: (Point) -> T, -): MultivariateIntegrand = MultivariateIntegrand(FeatureSet.of(*features), function) +): MultivariateIntegrand = MultivariateIntegrand(features.associateBy { it::class }, function) public val MultivariateIntegrand.value: T? get() = getFeature>()?.value diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt index 7815757aa..9bcc8e4d9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.integration @@ -44,7 +44,7 @@ public class SimpsonIntegrator( return res } - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { + override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { val ranges = integrand.getFeature() return if (ranges != null) { val res = algebra.sum(ranges.ranges.map { integrateRange(integrand, it.first, it.second) }) @@ -90,7 +90,7 @@ public object DoubleSimpsonIntegrator : UnivariateIntegrator { return res } - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { + override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { val ranges = integrand.getFeature() return if (ranges != null) { val res = ranges.ranges.sumOf { integrateRange(integrand, it.first, it.second) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt index eb88d9ae0..6581d5dd8 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.integration @@ -12,15 +12,19 @@ import space.kscience.kmath.interpolation.SplineInterpolator import space.kscience.kmath.interpolation.interpolatePolynomials import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.Field +import space.kscience.kmath.operations.invoke +import space.kscience.kmath.operations.sum import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.MutableBufferFactory +import space.kscience.kmath.structures.map /** * Compute analytical indefinite integral of this [PiecewisePolynomial], keeping all intervals intact */ -@OptIn(PerformancePitfall::class) +@PerformancePitfall @UnstableKMathAPI public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = PiecewisePolynomial(pieces.map { it.first to it.second.integrate(algebra) }) @@ -28,8 +32,6 @@ public fun > PiecewisePolynomial.integrate(algebra: Field> PiecewisePolynomial.integrate( @@ -54,7 +56,7 @@ public class SplineIntegrator>( public val algebra: Field, public val bufferFactory: MutableBufferFactory, ) : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand = algebra { + override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand = algebra { val range = integrand.getFeature()?.range ?: 0.0..1.0 val interpolator: PolynomialInterpolator = SplineInterpolator(algebra, bufferFactory) @@ -83,7 +85,7 @@ public class SplineIntegrator>( */ @UnstableKMathAPI public object DoubleSplineIntegrator : UnivariateIntegrator { - override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { + override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { val range = integrand.getFeature()?.range ?: 0.0..1.0 val interpolator: PolynomialInterpolator = SplineInterpolator(DoubleField, ::DoubleBuffer) @@ -100,7 +102,6 @@ public object DoubleSplineIntegrator : UnivariateIntegrator { } } -@Suppress("unused") @UnstableKMathAPI public inline val DoubleField.splineIntegrator: UnivariateIntegrator get() = DoubleSplineIntegrator \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt index 6fd75e6e6..f994ba9f9 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt @@ -1,28 +1,37 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.integration -import space.kscience.kmath.misc.FeatureSet import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.DoubleBuffer +import kotlin.reflect.KClass public class UnivariateIntegrand internal constructor( - override val features: FeatureSet, + private val featureMap: Map, IntegrandFeature>, public val function: (Double) -> T, ) : Integrand { + + override val features: Set get() = featureMap.values.toSet() + + @Suppress("UNCHECKED_CAST") + override fun getFeature(type: KClass): T? = featureMap[type] as? T + + public operator fun plus(pair: Pair, F>): UnivariateIntegrand = + UnivariateIntegrand(featureMap + pair, function) + public operator fun plus(feature: F): UnivariateIntegrand = - UnivariateIntegrand(features.with(feature), function) + plus(feature::class to feature) } @Suppress("FunctionName") public fun UnivariateIntegrand( function: (Double) -> T, vararg features: IntegrandFeature, -): UnivariateIntegrand = UnivariateIntegrand(FeatureSet.of(*features), function) +): UnivariateIntegrand = UnivariateIntegrand(features.associateBy { it::class }, function) public typealias UnivariateIntegrator = Integrator> @@ -70,7 +79,7 @@ public val UnivariateIntegrand.value: T get() = valueOrNull ?: erro public fun UnivariateIntegrator.integrate( vararg features: IntegrandFeature, function: (Double) -> T, -): UnivariateIntegrand = process(UnivariateIntegrand(function, *features)) +): UnivariateIntegrand = integrate(UnivariateIntegrand(function, *features)) /** * A shortcut method to integrate a [function] in [range] with additional [features]. @@ -81,7 +90,7 @@ public fun UnivariateIntegrator.integrate( range: ClosedRange, vararg features: IntegrandFeature, function: (Double) -> T, -): UnivariateIntegrand = process(UnivariateIntegrand(function, IntegrationRange(range), *features)) +): UnivariateIntegrand = integrate(UnivariateIntegrand(function, IntegrationRange(range), *features)) /** * A shortcut method to integrate a [function] in [range] with additional features. @@ -98,5 +107,5 @@ public fun UnivariateIntegrator.integrate( featureBuilder() add(IntegrationRange(range)) } - return process(UnivariateIntegrand(function, *features.toTypedArray())) + return integrate(UnivariateIntegrand(function, *features.toTypedArray())) } diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt index 2266092a3..7a096f902 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ @file:OptIn(UnstableKMathAPI::class) @@ -9,7 +9,6 @@ package space.kscience.kmath.interpolation import space.kscience.kmath.data.XYColumnarData import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.asFunction import space.kscience.kmath.functions.value import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.operations.Ring @@ -43,50 +42,20 @@ public fun > PolynomialInterpolator.interpolatePolynomials( x: Buffer, y: Buffer, ): PiecewisePolynomial { - val pointSet = XYColumnarData.of(x, y) + val pointSet = XYColumnarData(x, y) return interpolatePolynomials(pointSet) } public fun > PolynomialInterpolator.interpolatePolynomials( data: Map, ): PiecewisePolynomial { - val pointSet = XYColumnarData.of(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) + val pointSet = XYColumnarData(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) return interpolatePolynomials(pointSet) } public fun > PolynomialInterpolator.interpolatePolynomials( data: List>, ): PiecewisePolynomial { - val pointSet = XYColumnarData.of(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) + val pointSet = XYColumnarData(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) return interpolatePolynomials(pointSet) } - -public fun > PolynomialInterpolator.interpolate( - x: Buffer, - y: Buffer, -): (T) -> T? = interpolatePolynomials(x, y).asFunction(algebra) - -public fun > PolynomialInterpolator.interpolate( - data: Map, -): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) - -public fun > PolynomialInterpolator.interpolate( - data: List>, -): (T) -> T? = interpolatePolynomials(data).asFunction(algebra) - - -public fun > PolynomialInterpolator.interpolate( - x: Buffer, - y: Buffer, - defaultValue: T, -): (T) -> T = interpolatePolynomials(x, y).asFunction(algebra, defaultValue) - -public fun > PolynomialInterpolator.interpolate( - data: Map, - defaultValue: T, -): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) - -public fun > PolynomialInterpolator.interpolate( - data: List>, - defaultValue: T, -): (T) -> T = interpolatePolynomials(data).asFunction(algebra, defaultValue) \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt index 34d7bcf41..eff9cd97d 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.interpolation @@ -22,7 +22,6 @@ internal fun > insureSorted(points: XYColumnarData<*, T, *>) { * Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java */ public class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { - @OptIn(UnstableKMathAPI::class) override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { require(points.size > 0) { "Point array should not be empty" } @@ -38,6 +37,3 @@ public class LinearInterpolator>(override val algebra: Field> Field.linearInterpolator: LinearInterpolator - get() = LinearInterpolator(this) diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt index afcb33bd4..ac9708d01 100644 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt +++ b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.interpolation @@ -63,8 +63,8 @@ public class SplineInterpolator>( //Shift coefficients to represent absolute polynomial instead of one with an offset val polynomial = Polynomial( a - b * x0 + c * x02 - d * x03, - b - 2 * c * x0 + 3 * d * x02, - c - 3 * d * x0, + b - 2*c*x0 + 3*d*x02, + c - 3*d*x0, d ) cOld = c @@ -72,12 +72,8 @@ public class SplineInterpolator>( } } } + + public companion object { + public val double: SplineInterpolator = SplineInterpolator(DoubleField, ::DoubleBuffer) + } } - - -public fun > Field.splineInterpolator( - bufferFactory: MutableBufferFactory, -): SplineInterpolator = SplineInterpolator(this, bufferFactory) - -public val DoubleField.splineInterpolator: SplineInterpolator - get() = SplineInterpolator(this, ::DoubleBuffer) \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt index 05c16d17e..21e5473a0 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.functions diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt index 9f48a15ea..533389a6e 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.integration diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt index 9f2d71554..eaf7abbfd 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.integration diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt index afeba0be4..4dffb276f 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.integration diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt index 1143036d4..c3388c265 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt @@ -1,10 +1,12 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.interpolation +import space.kscience.kmath.functions.PiecewisePolynomial +import space.kscience.kmath.functions.asFunction import space.kscience.kmath.operations.DoubleField import kotlin.test.Test import kotlin.test.assertEquals @@ -19,8 +21,8 @@ internal class LinearInterpolatorTest { 3.0 to 4.0 ) - //val polynomial: PiecewisePolynomial = DoubleField.linearInterpolator.interpolatePolynomials(data) - val function = DoubleField.linearInterpolator.interpolate(data) + val polynomial: PiecewisePolynomial = LinearInterpolator(DoubleField).interpolatePolynomials(data) + val function = polynomial.asFunction(DoubleField) assertEquals(null, function(-1.0)) assertEquals(0.5, function(0.5)) assertEquals(2.0, function(1.5)) diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt index 4c7d816d4..42f41ab80 100644 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt +++ b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt @@ -1,10 +1,12 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.interpolation +import space.kscience.kmath.functions.PiecewisePolynomial +import space.kscience.kmath.functions.asFunction import space.kscience.kmath.operations.DoubleField import kotlin.math.PI import kotlin.math.sin @@ -19,10 +21,9 @@ internal class SplineInterpolatorTest { x to sin(x) } - //val polynomial: PiecewisePolynomial = DoubleField.splineInterpolator.interpolatePolynomials(data) - - val function = DoubleField.splineInterpolator.interpolate(data, Double.NaN) + val polynomial: PiecewisePolynomial = SplineInterpolator.double.interpolatePolynomials(data) + val function = polynomial.asFunction(DoubleField, Double.NaN) assertEquals(Double.NaN, function(-1.0)) assertEquals(sin(0.5), function(0.5), 0.1) assertEquals(sin(1.5), function(1.5), 0.1) diff --git a/kmath-geometry/README.md b/kmath-geometry/README.md deleted file mode 100644 index 6b8fb25a0..000000000 --- a/kmath-geometry/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-geometry - - - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-geometry:0.3.0-dev-20`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-geometry:0.3.0-dev-20' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-geometry:0.3.0-dev-20") -} -``` diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt index d00575bcc..e8b1ce95b 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.geometry @@ -47,7 +47,7 @@ public object Euclidean2DSpace : GeometrySpace, ScaleOperations, ScaleOperations { public val value: T public companion object { - public fun double(): ObjectCounter = ObjectCounter(DoubleField) + public fun real(): ObjectCounter = ObjectCounter(DoubleField) } } @@ -32,16 +32,6 @@ public class IntCounter : Counter { override val value: Int get() = innerValue.value } -public operator fun IntCounter.inc(): IntCounter { - add(1) - return this -} - -public operator fun IntCounter.dec(): IntCounter { - add(-1) - return this -} - public class LongCounter : Counter { private val innerValue = atomic(0L) @@ -52,17 +42,7 @@ public class LongCounter : Counter { override val value: Long get() = innerValue.value } -public operator fun LongCounter.inc(): LongCounter { - add(1L) - return this -} - -public operator fun LongCounter.dec(): LongCounter { - add(-1L) - return this -} - -public class ObjectCounter(private val group: Group) : Counter { +public class ObjectCounter(public val group: Ring) : Counter { private val innerValue = atomic(group.zero) override fun add(delta: T) { diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt index 61d0b9f33..27b14b65e 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.histogram @@ -9,7 +9,6 @@ import space.kscience.kmath.domains.Domain import space.kscience.kmath.domains.HyperSquareDomain import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.structures.* import kotlin.math.floor @@ -28,9 +27,10 @@ public class DoubleHistogramSpace( public val dimension: Int get() = lower.size - override val shape: IntArray = IntArray(binNums.size) { binNums[it] + 2 } - override val histogramValueSpace: DoubleFieldND = DoubleField.ndAlgebra(*shape) + private val shape = IntArray(binNums.size) { binNums[it] + 2 } + override val histogramValueSpace: DoubleFieldND = AlgebraND.real(*shape) + override val strides: Strides get() = histogramValueSpace.strides private val binSize = DoubleBuffer(dimension) { (upper[it] - lower[it]) / binNums[it] } /** @@ -51,7 +51,7 @@ public class DoubleHistogramSpace( val lowerBoundary = index.mapIndexed { axis, i -> when (i) { 0 -> Double.NEGATIVE_INFINITY - shape[axis] - 1 -> upper[axis] + strides.shape[axis] - 1 -> upper[axis] else -> lower[axis] + (i.toDouble()) * binSize[axis] } }.asBuffer() @@ -59,7 +59,7 @@ public class DoubleHistogramSpace( val upperBoundary = index.mapIndexed { axis, i -> when (i) { 0 -> lower[axis] - shape[axis] - 1 -> Double.POSITIVE_INFINITY + strides.shape[axis] - 1 -> Double.POSITIVE_INFINITY else -> lower[axis] + (i.toDouble() + 1) * binSize[axis] } }.asBuffer() @@ -74,7 +74,7 @@ public class DoubleHistogramSpace( } override fun produce(builder: HistogramBuilder.() -> Unit): IndexedHistogram { - val ndCounter = StructureND.auto(shape) { Counter.double() } + val ndCounter = StructureND.auto(strides) { Counter.real() } val hBuilder = HistogramBuilder { point, value -> val index = getIndex(point) ndCounter[index].add(value.toDouble()) diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt index 4e803fc63..946aa814b 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.histogram diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt index 9275c1c5e..44f3072d2 100644 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt +++ b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.histogram @@ -8,9 +8,8 @@ package space.kscience.kmath.histogram import space.kscience.kmath.domains.Domain import space.kscience.kmath.linear.Point import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.DefaultStrides import space.kscience.kmath.nd.FieldND -import space.kscience.kmath.nd.Shape +import space.kscience.kmath.nd.Strides import space.kscience.kmath.nd.StructureND import space.kscience.kmath.operations.Group import space.kscience.kmath.operations.ScaleOperations @@ -35,12 +34,13 @@ public class IndexedHistogram, V : Any>( return context.produceBin(index, values[index]) } - override val dimension: Int get() = context.shape.size + override val dimension: Int get() = context.strides.shape.size override val bins: Iterable> - get() = DefaultStrides(context.shape).asSequence().map { + get() = context.strides.indices().map { context.produceBin(it, values[it]) }.asIterable() + } /** @@ -49,7 +49,7 @@ public class IndexedHistogram, V : Any>( public interface IndexedHistogramSpace, V : Any> : Group>, ScaleOperations> { //public val valueSpace: Space - public val shape: Shape + public val strides: Strides public val histogramValueSpace: FieldND //= NDAlgebra.space(valueSpace, Buffer.Companion::boxing, *shape), /** @@ -66,10 +66,10 @@ public interface IndexedHistogramSpace, V : Any> public fun produce(builder: HistogramBuilder.() -> Unit): IndexedHistogram - override fun add(left: IndexedHistogram, right: IndexedHistogram): IndexedHistogram { - require(left.context == this) { "Can't operate on a histogram produced by external space" } - require(right.context == this) { "Can't operate on a histogram produced by external space" } - return IndexedHistogram(this, histogramValueSpace { left.values + right.values }) + override fun add(a: IndexedHistogram, b: IndexedHistogram): IndexedHistogram { + require(a.context == this) { "Can't operate on a histogram produced by external space" } + require(b.context == this) { "Can't operate on a histogram produced by external space" } + return IndexedHistogram(this, histogramValueSpace { a.values + b.values }) } override fun scale(a: IndexedHistogram, value: Double): IndexedHistogram { diff --git a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt index 923cc98de..c797eb65a 100644 --- a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt +++ b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt @@ -1,11 +1,10 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.histogram -import space.kscience.kmath.nd.DefaultStrides import space.kscience.kmath.operations.invoke import space.kscience.kmath.real.DoubleVector import kotlin.random.Random @@ -70,7 +69,7 @@ internal class MultivariateHistogramTest { } val res = histogram1 - histogram2 assertTrue { - DefaultStrides(shape).asSequence().all { index -> + strides.indices().all { index -> res.values[index] <= histogram1.values[index] } } diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt index 0853615e6..96f945f6a 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.histogram @@ -39,7 +39,7 @@ public class TreeHistogram( @PublishedApi internal class TreeHistogramBuilder(val binFactory: (Double) -> UnivariateDomain) : UnivariateHistogramBuilder { - internal class BinCounter(val domain: UnivariateDomain, val counter: Counter = Counter.double()) : + internal class BinCounter(val domain: UnivariateDomain, val counter: Counter = Counter.real()) : ClosedFloatingPointRange by domain.range private val bins: TreeMap = TreeMap() @@ -88,20 +88,20 @@ public class TreeHistogramSpace( TreeHistogramBuilder(binFactory).apply(block).build() override fun add( - left: UnivariateHistogram, - right: UnivariateHistogram, + a: UnivariateHistogram, + b: UnivariateHistogram, ): UnivariateHistogram { // require(a.context == this) { "Histogram $a does not belong to this context" } // require(b.context == this) { "Histogram $b does not belong to this context" } val bins = TreeMap().apply { - (left.bins.map { it.domain } union right.bins.map { it.domain }).forEach { def -> + (a.bins.map { it.domain } union b.bins.map { it.domain }).forEach { def -> put( def.center, UnivariateBin( def, - value = (left[def.center]?.value ?: 0.0) + (right[def.center]?.value ?: 0.0), - standardDeviation = (left[def.center]?.standardDeviation - ?: 0.0) + (right[def.center]?.standardDeviation ?: 0.0) + value = (a[def.center]?.value ?: 0.0) + (b[def.center]?.value ?: 0.0), + standardDeviation = (a[def.center]?.standardDeviation + ?: 0.0) + (b[def.center]?.standardDeviation ?: 0.0) ) ) } diff --git a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt index ac0576a8e..0841fcb4c 100644 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt +++ b/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt @@ -1,14 +1,14 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.histogram import space.kscience.kmath.domains.UnivariateDomain import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.asSequence import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.asSequence @UnstableKMathAPI @@ -34,7 +34,7 @@ public class UnivariateBin( } @OptIn(UnstableKMathAPI::class) -public interface UnivariateHistogram : Histogram { +public interface UnivariateHistogram : Histogram{ public operator fun get(value: Double): UnivariateBin? override operator fun get(point: Buffer): UnivariateBin? = get(point[0]) @@ -42,7 +42,7 @@ public interface UnivariateHistogram : Histogram { /** * Build and fill a [UnivariateHistogram]. Returns a read-only histogram. */ - public inline fun uniform( + public fun uniform( binSize: Double, start: Double = 0.0, builder: UnivariateHistogramBuilder.() -> Unit, @@ -51,7 +51,7 @@ public interface UnivariateHistogram : Histogram { /** * Build and fill a histogram with custom borders. Returns a read-only histogram. */ - public inline fun custom( + public fun custom( borders: DoubleArray, builder: UnivariateHistogramBuilder.() -> Unit, ): UnivariateHistogram = TreeHistogramSpace.custom(borders).fill(builder) diff --git a/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt b/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt index 28a1b03cb..e71602c7b 100644 --- a/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt +++ b/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.histogram diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md index a274b3d88..3c5d4e19d 100644 --- a/kmath-jafama/README.md +++ b/kmath-jafama/README.md @@ -7,17 +7,17 @@ Integration with [Jafama](https://github.com/jeffhain/jafama). ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-20`. +The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-14`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-jafama:0.3.0-dev-20' + implementation 'space.kscience:kmath-jafama:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -28,7 +28,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-jafama:0.3.0-dev-20") + implementation("space.kscience:kmath-jafama:0.3.0-dev-14") } ``` diff --git a/kmath-jafama/build.gradle.kts b/kmath-jafama/build.gradle.kts index 925a2bc60..9cf328d0b 100644 --- a/kmath-jafama/build.gradle.kts +++ b/kmath-jafama/build.gradle.kts @@ -23,5 +23,5 @@ readme { } kotlin.sourceSets.all { - languageSettings.optIn("space.kscience.kmath.misc.UnstableKMathAPI") + languageSettings.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") } diff --git a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt index 91d952a76..1a6e3325b 100644 --- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt +++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.jafama @@ -28,10 +28,10 @@ public object JafamaDoubleField : ExtendedField, Norm, S else -> super.binaryOperationFunction(operation) } - override inline fun add(left: Double, right: Double): Double = left + right + override inline fun add(a: Double, b: Double): Double = a + b - override inline fun multiply(left: Double, right: Double): Double = left * right - override inline fun divide(left: Double, right: Double): Double = left / right + override inline fun multiply(a: Double, b: Double): Double = a * b + override inline fun divide(a: Double, b: Double): Double = a / b override inline fun scale(a: Double, value: Double): Double = a * value @@ -57,10 +57,10 @@ public object JafamaDoubleField : ExtendedField, Norm, S override inline fun norm(arg: Double): Double = FastMath.abs(arg) override inline fun Double.unaryMinus(): Double = -this - override inline fun Double.plus(arg: Double): Double = this + arg - override inline fun Double.minus(arg: Double): Double = this - arg - override inline fun Double.times(arg: Double): Double = this * arg - override inline fun Double.div(arg: Double): Double = this / arg + override inline fun Double.plus(b: Double): Double = this + b + override inline fun Double.minus(b: Double): Double = this - b + override inline fun Double.times(b: Double): Double = this * b + override inline fun Double.div(b: Double): Double = this / b } /** @@ -79,10 +79,10 @@ public object StrictJafamaDoubleField : ExtendedField, Norm super.binaryOperationFunction(operation) } - override inline fun add(left: Double, right: Double): Double = left + right + override inline fun add(a: Double, b: Double): Double = a + b - override inline fun multiply(left: Double, right: Double): Double = left * right - override inline fun divide(left: Double, right: Double): Double = left / right + override inline fun multiply(a: Double, b: Double): Double = a * b + override inline fun divide(a: Double, b: Double): Double = a / b override inline fun scale(a: Double, value: Double): Double = a * value @@ -108,8 +108,8 @@ public object StrictJafamaDoubleField : ExtendedField, Norm>( ) : SpecialDifferentiableExpression> { override fun invoke(arguments: Map): T = mst.interpret(algebra, arguments) - override fun derivativeOrNull( - symbols: List, - ): KotlingradExpression = KotlingradExpression( - algebra, - symbols.map(Symbol::identity) - .map(MstNumericAlgebra::bindSymbol) - .map>>(Symbol::toSVar) - .fold(mst.toSFun(), SFun>::d) - .toMst(), - ) -} - -/** - * A diff processor using [MST] to Kotlingrad converter - */ -public class KotlingradProcessor>( - public val algebra: A, -) : AutoDiffProcessor { - override fun differentiate(function: MstExtendedField.() -> MST): DifferentiableExpression = - MstExtendedField.function().toKotlingradExpression(algebra) + override fun derivativeOrNull(symbols: List): KotlingradExpression = + KotlingradExpression( + algebra, + symbols.map(Symbol::identity) + .map(MstNumericAlgebra::bindSymbol) + .map>>(Symbol::toSVar) + .fold(mst.toSFun(), SFun>::d) + .toMst(), + ) } /** diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt index 37ce40cab..857824275 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt @@ -1,11 +1,11 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.kotlingrad -import ai.hypergraph.kotlingrad.api.* +import edu.umontreal.kotlingrad.api.* import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.MstExtendedField import space.kscience.kmath.expressions.MstExtendedField.unaryMinus @@ -106,8 +106,8 @@ public fun > MST.toSFun(): SFun = when (this) { is Symbol -> toSVar() is MST.Unary -> when (operation) { - GroupOps.PLUS_OPERATION -> +value.toSFun() - GroupOps.MINUS_OPERATION -> -value.toSFun() + GroupOperations.PLUS_OPERATION -> +value.toSFun() + GroupOperations.MINUS_OPERATION -> -value.toSFun() TrigonometricOperations.SIN_OPERATION -> sin(value.toSFun()) TrigonometricOperations.COS_OPERATION -> cos(value.toSFun()) TrigonometricOperations.TAN_OPERATION -> tan(value.toSFun()) @@ -124,10 +124,10 @@ public fun > MST.toSFun(): SFun = when (this) { } is MST.Binary -> when (operation) { - GroupOps.PLUS_OPERATION -> left.toSFun() + right.toSFun() - GroupOps.MINUS_OPERATION -> left.toSFun() - right.toSFun() - RingOps.TIMES_OPERATION -> left.toSFun() * right.toSFun() - FieldOps.DIV_OPERATION -> left.toSFun() / right.toSFun() + GroupOperations.PLUS_OPERATION -> left.toSFun() + right.toSFun() + GroupOperations.MINUS_OPERATION -> left.toSFun() - right.toSFun() + RingOperations.TIMES_OPERATION -> left.toSFun() * right.toSFun() + FieldOperations.DIV_OPERATION -> left.toSFun() / right.toSFun() PowerOperations.POW_OPERATION -> left.toSFun() pow (right as MST.Numeric).toSConst() else -> error("Binary operation $operation not defined in $this") } diff --git a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt index 570d7dd7f..67332a680 100644 --- a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt +++ b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt @@ -1,11 +1,11 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.kotlingrad -import ai.hypergraph.kotlingrad.api.* +import edu.umontreal.kotlingrad.api.* import space.kscience.kmath.asm.compileToExpression import space.kscience.kmath.ast.parseMath import space.kscience.kmath.expressions.MstNumericAlgebra @@ -22,7 +22,7 @@ internal class AdaptingTests { fun symbol() { assertEquals(x.identity, x.toSVar>().name) val c2 = "kitten".parseMath().toSFun>() - if (c2 is SVar<*>) assertTrue(c2.name == "kitten") else fail() + if (c2 is SVar) assertTrue(c2.name == "kitten") else fail() } @Test @@ -30,17 +30,17 @@ internal class AdaptingTests { val c1 = MstNumericAlgebra.number(12354324) assertTrue(c1.toSConst().doubleValue == 12354324.0) val c2 = "0.234".parseMath().toSFun>() - if (c2 is SConst<*>) assertTrue(c2.doubleValue == 0.234) else fail() + if (c2 is SConst) assertTrue(c2.doubleValue == 0.234) else fail() val c3 = "1e-3".parseMath().toSFun>() - if (c3 is SConst<*>) assertEquals(0.001, c3.value) else fail() + if (c3 is SConst) assertEquals(0.001, c3.value) else fail() } @Test fun simpleFunctionShape() { val linear = "2*x+16".parseMath().toSFun>() - if (linear !is Sum<*>) fail() - if (linear.left !is Prod<*>) fail() - if (linear.right !is SConst<*>) fail() + if (linear !is Sum) fail() + if (linear.left !is Prod) fail() + if (linear.right !is SConst) fail() } @Test @@ -62,6 +62,6 @@ internal class AdaptingTests { .parseMath() .compileToExpression(DoubleField) - assertEquals(actualDerivative(x to -0.1), expectedDerivative(x to -0.1)) + assertEquals(actualDerivative(x to 0.1), expectedDerivative(x to 0.1)) } } diff --git a/kmath-memory/README.md b/kmath-memory/README.md deleted file mode 100644 index d37087a66..000000000 --- a/kmath-memory/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-memory - - - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-memory:0.3.0-dev-20`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-memory:0.3.0-dev-20' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-memory:0.3.0-dev-20") -} -``` diff --git a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt index e8e51e9e2..9f73ae2f3 100644 --- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt +++ b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.memory diff --git a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt index 1ee1cf4e2..2f2af4d9c 100644 --- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt +++ b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.memory diff --git a/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt b/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt index 6153743fc..db5eb556e 100644 --- a/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt +++ b/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.memory diff --git a/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt b/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt index aef68fd80..6e60514f8 100644 --- a/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt +++ b/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.memory diff --git a/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt b/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt index 5146d9689..d13da1191 100644 --- a/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt +++ b/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.memory diff --git a/kmath-multik/README.md b/kmath-multik/README.md deleted file mode 100644 index 167445f52..000000000 --- a/kmath-multik/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-multik - -JetBrains Multik connector - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-multik:0.3.0-dev-20`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-multik:0.3.0-dev-20' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-multik:0.3.0-dev-20") -} -``` diff --git a/kmath-multik/build.gradle.kts b/kmath-multik/build.gradle.kts deleted file mode 100644 index df2292f2e..000000000 --- a/kmath-multik/build.gradle.kts +++ /dev/null @@ -1,14 +0,0 @@ -plugins { - id("ru.mipt.npm.gradle.jvm") -} - -description = "JetBrains Multik connector" - -dependencies { - api(project(":kmath-tensors")) - api("org.jetbrains.kotlinx:multik-default:0.1.0") -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE -} \ No newline at end of file diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt deleted file mode 100644 index 1dc318517..000000000 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikDoubleAlgebra.kt +++ /dev/null @@ -1,54 +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.multik - -import org.jetbrains.kotlinx.multik.ndarray.data.DataType -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.ExponentialOperations -import space.kscience.kmath.operations.TrigonometricOperations - -public object MultikDoubleAlgebra : MultikDivisionTensorAlgebra(), - TrigonometricOperations>, ExponentialOperations> { - override val elementAlgebra: DoubleField get() = DoubleField - override val type: DataType get() = DataType.DoubleDataType - - override fun sin(arg: StructureND): MultikTensor = multikMath.mathEx.sin(arg.asMultik().array).wrap() - - override fun cos(arg: StructureND): MultikTensor = multikMath.mathEx.cos(arg.asMultik().array).wrap() - - override fun tan(arg: StructureND): MultikTensor = sin(arg) / cos(arg) - - override fun asin(arg: StructureND): MultikTensor = arg.map { asin(it) } - - override fun acos(arg: StructureND): MultikTensor = arg.map { acos(it) } - - override fun atan(arg: StructureND): MultikTensor = arg.map { atan(it) } - - override fun exp(arg: StructureND): MultikTensor = multikMath.mathEx.exp(arg.asMultik().array).wrap() - - override fun ln(arg: StructureND): MultikTensor = multikMath.mathEx.log(arg.asMultik().array).wrap() - - override fun sinh(arg: StructureND): MultikTensor = (exp(arg) - exp(-arg)) / 2.0 - - override fun cosh(arg: StructureND): MultikTensor = (exp(arg) + exp(-arg)) / 2.0 - - override fun tanh(arg: StructureND): MultikTensor { - val expPlus = exp(arg) - val expMinus = exp(-arg) - return (expPlus - expMinus) / (expPlus + expMinus) - } - - override fun asinh(arg: StructureND): MultikTensor = arg.map { asinh(it) } - - override fun acosh(arg: StructureND): MultikTensor = arg.map { acosh(it) } - - override fun atanh(arg: StructureND): MultikTensor = arg.map { atanh(it) } -} - -public val Double.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra -public val DoubleField.multikAlgebra: MultikTensorAlgebra get() = MultikDoubleAlgebra - diff --git a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt b/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt deleted file mode 100644 index 250ef7e7f..000000000 --- a/kmath-multik/src/main/kotlin/space/kscience/kmath/multik/MultikTensorAlgebra.kt +++ /dev/null @@ -1,343 +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. - */ - -@file:Suppress("unused") - -package space.kscience.kmath.multik - -import org.jetbrains.kotlinx.multik.api.* -import org.jetbrains.kotlinx.multik.api.linalg.LinAlg -import org.jetbrains.kotlinx.multik.api.math.Math -import org.jetbrains.kotlinx.multik.ndarray.data.* -import org.jetbrains.kotlinx.multik.ndarray.operations.* -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.DefaultStrides -import space.kscience.kmath.nd.Shape -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.mapInPlace -import space.kscience.kmath.operations.* -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.api.TensorAlgebra -import space.kscience.kmath.tensors.api.TensorPartialDivisionAlgebra - -@JvmInline -public value class MultikTensor(public val array: MutableMultiArray) : Tensor { - override val shape: Shape get() = array.shape - - override fun get(index: IntArray): T = array[index] - - @PerformancePitfall - override fun elements(): Sequence> = - array.multiIndices.iterator().asSequence().map { it to get(it) } - - override fun set(index: IntArray, value: T) { - array[index] = value - } -} - -private fun MultiArray.asD1Array(): D1Array { - if (this is NDArray) - return this.asD1Array() - else throw ClassCastException("Cannot cast MultiArray to NDArray.") -} - - -private fun MultiArray.asD2Array(): D2Array { - if (this is NDArray) - return this.asD2Array() - else throw ClassCastException("Cannot cast MultiArray to NDArray.") -} - -public abstract class MultikTensorAlgebra> : TensorAlgebra - where T : Number, T : Comparable { - - public abstract val type: DataType - - protected val multikMath: Math = mk.math - protected val multikLinAl: LinAlg = mk.linalg - protected val multikStat: Statistics = mk.stat - - - override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): MultikTensor { - val strides = DefaultStrides(shape) - val memoryView = initMemoryView(strides.linearSize, type) - strides.asSequence().forEachIndexed { linearIndex, tensorIndex -> - memoryView[linearIndex] = elementAlgebra.initializer(tensorIndex) - } - return MultikTensor(NDArray(memoryView, shape = shape, dim = DN(shape.size))) - } - - @OptIn(PerformancePitfall::class) - override fun StructureND.map(transform: A.(T) -> T): MultikTensor = if (this is MultikTensor) { - val data = initMemoryView(array.size, type) - var count = 0 - for (el in array) data[count++] = elementAlgebra.transform(el) - NDArray(data, shape = shape, dim = array.dim).wrap() - } else { - structureND(shape) { index -> - transform(get(index)) - } - } - - @OptIn(PerformancePitfall::class) - override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): MultikTensor = - if (this is MultikTensor) { - val array = asMultik().array - val data = initMemoryView(array.size, type) - val indexIter = array.multiIndices.iterator() - var index = 0 - for (item in array) { - if (indexIter.hasNext()) { - data[index++] = elementAlgebra.transform(indexIter.next(), item) - } else { - throw ArithmeticException("Index overflow has happened.") - } - } - NDArray(data, shape = array.shape, dim = array.dim).wrap() - } else { - structureND(shape) { index -> - transform(index, get(index)) - } - } - - @OptIn(PerformancePitfall::class) - override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): MultikTensor { - require(left.shape.contentEquals(right.shape)) { "ND array shape mismatch" } //TODO replace by ShapeMismatchException - val leftArray = left.asMultik().array - val rightArray = right.asMultik().array - val data = initMemoryView(leftArray.size, type) - var counter = 0 - val leftIterator = leftArray.iterator() - val rightIterator = rightArray.iterator() - //iterating them together - while (leftIterator.hasNext()) { - data[counter++] = elementAlgebra.transform(leftIterator.next(), rightIterator.next()) - } - return NDArray(data, shape = leftArray.shape, dim = leftArray.dim).wrap() - } - - /** - * Convert a tensor to [MultikTensor] if necessary. If tensor is converted, changes on the resulting tensor - * are not reflected back onto the source - */ - public fun StructureND.asMultik(): MultikTensor = if (this is MultikTensor) { - this - } else { - val res = mk.zeros(shape, type).asDNArray() - for (index in res.multiIndices) { - res[index] = this[index] - } - res.wrap() - } - - public fun MutableMultiArray.wrap(): MultikTensor = MultikTensor(this.asDNArray()) - - override fun StructureND.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) { - get(intArrayOf(0)) - } else null - - override fun T.plus(arg: StructureND): MultikTensor = - arg.plus(this) - - override fun StructureND.plus(arg: T): MultikTensor = - asMultik().array.deepCopy().apply { plusAssign(arg) }.wrap() - - override fun StructureND.plus(arg: StructureND): MultikTensor = - asMultik().array.plus(arg.asMultik().array).wrap() - - override fun Tensor.plusAssign(value: T) { - if (this is MultikTensor) { - array.plusAssign(value) - } else { - mapInPlace { _, t -> elementAlgebra.add(t, value) } - } - } - - override fun Tensor.plusAssign(arg: StructureND) { - if (this is MultikTensor) { - array.plusAssign(arg.asMultik().array) - } else { - mapInPlace { index, t -> elementAlgebra.add(t, arg[index]) } - } - } - - override fun T.minus(arg: StructureND): MultikTensor = (-(arg.asMultik().array - this)).wrap() - - override fun StructureND.minus(arg: T): MultikTensor = - asMultik().array.deepCopy().apply { minusAssign(arg) }.wrap() - - override fun StructureND.minus(arg: StructureND): MultikTensor = - asMultik().array.minus(arg.asMultik().array).wrap() - - override fun Tensor.minusAssign(value: T) { - if (this is MultikTensor) { - array.minusAssign(value) - } else { - mapInPlace { _, t -> elementAlgebra.run { t - value } } - } - } - - override fun Tensor.minusAssign(arg: StructureND) { - if (this is MultikTensor) { - array.minusAssign(arg.asMultik().array) - } else { - mapInPlace { index, t -> elementAlgebra.run { t - arg[index] } } - } - } - - override fun T.times(arg: StructureND): MultikTensor = - arg.asMultik().array.deepCopy().apply { timesAssign(this@times) }.wrap() - - override fun StructureND.times(arg: T): Tensor = - asMultik().array.deepCopy().apply { timesAssign(arg) }.wrap() - - override fun StructureND.times(arg: StructureND): MultikTensor = - asMultik().array.times(arg.asMultik().array).wrap() - - override fun Tensor.timesAssign(value: T) { - if (this is MultikTensor) { - array.timesAssign(value) - } else { - mapInPlace { _, t -> elementAlgebra.multiply(t, value) } - } - } - - override fun Tensor.timesAssign(arg: StructureND) { - if (this is MultikTensor) { - array.timesAssign(arg.asMultik().array) - } else { - mapInPlace { index, t -> elementAlgebra.multiply(t, arg[index]) } - } - } - - override fun StructureND.unaryMinus(): MultikTensor = - asMultik().array.unaryMinus().wrap() - - override fun Tensor.get(i: Int): MultikTensor = asMultik().array.mutableView(i).wrap() - - override fun Tensor.transpose(i: Int, j: Int): MultikTensor = asMultik().array.transpose(i, j).wrap() - - override fun Tensor.view(shape: IntArray): MultikTensor { - require(shape.all { it > 0 }) - require(shape.fold(1, Int::times) == this.shape.size) { - "Cannot reshape array of size ${this.shape.size} into a new shape ${ - shape.joinToString( - prefix = "(", - postfix = ")" - ) - }" - } - - val mt = asMultik().array - return if (mt.shape.contentEquals(shape)) { - mt - } else { - NDArray(mt.data, mt.offset, shape, dim = DN(shape.size), base = mt.base ?: mt) - }.wrap() - } - - override fun Tensor.viewAs(other: StructureND): MultikTensor = view(other.shape) - - override fun StructureND.dot(other: StructureND): MultikTensor = - if (this.shape.size == 1 && other.shape.size == 1) { - Multik.ndarrayOf( - multikLinAl.linAlgEx.dotVV(asMultik().array.asD1Array(), other.asMultik().array.asD1Array()) - ).wrap() - } else if (this.shape.size == 2 && other.shape.size == 2) { - multikLinAl.linAlgEx.dotMM(asMultik().array.asD2Array(), other.asMultik().array.asD2Array()).wrap() - } else if (this.shape.size == 2 && other.shape.size == 1) { - multikLinAl.linAlgEx.dotMV(asMultik().array.asD2Array(), other.asMultik().array.asD1Array()).wrap() - } else { - TODO("Not implemented for broadcasting") - } - - override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): MultikTensor { - TODO("Diagonal embedding not implemented") - } - - override fun StructureND.sum(): T = asMultik().array.reduceMultiIndexed { _: IntArray, acc: T, t: T -> - elementAlgebra.add(acc, t) - } - - override fun StructureND.sum(dim: Int, keepDim: Boolean): MultikTensor { - TODO("Not yet implemented") - } - - override fun StructureND.min(): T? = asMultik().array.min() - - override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.max(): T? = asMultik().array.max() - - override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") - } - - override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor { - TODO("Not yet implemented") - } -} - -public abstract class MultikDivisionTensorAlgebra> - : MultikTensorAlgebra(), TensorPartialDivisionAlgebra where T : Number, T : Comparable { - - override fun T.div(arg: StructureND): MultikTensor = arg.map { elementAlgebra.divide(this@div, it) } - - override fun StructureND.div(arg: T): MultikTensor = - asMultik().array.deepCopy().apply { divAssign(arg) }.wrap() - - override fun StructureND.div(arg: StructureND): MultikTensor = - asMultik().array.div(arg.asMultik().array).wrap() - - override fun Tensor.divAssign(value: T) { - if (this is MultikTensor) { - array.divAssign(value) - } else { - mapInPlace { _, t -> elementAlgebra.divide(t, value) } - } - } - - override fun Tensor.divAssign(arg: StructureND) { - if (this is MultikTensor) { - array.divAssign(arg.asMultik().array) - } else { - mapInPlace { index, t -> elementAlgebra.divide(t, arg[index]) } - } - } -} - -public object MultikFloatAlgebra : MultikDivisionTensorAlgebra() { - override val elementAlgebra: FloatField get() = FloatField - override val type: DataType get() = DataType.FloatDataType -} - -public val Float.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikFloatAlgebra -public val FloatField.multikAlgebra: MultikTensorAlgebra get() = MultikFloatAlgebra - -public object MultikShortAlgebra : MultikTensorAlgebra() { - override val elementAlgebra: ShortRing get() = ShortRing - override val type: DataType get() = DataType.ShortDataType -} - -public val Short.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikShortAlgebra -public val ShortRing.multikAlgebra: MultikTensorAlgebra get() = MultikShortAlgebra - -public object MultikIntAlgebra : MultikTensorAlgebra() { - override val elementAlgebra: IntRing get() = IntRing - override val type: DataType get() = DataType.IntDataType -} - -public val Int.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikIntAlgebra -public val IntRing.multikAlgebra: MultikTensorAlgebra get() = MultikIntAlgebra - -public object MultikLongAlgebra : MultikTensorAlgebra() { - override val elementAlgebra: LongRing get() = LongRing - override val type: DataType get() = DataType.LongDataType -} - -public val Long.Companion.multikAlgebra: MultikTensorAlgebra get() = MultikLongAlgebra -public val LongRing.multikAlgebra: MultikTensorAlgebra get() = MultikLongAlgebra \ No newline at end of file diff --git a/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt b/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt deleted file mode 100644 index 72c43d8e6..000000000 --- a/kmath-multik/src/test/kotlin/space/kscience/kmath/multik/MultikNDTest.kt +++ /dev/null @@ -1,43 +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.multik - -import org.junit.jupiter.api.Test -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.one -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.tensorAlgebra -import kotlin.test.assertTrue - -internal class MultikNDTest { - @Test - fun basicAlgebra(): Unit = DoubleField.multikAlgebra{ - one(2,2) + 1.0 - } - - @Test - fun dotResult(){ - val dim = 100 - - val tensor1 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12224) - val tensor2 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12225) - - val multikResult = with(DoubleField.multikAlgebra){ - tensor1 dot tensor2 - } - - val defaultResult = with(DoubleField.tensorAlgebra){ - tensor1 dot tensor2 - } - - assertTrue { - StructureND.contentEquals(multikResult, defaultResult) - } - - } -} \ No newline at end of file diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index 225de18e9..5cbb31d5a 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -9,17 +9,17 @@ ND4J based implementations of KMath abstractions. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-20`. +The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-14`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-nd4j:0.3.0-dev-20' + implementation 'space.kscience:kmath-nd4j:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -30,7 +30,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-nd4j:0.3.0-dev-20") + implementation("space.kscience:kmath-nd4j:0.3.0-dev-14") } ``` diff --git a/kmath-nd4j/build.gradle.kts b/kmath-nd4j/build.gradle.kts index 09264501f..dcb6f1b4a 100644 --- a/kmath-nd4j/build.gradle.kts +++ b/kmath-nd4j/build.gradle.kts @@ -9,7 +9,7 @@ dependencies { api(project(":kmath-tensors")) api("org.nd4j:nd4j-api:1.0.0-M1") testImplementation("org.nd4j:nd4j-native-platform:1.0.0-M1") - testImplementation("org.slf4j:slf4j-simple:1.7.32") + testImplementation("org.slf4j:slf4j-simple:1.7.31") } readme { diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt index e29a3f467..54df31556 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.nd4j @@ -15,6 +15,13 @@ import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.nd.* import space.kscience.kmath.operations.* +internal fun AlgebraND<*, *>.checkShape(array: INDArray): INDArray { + val arrayShape = array.shape().toIntArray() + if (!shape.contentEquals(arrayShape)) throw ShapeMismatchException(shape, arrayShape) + return array +} + + /** * Represents [AlgebraND] over [Nd4jArrayAlgebra]. * @@ -32,35 +39,34 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND.ndArray: INDArray - override fun structureND(shape: Shape, initializer: C.(IntArray) -> T): Nd4jArrayStructure { + override fun produce(initializer: C.(IntArray) -> T): Nd4jArrayStructure { val struct = Nd4j.create(*shape)!!.wrap() - struct.indicesIterator().forEach { struct[it] = elementAlgebra.initializer(it) } + struct.indicesIterator().forEach { struct[it] = elementContext.initializer(it) } return struct } - @OptIn(PerformancePitfall::class) + @PerformancePitfall override fun StructureND.map(transform: C.(T) -> T): Nd4jArrayStructure { val newStruct = ndArray.dup().wrap() - newStruct.elements().forEach { (idx, value) -> newStruct[idx] = elementAlgebra.transform(value) } + newStruct.elements().forEach { (idx, value) -> newStruct[idx] = elementContext.transform(value) } return newStruct } override fun StructureND.mapIndexed( transform: C.(index: IntArray, T) -> T, ): Nd4jArrayStructure { - val new = Nd4j.create(*shape).wrap() - new.indicesIterator().forEach { idx -> new[idx] = elementAlgebra.transform(idx, this[idx]) } + val new = Nd4j.create(*this@Nd4jArrayAlgebra.shape).wrap() + new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(idx, this[idx]) } return new } - override fun zip( - left: StructureND, - right: StructureND, + override fun combine( + a: StructureND, + b: StructureND, transform: C.(T, T) -> T, ): Nd4jArrayStructure { - require(left.shape.contentEquals(right.shape)) { "Can't zip tow structures of shape ${left.shape} and ${right.shape}" } - val new = Nd4j.create(*left.shape).wrap() - new.indicesIterator().forEach { idx -> new[idx] = elementAlgebra.transform(left[idx], right[idx]) } + val new = Nd4j.create(*shape).wrap() + new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(a[idx], b[idx]) } return new } } @@ -71,13 +77,16 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND> : GroupOpsND, Nd4jArrayAlgebra { +public sealed interface Nd4jArrayGroup> : GroupND, Nd4jArrayAlgebra { - override fun add(left: StructureND, right: StructureND): Nd4jArrayStructure = - left.ndArray.add(right.ndArray).wrap() + override val zero: Nd4jArrayStructure + get() = Nd4j.zeros(*shape).wrap() - override operator fun StructureND.minus(arg: StructureND): Nd4jArrayStructure = - ndArray.sub(arg.ndArray).wrap() + override fun add(a: StructureND, b: StructureND): Nd4jArrayStructure = + a.ndArray.add(b.ndArray).wrap() + + override operator fun StructureND.minus(b: StructureND): Nd4jArrayStructure = + ndArray.sub(b.ndArray).wrap() override operator fun StructureND.unaryMinus(): Nd4jArrayStructure = ndArray.neg().wrap() @@ -93,10 +102,13 @@ public sealed interface Nd4jArrayGroupOps> : GroupOpsND * @param R the type of ring of structure elements. */ @OptIn(UnstableKMathAPI::class) -public sealed interface Nd4jArrayRingOps> : RingOpsND, Nd4jArrayGroupOps { +public sealed interface Nd4jArrayRing> : RingND, Nd4jArrayGroup { - override fun multiply(left: StructureND, right: StructureND): Nd4jArrayStructure = - left.ndArray.mul(right.ndArray).wrap() + override val one: Nd4jArrayStructure + get() = Nd4j.ones(*shape).wrap() + + override fun multiply(a: StructureND, b: StructureND): Nd4jArrayStructure = + a.ndArray.mul(b.ndArray).wrap() // // override operator fun Nd4jArrayStructure.minus(b: Number): Nd4jArrayStructure { // check(this) @@ -114,12 +126,21 @@ public sealed interface Nd4jArrayRingOps> : RingOpsND, // } public companion object { + private val intNd4jArrayRingCache: ThreadLocal> = + ThreadLocal.withInitial(::HashMap) + + /** + * Creates an [RingND] for [Int] values or pull it from cache if it was created previously. + */ + public fun int(vararg shape: Int): Nd4jArrayRing = + intNd4jArrayRingCache.get().getOrPut(shape) { IntNd4jArrayRing(shape) } + /** * Creates a most suitable implementation of [RingND] using reified class. */ @Suppress("UNCHECKED_CAST") - public inline fun auto(): Nd4jArrayRingOps> = when { - T::class == Int::class -> IntRing.nd4j as Nd4jArrayRingOps> + public inline fun auto(vararg shape: Int): Nd4jArrayRing> = when { + T::class == Int::class -> int(*shape) as Nd4jArrayRing> else -> throw UnsupportedOperationException("This factory method only supports Long type.") } } @@ -131,21 +152,38 @@ public sealed interface Nd4jArrayRingOps> : RingOpsND, * @param T the type of the element contained in ND structure. * @param F the type field of structure elements. */ -public sealed interface Nd4jArrayField> : FieldOpsND, Nd4jArrayRingOps { - - override fun divide(left: StructureND, right: StructureND): Nd4jArrayStructure = - left.ndArray.div(right.ndArray).wrap() +public sealed interface Nd4jArrayField> : FieldND, Nd4jArrayRing { + override fun divide(a: StructureND, b: StructureND): Nd4jArrayStructure = + a.ndArray.div(b.ndArray).wrap() public operator fun Number.div(b: StructureND): Nd4jArrayStructure = b.ndArray.rdiv(this).wrap() public companion object { + private val floatNd4jArrayFieldCache: ThreadLocal> = + ThreadLocal.withInitial(::HashMap) + + private val doubleNd4JArrayFieldCache: ThreadLocal> = + ThreadLocal.withInitial(::HashMap) + + /** + * Creates an [FieldND] for [Float] values or pull it from cache if it was created previously. + */ + public fun float(vararg shape: Int): Nd4jArrayRing = + floatNd4jArrayFieldCache.get().getOrPut(shape) { FloatNd4jArrayField(shape) } + + /** + * Creates an [FieldND] for [Double] values or pull it from cache if it was created previously. + */ + public fun real(vararg shape: Int): Nd4jArrayRing = + doubleNd4JArrayFieldCache.get().getOrPut(shape) { DoubleNd4jArrayField(shape) } + /** * Creates a most suitable implementation of [FieldND] using reified class. */ @Suppress("UNCHECKED_CAST") - public inline fun auto(): Nd4jArrayField> = when { - T::class == Float::class -> FloatField.nd4j as Nd4jArrayField> - T::class == Double::class -> DoubleField.nd4j as Nd4jArrayField> + public inline fun auto(vararg shape: Int): Nd4jArrayField> = when { + T::class == Float::class -> float(*shape) as Nd4jArrayField> + T::class == Double::class -> real(*shape) as Nd4jArrayField> else -> throw UnsupportedOperationException("This factory method only supports Float and Double types.") } } @@ -154,9 +192,8 @@ public sealed interface Nd4jArrayField> : FieldOpsND, /** * Represents intersection of [ExtendedField] and [Field] over [Nd4jArrayStructure]. */ -public sealed interface Nd4jArrayExtendedFieldOps> : - ExtendedFieldOps>, Nd4jArrayField, PowerOperations> { - +public sealed interface Nd4jArrayExtendedField> : ExtendedField>, + Nd4jArrayField { override fun sin(arg: StructureND): StructureND = Transforms.sin(arg.ndArray).wrap() override fun cos(arg: StructureND): StructureND = Transforms.cos(arg.ndArray).wrap() override fun asin(arg: StructureND): StructureND = Transforms.asin(arg.ndArray).wrap() @@ -185,59 +222,61 @@ public sealed interface Nd4jArrayExtendedFieldOps> : /** * Represents [FieldND] over [Nd4jArrayDoubleStructure]. */ -public open class DoubleNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps { - override val elementAlgebra: DoubleField get() = DoubleField +public class DoubleNd4jArrayField(override val shape: IntArray) : Nd4jArrayExtendedField { + override val elementContext: DoubleField get() = DoubleField - override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asDoubleStructure() @OptIn(PerformancePitfall::class) override val StructureND.ndArray: INDArray get() = when (this) { - is Nd4jArrayStructure -> ndArray + is Nd4jArrayStructure -> checkShape(ndArray) else -> Nd4j.zeros(*shape).also { elements().forEach { (idx, value) -> it.putScalar(idx, value) } } } - override fun scale(a: StructureND, value: Double): Nd4jArrayStructure = a.ndArray.mul(value).wrap() + override fun scale(a: StructureND, value: Double): Nd4jArrayStructure { + return a.ndArray.mul(value).wrap() + } - override operator fun StructureND.div(arg: Double): Nd4jArrayStructure = ndArray.div(arg).wrap() + override operator fun StructureND.div(arg: Double): Nd4jArrayStructure { + return ndArray.div(arg).wrap() + } - override operator fun StructureND.plus(arg: Double): Nd4jArrayStructure = ndArray.add(arg).wrap() + override operator fun StructureND.plus(arg: Double): Nd4jArrayStructure { + return ndArray.add(arg).wrap() + } - override operator fun StructureND.minus(arg: Double): Nd4jArrayStructure = ndArray.sub(arg).wrap() + override operator fun StructureND.minus(arg: Double): Nd4jArrayStructure { + return ndArray.sub(arg).wrap() + } - override operator fun StructureND.times(arg: Double): Nd4jArrayStructure = ndArray.mul(arg).wrap() + override operator fun StructureND.times(arg: Double): Nd4jArrayStructure { + return ndArray.mul(arg).wrap() + } - override operator fun Double.div(arg: StructureND): Nd4jArrayStructure = - arg.ndArray.rdiv(this).wrap() + override operator fun Double.div(arg: StructureND): Nd4jArrayStructure { + return arg.ndArray.rdiv(this).wrap() + } - override operator fun Double.minus(arg: StructureND): Nd4jArrayStructure = - arg.ndArray.rsub(this).wrap() - - public companion object : DoubleNd4jArrayFieldOps() + override operator fun Double.minus(arg: StructureND): Nd4jArrayStructure { + return arg.ndArray.rsub(this).wrap() + } } -public val DoubleField.nd4j: DoubleNd4jArrayFieldOps get() = DoubleNd4jArrayFieldOps - -public class DoubleNd4jArrayField(override val shape: Shape) : DoubleNd4jArrayFieldOps(), FieldND - -public fun DoubleField.nd4j(shapeFirst: Int, vararg shapeRest: Int): DoubleNd4jArrayField = - DoubleNd4jArrayField(intArrayOf(shapeFirst, * shapeRest)) - - /** * Represents [FieldND] over [Nd4jArrayStructure] of [Float]. */ -public open class FloatNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps { - override val elementAlgebra: FloatField get() = FloatField +public class FloatNd4jArrayField(override val shape: IntArray) : Nd4jArrayExtendedField { + override val elementContext: FloatField get() = FloatField - override fun INDArray.wrap(): Nd4jArrayStructure = asFloatStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asFloatStructure() @OptIn(PerformancePitfall::class) override val StructureND.ndArray: INDArray get() = when (this) { - is Nd4jArrayStructure -> ndArray + is Nd4jArrayStructure -> checkShape(ndArray) else -> Nd4j.zeros(*shape).also { elements().forEach { (idx, value) -> it.putScalar(idx, value) } } @@ -263,29 +302,21 @@ public open class FloatNd4jArrayFieldOps : Nd4jArrayExtendedFieldOps): Nd4jArrayStructure = arg.ndArray.rsub(this).wrap() - - public companion object : FloatNd4jArrayFieldOps() } -public class FloatNd4jArrayField(override val shape: Shape) : FloatNd4jArrayFieldOps(), RingND - -public val FloatField.nd4j: FloatNd4jArrayFieldOps get() = FloatNd4jArrayFieldOps - -public fun FloatField.nd4j(shapeFirst: Int, vararg shapeRest: Int): FloatNd4jArrayField = - FloatNd4jArrayField(intArrayOf(shapeFirst, * shapeRest)) - /** * Represents [RingND] over [Nd4jArrayIntStructure]. */ -public open class IntNd4jArrayRingOps : Nd4jArrayRingOps { - override val elementAlgebra: IntRing get() = IntRing +public class IntNd4jArrayRing(override val shape: IntArray) : Nd4jArrayRing { + override val elementContext: IntRing + get() = IntRing - override fun INDArray.wrap(): Nd4jArrayStructure = asIntStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asIntStructure() @OptIn(PerformancePitfall::class) override val StructureND.ndArray: INDArray get() = when (this) { - is Nd4jArrayStructure -> ndArray + is Nd4jArrayStructure -> checkShape(ndArray) else -> Nd4j.zeros(*shape).also { elements().forEach { (idx, value) -> it.putScalar(idx, value) } } @@ -302,13 +333,4 @@ public open class IntNd4jArrayRingOps : Nd4jArrayRingOps { override operator fun Int.minus(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rsub(this).wrap() - - public companion object : IntNd4jArrayRingOps() } - -public val IntRing.nd4j: IntNd4jArrayRingOps get() = IntNd4jArrayRingOps - -public class IntNd4jArrayRing(override val shape: Shape) : IntNd4jArrayRingOps(), RingND - -public fun IntRing.nd4j(shapeFirst: Int, vararg shapeRest: Int): IntNd4jArrayRing = - IntNd4jArrayRing(intArrayOf(shapeFirst, * shapeRest)) \ No newline at end of file diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt index d4cad8996..5ae6f6b01 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.nd4j diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt index 2a0fdc86c..82f560fdb 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.nd4j diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt index ceb384f0d..0ac37e19b 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.nd4j @@ -13,11 +13,7 @@ import org.nd4j.linalg.factory.Nd4j import org.nd4j.linalg.factory.ops.NDBase import org.nd4j.linalg.ops.transforms.Transforms import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.DefaultStrides -import space.kscience.kmath.nd.Shape import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Field import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.api.TensorAlgebra @@ -26,8 +22,7 @@ import space.kscience.kmath.tensors.core.DoubleTensorAlgebra /** * ND4J based [TensorAlgebra] implementation. */ -public sealed interface Nd4jTensorAlgebra> : AnalyticTensorAlgebra { - +public sealed interface Nd4jTensorAlgebra : AnalyticTensorAlgebra { /** * Wraps [INDArray] to [Nd4jArrayStructure]. */ @@ -38,121 +33,105 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe */ public val StructureND.ndArray: INDArray - override fun structureND(shape: Shape, initializer: A.(IntArray) -> T): Nd4jArrayStructure + override fun T.plus(other: Tensor): Tensor = other.ndArray.add(this).wrap() + override fun Tensor.plus(value: T): Tensor = ndArray.add(value).wrap() - override fun StructureND.map(transform: A.(T) -> T): Nd4jArrayStructure = - structureND(shape) { index -> elementAlgebra.transform(get(index)) } - - override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): Nd4jArrayStructure = - structureND(shape) { index -> elementAlgebra.transform(index, get(index)) } - - override fun zip(left: StructureND, right: StructureND, transform: A.(T, T) -> T): Nd4jArrayStructure { - require(left.shape.contentEquals(right.shape)) - return structureND(left.shape) { index -> elementAlgebra.transform(left[index], right[index]) } - } - - override fun T.plus(arg: StructureND): Nd4jArrayStructure = arg.ndArray.add(this).wrap() - override fun StructureND.plus(arg: T): Nd4jArrayStructure = ndArray.add(arg).wrap() - - override fun StructureND.plus(arg: StructureND): Nd4jArrayStructure = ndArray.add(arg.ndArray).wrap() + override fun Tensor.plus(other: Tensor): Tensor = ndArray.add(other.ndArray).wrap() override fun Tensor.plusAssign(value: T) { ndArray.addi(value) } - override fun Tensor.plusAssign(arg: StructureND) { - ndArray.addi(arg.ndArray) + override fun Tensor.plusAssign(other: Tensor) { + ndArray.addi(other.ndArray) } - override fun T.minus(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rsub(this).wrap() - override fun StructureND.minus(arg: T): Nd4jArrayStructure = ndArray.sub(arg).wrap() - override fun StructureND.minus(arg: StructureND): Nd4jArrayStructure = ndArray.sub(arg.ndArray).wrap() + override fun T.minus(other: Tensor): Tensor = other.ndArray.rsub(this).wrap() + override fun Tensor.minus(value: T): Tensor = ndArray.sub(value).wrap() + override fun Tensor.minus(other: Tensor): Tensor = ndArray.sub(other.ndArray).wrap() override fun Tensor.minusAssign(value: T) { ndArray.rsubi(value) } - override fun Tensor.minusAssign(arg: StructureND) { - ndArray.subi(arg.ndArray) + override fun Tensor.minusAssign(other: Tensor) { + ndArray.subi(other.ndArray) } - override fun T.times(arg: StructureND): Nd4jArrayStructure = arg.ndArray.mul(this).wrap() + override fun T.times(other: Tensor): Tensor = other.ndArray.mul(this).wrap() - override fun StructureND.times(arg: T): Nd4jArrayStructure = - ndArray.mul(arg).wrap() + override fun Tensor.times(value: T): Tensor = + ndArray.mul(value).wrap() - override fun StructureND.times(arg: StructureND): Nd4jArrayStructure = ndArray.mul(arg.ndArray).wrap() + override fun Tensor.times(other: Tensor): Tensor = ndArray.mul(other.ndArray).wrap() override fun Tensor.timesAssign(value: T) { ndArray.muli(value) } - override fun Tensor.timesAssign(arg: StructureND) { - ndArray.mmuli(arg.ndArray) + override fun Tensor.timesAssign(other: Tensor) { + ndArray.mmuli(other.ndArray) } - override fun StructureND.unaryMinus(): Nd4jArrayStructure = ndArray.neg().wrap() - override fun Tensor.get(i: Int): Nd4jArrayStructure = ndArray.slice(i.toLong()).wrap() - override fun Tensor.transpose(i: Int, j: Int): Nd4jArrayStructure = ndArray.swapAxes(i, j).wrap() - override fun StructureND.dot(other: StructureND): Nd4jArrayStructure = ndArray.mmul(other.ndArray).wrap() + override fun Tensor.unaryMinus(): Tensor = ndArray.neg().wrap() + override fun Tensor.get(i: Int): Tensor = ndArray.slice(i.toLong()).wrap() + override fun Tensor.transpose(i: Int, j: Int): Tensor = ndArray.swapAxes(i, j).wrap() + override fun Tensor.dot(other: Tensor): Tensor = ndArray.mmul(other.ndArray).wrap() - override fun StructureND.min(dim: Int, keepDim: Boolean): Nd4jArrayStructure = + override fun Tensor.min(dim: Int, keepDim: Boolean): Tensor = ndArray.min(keepDim, dim).wrap() - override fun StructureND.sum(dim: Int, keepDim: Boolean): Nd4jArrayStructure = + override fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor = ndArray.sum(keepDim, dim).wrap() - override fun StructureND.max(dim: Int, keepDim: Boolean): Nd4jArrayStructure = + override fun Tensor.max(dim: Int, keepDim: Boolean): Tensor = ndArray.max(keepDim, dim).wrap() - override fun Tensor.view(shape: IntArray): Nd4jArrayStructure = ndArray.reshape(shape).wrap() - override fun Tensor.viewAs(other: StructureND): Nd4jArrayStructure = view(other.shape) + override fun Tensor.view(shape: IntArray): Tensor = ndArray.reshape(shape).wrap() + override fun Tensor.viewAs(other: Tensor): Tensor = view(other.shape) - override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor = - ndBase.get().argmax(ndArray, keepDim, dim).asIntStructure() + override fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor = + ndBase.get().argmax(ndArray, keepDim, dim).wrap() - override fun StructureND.mean(dim: Int, keepDim: Boolean): Nd4jArrayStructure = - ndArray.mean(keepDim, dim).wrap() + override fun Tensor.mean(dim: Int, keepDim: Boolean): Tensor = ndArray.mean(keepDim, dim).wrap() - override fun StructureND.exp(): Nd4jArrayStructure = Transforms.exp(ndArray).wrap() - override fun StructureND.ln(): Nd4jArrayStructure = Transforms.log(ndArray).wrap() - override fun StructureND.sqrt(): Nd4jArrayStructure = Transforms.sqrt(ndArray).wrap() - override fun StructureND.cos(): Nd4jArrayStructure = Transforms.cos(ndArray).wrap() - override fun StructureND.acos(): Nd4jArrayStructure = Transforms.acos(ndArray).wrap() - override fun StructureND.cosh(): Nd4jArrayStructure = Transforms.cosh(ndArray).wrap() + override fun Tensor.exp(): Tensor = Transforms.exp(ndArray).wrap() + override fun Tensor.ln(): Tensor = Transforms.log(ndArray).wrap() + override fun Tensor.sqrt(): Tensor = Transforms.sqrt(ndArray).wrap() + override fun Tensor.cos(): Tensor = Transforms.cos(ndArray).wrap() + override fun Tensor.acos(): Tensor = Transforms.acos(ndArray).wrap() + override fun Tensor.cosh(): Tensor = Transforms.cosh(ndArray).wrap() - override fun StructureND.acosh(): Nd4jArrayStructure = + override fun Tensor.acosh(): Tensor = Nd4j.getExecutioner().exec(ACosh(ndArray, ndArray.ulike())).wrap() - override fun StructureND.sin(): Nd4jArrayStructure = Transforms.sin(ndArray).wrap() - override fun StructureND.asin(): Nd4jArrayStructure = Transforms.asin(ndArray).wrap() - override fun StructureND.sinh(): Tensor = Transforms.sinh(ndArray).wrap() + override fun Tensor.sin(): Tensor = Transforms.sin(ndArray).wrap() + override fun Tensor.asin(): Tensor = Transforms.asin(ndArray).wrap() + override fun Tensor.sinh(): Tensor = Transforms.sinh(ndArray).wrap() - override fun StructureND.asinh(): Nd4jArrayStructure = + override fun Tensor.asinh(): Tensor = Nd4j.getExecutioner().exec(ASinh(ndArray, ndArray.ulike())).wrap() - override fun StructureND.tan(): Nd4jArrayStructure = Transforms.tan(ndArray).wrap() - override fun StructureND.atan(): Nd4jArrayStructure = Transforms.atan(ndArray).wrap() - override fun StructureND.tanh(): Nd4jArrayStructure = Transforms.tanh(ndArray).wrap() - override fun StructureND.atanh(): Nd4jArrayStructure = Transforms.atanh(ndArray).wrap() - override fun StructureND.ceil(): Nd4jArrayStructure = Transforms.ceil(ndArray).wrap() - override fun StructureND.floor(): Nd4jArrayStructure = Transforms.floor(ndArray).wrap() - override fun StructureND.std(dim: Int, keepDim: Boolean): Nd4jArrayStructure = - ndArray.std(true, keepDim, dim).wrap() - - override fun T.div(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rdiv(this).wrap() - override fun StructureND.div(arg: T): Nd4jArrayStructure = ndArray.div(arg).wrap() - override fun StructureND.div(arg: StructureND): Nd4jArrayStructure = ndArray.div(arg.ndArray).wrap() + override fun Tensor.tan(): Tensor = Transforms.tan(ndArray).wrap() + override fun Tensor.atan(): Tensor = Transforms.atan(ndArray).wrap() + override fun Tensor.tanh(): Tensor = Transforms.tanh(ndArray).wrap() + override fun Tensor.atanh(): Tensor = Transforms.atanh(ndArray).wrap() + override fun Tensor.ceil(): Tensor = Transforms.ceil(ndArray).wrap() + override fun Tensor.floor(): Tensor = Transforms.floor(ndArray).wrap() + override fun Tensor.std(dim: Int, keepDim: Boolean): Tensor = ndArray.std(true, keepDim, dim).wrap() + override fun T.div(other: Tensor): Tensor = other.ndArray.rdiv(this).wrap() + override fun Tensor.div(value: T): Tensor = ndArray.div(value).wrap() + override fun Tensor.div(other: Tensor): Tensor = ndArray.div(other.ndArray).wrap() override fun Tensor.divAssign(value: T) { ndArray.divi(value) } - override fun Tensor.divAssign(arg: StructureND) { - ndArray.divi(arg.ndArray) + override fun Tensor.divAssign(other: Tensor) { + ndArray.divi(other.ndArray) } - override fun StructureND.variance(dim: Int, keepDim: Boolean): Nd4jArrayStructure = + override fun Tensor.variance(dim: Int, keepDim: Boolean): Tensor = Nd4j.getExecutioner().exec(Variance(ndArray, true, true, dim)).wrap() private companion object { @@ -163,22 +142,9 @@ public sealed interface Nd4jTensorAlgebra> : AnalyticTe /** * [Double] specialization of [Nd4jTensorAlgebra]. */ -public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { - - override val elementAlgebra: DoubleField get() = DoubleField - +public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() - override fun structureND(shape: Shape, initializer: DoubleField.(IntArray) -> Double): Nd4jArrayStructure { - val array: INDArray = Nd4j.zeros(*shape) - val indices = DefaultStrides(shape) - indices.asSequence().forEach { index -> - array.putScalar(index, elementAlgebra.initializer(index)) - } - return array.wrap() - } - - @OptIn(PerformancePitfall::class) override val StructureND.ndArray: INDArray get() = when (this) { @@ -188,10 +154,11 @@ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { } } - override fun StructureND.valueOrNull(): Double? = + override fun Tensor.valueOrNull(): Double? = if (shape contentEquals intArrayOf(1)) ndArray.getDouble(0) else null // TODO rewrite + @PerformancePitfall override fun diagonalEmbedding( diagonalEntries: Tensor, offset: Int, @@ -199,10 +166,10 @@ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { dim2: Int, ): Tensor = DoubleTensorAlgebra.diagonalEmbedding(diagonalEntries, offset, dim1, dim2) - override fun StructureND.sum(): Double = ndArray.sumNumber().toDouble() - override fun StructureND.min(): Double = ndArray.minNumber().toDouble() - override fun StructureND.max(): Double = ndArray.maxNumber().toDouble() - override fun StructureND.mean(): Double = ndArray.meanNumber().toDouble() - override fun StructureND.std(): Double = ndArray.stdNumber().toDouble() - override fun StructureND.variance(): Double = ndArray.varNumber().toDouble() + override fun Tensor.sum(): Double = ndArray.sumNumber().toDouble() + override fun Tensor.min(): Double = ndArray.minNumber().toDouble() + override fun Tensor.max(): Double = ndArray.maxNumber().toDouble() + override fun Tensor.mean(): Double = ndArray.meanNumber().toDouble() + override fun Tensor.std(): Double = ndArray.stdNumber().toDouble() + override fun Tensor.variance(): Double = ndArray.varNumber().toDouble() } diff --git a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt index 3ca756600..cc9211b20 100644 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt +++ b/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.nd4j diff --git a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt index 9d30c2027..a03a7269e 100644 --- a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt +++ b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.nd4j @@ -8,10 +8,6 @@ package space.kscience.kmath.nd4j import org.nd4j.linalg.factory.Nd4j import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.one -import space.kscience.kmath.nd.structureND -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.IntRing import space.kscience.kmath.operations.invoke import kotlin.math.PI import kotlin.test.Test @@ -23,7 +19,7 @@ import kotlin.test.fail internal class Nd4jArrayAlgebraTest { @Test fun testProduce() { - val res = DoubleField.nd4j.structureND(2, 2) { it.sum().toDouble() } + val res = with(DoubleNd4jArrayField(intArrayOf(2, 2))) { produce { it.sum().toDouble() } } val expected = (Nd4j.create(2, 2) ?: fail()).asDoubleStructure() expected[intArrayOf(0, 0)] = 0.0 expected[intArrayOf(0, 1)] = 1.0 @@ -34,9 +30,7 @@ internal class Nd4jArrayAlgebraTest { @Test fun testMap() { - val res = IntRing.nd4j { - one(2, 2).map { it + it * 2 } - } + val res = with(IntNd4jArrayRing(intArrayOf(2, 2))) { one.map { it + it * 2 } } val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure() expected[intArrayOf(0, 0)] = 3 expected[intArrayOf(0, 1)] = 3 @@ -47,7 +41,7 @@ internal class Nd4jArrayAlgebraTest { @Test fun testAdd() { - val res = IntRing.nd4j { one(2, 2) + 25 } + val res = with(IntNd4jArrayRing(intArrayOf(2, 2))) { one + 25 } val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure() expected[intArrayOf(0, 0)] = 26 expected[intArrayOf(0, 1)] = 26 @@ -57,10 +51,10 @@ internal class Nd4jArrayAlgebraTest { } @Test - fun testSin() = DoubleField.nd4j{ - val initial = structureND(2, 2) { (i, j) -> if (i == j) PI / 2 else 0.0 } + fun testSin() = DoubleNd4jArrayField(intArrayOf(2, 2)).invoke { + val initial = produce { (i, j) -> if (i == j) PI / 2 else 0.0 } val transformed = sin(initial) - val expected = structureND(2, 2) { (i, j) -> if (i == j) 1.0 else 0.0 } + val expected = produce { (i, j) -> if (i == j) 1.0 else 0.0 } println(transformed) assertTrue { StructureND.contentEquals(transformed, expected) } diff --git a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt index 30d01338f..ff55ad521 100644 --- a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt +++ b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.nd4j diff --git a/kmath-optimization/README.md b/kmath-optimization/README.md deleted file mode 100644 index 137975c90..000000000 --- a/kmath-optimization/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-optimization - - - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-optimization:0.3.0-dev-20`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-optimization:0.3.0-dev-20' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-optimization:0.3.0-dev-20") -} -``` diff --git a/kmath-optimization/build.gradle.kts b/kmath-optimization/build.gradle.kts deleted file mode 100644 index b920b9267..000000000 --- a/kmath-optimization/build.gradle.kts +++ /dev/null @@ -1,24 +0,0 @@ -plugins { - id("ru.mipt.npm.gradle.mpp") - id("ru.mipt.npm.gradle.native") -} - -kscience { - useAtomic() -} - -kotlin.sourceSets { - all { - languageSettings.optIn("space.kscience.kmath.misc.UnstableKMathAPI") - } - - commonMain { - dependencies { - api(project(":kmath-coroutines")) - } - } -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL -} diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt deleted file mode 100644 index 02602b068..000000000 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt +++ /dev/null @@ -1,71 +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.optimization - -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.FeatureSet - -public class OptimizationValue(public val value: T) : OptimizationFeature { - override fun toString(): String = "Value($value)" -} - -public enum class FunctionOptimizationTarget : OptimizationFeature { - MAXIMIZE, - MINIMIZE -} - -public class FunctionOptimization( - override val features: FeatureSet, - public val expression: DifferentiableExpression, -) : OptimizationProblem { - - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as FunctionOptimization<*> - - if (features != other.features) return false - if (expression != other.expression) return false - - return true - } - - override fun hashCode(): Int { - var result = features.hashCode() - result = 31 * result + expression.hashCode() - return result - } - - override fun toString(): String = "FunctionOptimization(features=$features)" -} - -public fun FunctionOptimization.withFeatures( - vararg newFeature: OptimizationFeature, -): FunctionOptimization = FunctionOptimization( - features.with(*newFeature), - expression, -) - -/** - * Optimizes differentiable expression using specific [optimizer] form given [startingPoint]. - */ -public suspend fun DifferentiableExpression.optimizeWith( - optimizer: Optimizer>, - startingPoint: Map, - vararg features: OptimizationFeature, -): FunctionOptimization { - val problem = FunctionOptimization(FeatureSet.of(OptimizationStartPoint(startingPoint), *features), this) - return optimizer.optimize(problem) -} - -public val FunctionOptimization.resultValueOrNull: T? - get() = getFeature>()?.point?.let { expression(it) } - -public val FunctionOptimization.resultValue: T - get() = resultValueOrNull ?: error("Result is not present in $this") \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt deleted file mode 100644 index 416d0195d..000000000 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationBuilder.kt +++ /dev/null @@ -1,93 +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.optimization - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.FeatureSet - -public abstract class OptimizationBuilder> { - public val features: MutableList = ArrayList() - - public fun addFeature(feature: OptimizationFeature) { - features.add(feature) - } - - public inline fun updateFeature(update: (T?) -> T) { - val existing = features.find { it.key == T::class } as? T - val new = update(existing) - if (existing != null) { - features.remove(existing) - } - addFeature(new) - } - - public abstract fun build(): R -} - -public fun OptimizationBuilder.startAt(startingPoint: Map) { - addFeature(OptimizationStartPoint(startingPoint)) -} - -public class FunctionOptimizationBuilder( - private val expression: DifferentiableExpression, -) : OptimizationBuilder>() { - override fun build(): FunctionOptimization = FunctionOptimization(FeatureSet.of(features), expression) -} - -public fun FunctionOptimization( - expression: DifferentiableExpression, - builder: FunctionOptimizationBuilder.() -> Unit, -): FunctionOptimization = FunctionOptimizationBuilder(expression).apply(builder).build() - -public suspend fun DifferentiableExpression.optimizeWith( - optimizer: Optimizer>, - startingPoint: Map, - builder: FunctionOptimizationBuilder.() -> Unit = {}, -): FunctionOptimization { - val problem = FunctionOptimization(this) { - startAt(startingPoint) - builder() - } - return optimizer.optimize(problem) -} - -public suspend fun DifferentiableExpression.optimizeWith( - optimizer: Optimizer>, - vararg startingPoint: Pair, - builder: FunctionOptimizationBuilder.() -> Unit = {}, -): FunctionOptimization { - val problem = FunctionOptimization(this) { - startAt(mapOf(*startingPoint)) - builder() - } - return optimizer.optimize(problem) -} - - -public class XYOptimizationBuilder( - public val data: XYColumnarData, - public val model: DifferentiableExpression, -) : OptimizationBuilder() { - - public var pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY - public var pointWeight: PointWeight = PointWeight.byYSigma - - override fun build(): XYFit = XYFit( - data, - model, - FeatureSet.of(features), - pointToCurveDistance, - pointWeight - ) -} - -public fun XYOptimization( - data: XYColumnarData, - model: DifferentiableExpression, - builder: XYOptimizationBuilder.() -> Unit, -): XYFit = XYOptimizationBuilder(data, model).apply(builder).build() \ No newline at end of file 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 deleted file mode 100644 index b42be4035..000000000 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/OptimizationProblem.kt +++ /dev/null @@ -1,66 +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.optimization - -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.misc.* -import kotlin.reflect.KClass - -public interface OptimizationFeature : Feature { - // enforce toString override - override fun toString(): String -} - -public interface OptimizationProblem : Featured { - public val features: FeatureSet - override fun getFeature(type: KClass): F? = features.getFeature(type) -} - -public inline fun OptimizationProblem<*>.getFeature(): F? = getFeature(F::class) - -public open class OptimizationStartPoint(public val point: Map) : OptimizationFeature { - override fun toString(): String = "StartPoint($point)" -} - - -public interface OptimizationPrior : OptimizationFeature, DifferentiableExpression { - override val key: FeatureKey get() = OptimizationPrior::class -} - -public class OptimizationCovariance(public val covariance: Matrix) : OptimizationFeature { - override fun toString(): String = "Covariance($covariance)" -} - -/** - * Get the starting point for optimization. Throws error if not defined. - */ -public val OptimizationProblem.startPoint: Map - get() = getFeature>()?.point - ?: error("Starting point not defined in $this") - -public open class OptimizationResult(public val point: Map) : OptimizationFeature { - override fun toString(): String = "Result($point)" -} - -public val OptimizationProblem.resultPointOrNull: Map? - get() = getFeature>()?.point - -public val OptimizationProblem.resultPoint: Map - get() = resultPointOrNull ?: error("Result is not present in $this") - -public class OptimizationLog(private val loggable: Loggable) : Loggable by loggable, OptimizationFeature { - override fun toString(): String = "Log($loggable)" -} - -public class OptimizationParameters(public val symbols: List) : OptimizationFeature { - public constructor(vararg symbols: Symbol) : this(listOf(*symbols)) - - override fun toString(): String = "Parameters($symbols)" -} - - diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt deleted file mode 100644 index 78385a99b..000000000 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimizer.kt +++ /dev/null @@ -1,10 +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.optimization - -public interface Optimizer> { - public suspend fun optimize(problem: P): P -} \ No newline at end of file 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 deleted file mode 100644 index babbaf6cd..000000000 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt +++ /dev/null @@ -1,266 +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.optimization - -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.SymbolIndexer -import space.kscience.kmath.expressions.derivative -import space.kscience.kmath.linear.* -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.misc.log -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.DoubleL2Norm -import space.kscience.kmath.operations.algebra -import space.kscience.kmath.structures.DoubleBuffer - - -public class QowRuns(public val runs: Int) : OptimizationFeature { - init { - require(runs >= 1) { "Number of runs must be more than zero" } - } - - override fun toString(): String = "QowRuns(runs=$runs)" -} - - -/** - * An optimizer based onf Fyodor Tkachev's quasi-optimal weights method. - * See [the article](http://arxiv.org/abs/physics/0604127). - */ -@UnstableKMathAPI -public object QowOptimizer : Optimizer { - - private val linearSpace: LinearSpace = Double.algebra.linearSpace - private val solver: LinearSolver = linearSpace.lupSolver() - - @OptIn(UnstableKMathAPI::class) - private class QoWeight( - val problem: XYFit, - val parameters: Map, - ) : Map by parameters, SymbolIndexer { - override val symbols: List = parameters.keys.toList() - - val data get() = problem.data - - /** - * Derivatives of the spectrum over parameters. First index in the point number, second one - index of parameter - */ - val derivs: Matrix by lazy { - linearSpace.buildMatrix(problem.data.size, symbols.size) { d, s -> - problem.distance(d).derivative(symbols[s])(parameters) - } - } - - /** - * Array of dispersions in each point - */ - val dispersion: Point by lazy { - DoubleBuffer(problem.data.size) { d -> - 1.0/problem.weight(d).invoke(parameters) - } - } - - val prior: DifferentiableExpression? get() = problem.getFeature>() - - override fun toString(): String = parameters.toString() - } - - /** - * The signed distance from the model to the [d]-th point of data. - */ - private fun QoWeight.distance(d: Int, parameters: Map): Double = problem.distance(d)(parameters) - - - /** - * The derivative of [distance] - */ - private fun QoWeight.distanceDerivative(symbol: Symbol, d: Int, parameters: Map): Double = - problem.distance(d).derivative(symbol)(parameters) - - /** - * Теоретическая ковариация весовых функций. - * - * D(\phi)=E(\phi_k(\theta_0) \phi_l(\theta_0))= disDeriv_k * disDeriv_l /sigma^2 - */ - private fun QoWeight.covarF(): Matrix = - linearSpace.matrix(size, size).symmetric { s1, s2 -> - (0 until data.size).sumOf { d -> derivs[d, s1] * derivs[d, s2] / dispersion[d] } - } - - /** - * Экспериментальная ковариация весов. Формула (22) из - * http://arxiv.org/abs/physics/0604127 - */ - private fun QoWeight.covarFExp(theta: Map): Matrix = - with(linearSpace) { - /* - * Важно! Если не делать предварителього вычисления этих производных, то - * количество вызывов функции будет dim^2 вместо dim Первый индекс - - * номер точки, второй - номер переменной, по которой берется производная - */ - val eqvalues = linearSpace.buildMatrix(data.size, size) { d, s -> - distance(d, theta) * derivs[d, s] / dispersion[d] - } - - buildMatrix(size, size) { s1, s2 -> - (0 until data.size).sumOf { d -> eqvalues[d, s2] * eqvalues[d, s1] } - } - } - - /** - * Equation derivatives for Newton run - */ - private fun QoWeight.getEqDerivValues( - theta: Map = parameters, - ): Matrix = with(linearSpace) { - //Возвращает производную k-того Eq по l-тому параметру - //val res = Array(fitDim) { DoubleArray(fitDim) } - val sderiv = buildMatrix(data.size, size) { d, s -> - distanceDerivative(symbols[s], d, theta) - } - - buildMatrix(size, size) { s1, s2 -> - val base = (0 until data.size).sumOf { d -> - require(dispersion[d] > 0) - sderiv[d, s2] * derivs[d, s1] / dispersion[d] - } - prior?.let { prior -> - //Check if this one is correct - val pi = prior(theta) - val deriv1 = prior.derivative(symbols[s1])(theta) - val deriv2 = prior.derivative(symbols[s2])(theta) - base + deriv1 * deriv2 / pi / pi - } ?: base - } - } - - - /** - * Значения уравнений метода квазиоптимальных весов - */ - private fun QoWeight.getEqValues(theta: Map = this): Point { - val distances = DoubleBuffer(data.size) { d -> distance(d, theta) } - - return DoubleBuffer(size) { s -> - val base = (0 until data.size).sumOf { d -> distances[d] * derivs[d, s] / dispersion[d] } - //Поправка на априорную вероятность - prior?.let { prior -> - base - prior.derivative(symbols[s])(theta) / prior(theta) - } ?: base - } - } - - - private fun QoWeight.newtonianStep( - theta: Map, - eqvalues: Point, - ): QoWeight = linearSpace { - with(this@newtonianStep) { - val start = theta.toPoint() - val invJacob = solver.inverse(this@newtonianStep.getEqDerivValues(theta)) - - val step = invJacob.dot(eqvalues) - return QoWeight(problem, theta + (start - step).toMap()) - } - } - - private fun QoWeight.newtonianRun( - maxSteps: Int = 100, - tolerance: Double = 0.0, - fast: Boolean = false, - ): QoWeight { - - val logger = problem.getFeature() - - var dis: Double //discrepancy value - // Working with the full set of parameters - var par = problem.startPoint - - logger?.log { "Starting newtonian iteration from: \n\t$par" } - - var eqvalues = getEqValues(par) //Values of the weight functions - - dis = DoubleL2Norm.norm(eqvalues) // discrepancy - logger?.log { "Starting discrepancy is $dis" } - var i = 0 - var flag = false - while (!flag) { - i++ - logger?.log { "Starting step number $i" } - - val currentSolution = if (fast) { - //Берет значения матрицы в той точке, где считается вес - newtonianStep(this, eqvalues) - } else { - //Берет значения матрицы в точке par - newtonianStep(par, eqvalues) - } - // здесь должен стоять учет границ параметров - logger?.log { "Parameter values after step are: \n\t$currentSolution" } - - eqvalues = getEqValues(currentSolution) - val currentDis = DoubleL2Norm.norm(eqvalues)// невязка после шага - - logger?.log { "The discrepancy after step is: $currentDis." } - - if (currentDis >= dis && i > 1) { - //дополнительно проверяем, чтобы был сделан хотя бы один шаг - flag = true - logger?.log { "The discrepancy does not decrease. Stopping iteration." } - } else { - par = currentSolution - dis = currentDis - } - if (i >= maxSteps) { - flag = true - logger?.log { "Maximum number of iterations reached. Stopping iteration." } - } - if (dis <= tolerance) { - flag = true - logger?.log { "Tolerance threshold is reached. Stopping iteration." } - } - } - - return QoWeight(problem, par) - } - - private fun QoWeight.covariance(): Matrix { - val logger = problem.getFeature() - - logger?.log { - """ - Starting errors estimation using quasioptimal weights method. The starting weight is: - ${problem.startPoint} - """.trimIndent() - } - - val covar = solver.inverse(getEqDerivValues()) - //TODO fix eigenvalues check -// val decomposition = EigenDecomposition(covar.matrix) -// var valid = true -// for (lambda in decomposition.realEigenvalues) { -// if (lambda <= 0) { -// logger?.log { "The covariance matrix is not positive defined. Error estimation is not valid" } -// valid = false -// } -// } - return covar - } - - override suspend fun optimize(problem: XYFit): XYFit { - val qowRuns = problem.getFeature()?.runs ?: 2 - - - var qow = QoWeight(problem, problem.startPoint) - var res = qow.newtonianRun() - repeat(qowRuns - 1) { - qow = QoWeight(problem, res.parameters) - res = qow.newtonianRun() - } - return res.problem.withFeature(OptimizationResult(res.parameters)) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt deleted file mode 100644 index 07fea3126..000000000 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt +++ /dev/null @@ -1,146 +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. - */ -@file:OptIn(UnstableKMathAPI::class) - -package space.kscience.kmath.optimization - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.data.indices -import space.kscience.kmath.expressions.* -import space.kscience.kmath.misc.FeatureSet -import space.kscience.kmath.misc.Loggable -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.bindSymbol -import kotlin.math.pow - -/** - * Specify the way to compute distance from point to the curve as DifferentiableExpression - */ -public interface PointToCurveDistance : OptimizationFeature { - public fun distance(problem: XYFit, index: Int): DifferentiableExpression - - public companion object { - public val byY: PointToCurveDistance = object : PointToCurveDistance { - override fun distance(problem: XYFit, index: Int): DifferentiableExpression { - val x = problem.data.x[index] - val y = problem.data.y[index] - - return object : DifferentiableExpression { - override fun derivativeOrNull( - symbols: List - ): Expression? = problem.model.derivativeOrNull(symbols)?.let { derivExpression -> - Expression { arguments -> - derivExpression.invoke(arguments + (Symbol.x to x)) - } - } - - override fun invoke(arguments: Map): Double = - problem.model(arguments + (Symbol.x to x)) - y - } - } - - override fun toString(): String = "PointToCurveDistanceByY" - } - } -} - -/** - * Compute a wight of the point. The more the weight, the more impact this point will have on the fit. - * By default, uses Dispersion^-1 - */ -public interface PointWeight : OptimizationFeature { - public fun weight(problem: XYFit, index: Int): DifferentiableExpression - - public companion object { - public fun bySigma(sigmaSymbol: Symbol): PointWeight = object : PointWeight { - override fun weight(problem: XYFit, index: Int): DifferentiableExpression = - object : DifferentiableExpression { - override fun invoke(arguments: Map): Double { - return problem.data[sigmaSymbol]?.get(index)?.pow(-2) ?: 1.0 - } - - override fun derivativeOrNull(symbols: List): Expression = Expression { 0.0 } - } - - override fun toString(): String = "PointWeightBySigma($sigmaSymbol)" - - } - - public val byYSigma: PointWeight = bySigma(Symbol.yError) - } -} - -/** - * A fit problem for X-Y-Yerr data. Also known as "least-squares" problem. - */ -public class XYFit( - public val data: XYColumnarData, - public val model: DifferentiableExpression, - override val features: FeatureSet, - internal val pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY, - internal val pointWeight: PointWeight = PointWeight.byYSigma, - public val xSymbol: Symbol = Symbol.x, -) : OptimizationProblem { - public fun distance(index: Int): DifferentiableExpression = pointToCurveDistance.distance(this, index) - - public fun weight(index: Int): DifferentiableExpression = pointWeight.weight(this, index) -} - -public fun XYFit.withFeature(vararg features: OptimizationFeature): XYFit { - return XYFit(data, model, this.features.with(*features), pointToCurveDistance, pointWeight) -} - -/** - * Fit given dta with - */ -public suspend fun XYColumnarData.fitWith( - optimizer: Optimizer, - processor: AutoDiffProcessor, - startingPoint: Map, - vararg features: OptimizationFeature = emptyArray(), - xSymbol: Symbol = Symbol.x, - pointToCurveDistance: PointToCurveDistance = PointToCurveDistance.byY, - pointWeight: PointWeight = PointWeight.byYSigma, - model: A.(I) -> I -): XYFit where A : ExtendedField, A : ExpressionAlgebra { - val modelExpression = processor.differentiate { - val x = bindSymbol(xSymbol) - model(x) - } - - var actualFeatures = FeatureSet.of(*features, OptimizationStartPoint(startingPoint)) - - if (actualFeatures.getFeature() == null) { - actualFeatures = actualFeatures.with(OptimizationLog(Loggable.console)) - } - val problem = XYFit( - this, - modelExpression, - actualFeatures, - pointToCurveDistance, - pointWeight, - xSymbol - ) - return optimizer.optimize(problem) -} - -/** - * Compute chi squared value for completed fit. Return null for incomplete fit - */ -public val XYFit.chiSquaredOrNull: Double? get() { - val result = resultPointOrNull ?: return null - - return data.indices.sumOf { index-> - - val x = data.x[index] - val y = data.y[index] - val yErr = data[Symbol.yError]?.get(index) ?: 1.0 - - val mu = model.invoke(result + (xSymbol to x) ) - - ((y - mu)/yErr).pow(2) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt b/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt deleted file mode 100644 index b4cb2f1cf..000000000 --- a/kmath-optimization/src/commonMain/kotlin/space/kscience/kmath/optimization/logLikelihood.kt +++ /dev/null @@ -1,66 +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.optimization - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.data.indices -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.derivative -import space.kscience.kmath.misc.UnstableKMathAPI -import kotlin.math.PI -import kotlin.math.ln -import kotlin.math.pow -import kotlin.math.sqrt - - -private val oneOver2Pi = 1.0 / sqrt(2 * PI) - -@UnstableKMathAPI -internal fun XYFit.logLikelihood(): DifferentiableExpression = object : DifferentiableExpression { - override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> - data.indices.sumOf { index -> - val d = distance(index)(arguments) - val weight = weight(index)(arguments) - val weightDerivative = weight(index).derivative(symbols)(arguments) - - // -1 / (sqrt(2 PI) * sigma) + 2 (x-mu)/ 2 sigma^2 * d mu/ d theta - (x-mu)^2 / 2 * d w/ d theta - return@sumOf -oneOver2Pi * sqrt(weight) + //offset derivative - d * model.derivative(symbols)(arguments) * weight - //model derivative - d.pow(2) * weightDerivative / 2 //weight derivative - } - } - - override fun invoke(arguments: Map): Double { - return data.indices.sumOf { index -> - val d = distance(index)(arguments) - val weight = weight(index)(arguments) - //1/sqrt(2 PI sigma^2) - (x-mu)^2/ (2 * sigma^2) - oneOver2Pi * ln(weight) - d.pow(2) * weight - } / 2 - } - -} - -/** - * Optimize given XY (least squares) [problem] using this function [Optimizer]. - * The problem is treated as maximum likelihood problem and is done via maximizing logarithmic likelihood, respecting - * possible weight dependency on the model and parameters. - */ -@UnstableKMathAPI -public suspend fun Optimizer>.maximumLogLikelihood(problem: XYFit): XYFit { - val functionOptimization = FunctionOptimization(problem.features, problem.logLikelihood()) - val result = optimize(functionOptimization.withFeatures(FunctionOptimizationTarget.MAXIMIZE)) - return XYFit(problem.data, problem.model, result.features) -} - -@UnstableKMathAPI -public suspend fun Optimizer>.maximumLogLikelihood( - data: XYColumnarData, - model: DifferentiableExpression, - builder: XYOptimizationBuilder.() -> Unit, -): XYFit = maximumLogLikelihood(XYOptimization(data, model, builder)) diff --git a/kmath-optimization/src/commonMain/tmp/QowFit.kt b/kmath-optimization/src/commonMain/tmp/QowFit.kt deleted file mode 100644 index c78aef401..000000000 --- a/kmath-optimization/src/commonMain/tmp/QowFit.kt +++ /dev/null @@ -1,372 +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.optimization.qow - -import space.kscience.kmath.data.ColumnarData -import space.kscience.kmath.data.XYErrorColumnarData -import space.kscience.kmath.expressions.* -import space.kscience.kmath.linear.* -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Field -import space.kscience.kmath.optimization.OptimizationFeature -import space.kscience.kmath.optimization.OptimizationProblemFactory -import space.kscience.kmath.optimization.OptimizationResult -import space.kscience.kmath.optimization.XYOptimization -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.DoubleL2Norm -import kotlin.math.pow - - -private typealias ParamSet = Map - -@OptIn(UnstableKMathAPI::class) -public class QowFit( - override val symbols: List, - private val space: LinearSpace, - private val solver: LinearSolver, -) : XYOptimization, SymbolIndexer { - - private var logger: FitLogger? = null - - private var startingPoint: Map = TODO() - private var covariance: Matrix? = TODO() - private val prior: DifferentiableExpression>? = TODO() - private var data: XYErrorColumnarData = TODO() - private var model: DifferentiableExpression> = TODO() - - private val features = HashSet() - - override fun update(result: OptimizationResult) { - TODO("Not yet implemented") - } - - override val algebra: Field - get() = TODO("Not yet implemented") - - override fun data( - dataSet: ColumnarData, - xSymbol: Symbol, - ySymbol: Symbol, - xErrSymbol: Symbol?, - yErrSymbol: Symbol?, - ) { - TODO("Not yet implemented") - } - - override fun model(model: (Double) -> DifferentiableExpression) { - TODO("Not yet implemented") - } - - private var x: Symbol = Symbol.x - - /** - * The signed distance from the model to the [i]-th point of data. - */ - private fun distance(i: Int, parameters: Map): Double = - model(parameters + (x to data.x[i])) - data.y[i] - - - /** - * The derivative of [distance] - * TODO use expressions instead - */ - private fun distanceDerivative(symbol: Symbol, i: Int, parameters: Map): Double = - model.derivative(symbol)(parameters + (x to data.x[i])) - - /** - * The dispersion of [i]-th data point - */ - private fun getDispersion(i: Int, parameters: Map): Double = data.yErr[i].pow(2) - - private fun getCovariance(weight: QoWeight): Matrix = solver.inverse(getEqDerivValues(weight)) - - /** - * Теоретическая ковариация весовых функций. - * - * D(\phi)=E(\phi_k(\theta_0) \phi_l(\theta_0))= disDeriv_k * disDeriv_l /sigma^2 - */ - private fun covarF(weight: QoWeight): Matrix = space.buildSymmetricMatrix(symbols.size) { k, l -> - (0 until data.size).sumOf { i -> weight.derivs[k, i] * weight.derivs[l, i] / weight.dispersion[i] } - } - - /** - * Экспериментальная ковариация весов. Формула (22) из - * http://arxiv.org/abs/physics/0604127 - * - * @param source - * @param set - * @param fitPars - * @param weight - * @return - */ - private fun covarFExp(weight: QoWeight, theta: Map): Matrix = space.run { - /* - * Важно! Если не делать предварителього вычисления этих производных, то - * количество вызывов функции будет dim^2 вместо dim Первый индекс - - * номер точки, второй - номер переменной, по которой берется производная - */ - val eqvalues = buildMatrix(data.size, symbols.size) { i, l -> - distance(i, theta) * weight.derivs[l, i] / weight.dispersion[i] - } - - buildMatrix(symbols.size, symbols.size) { k, l -> - (0 until data.size).sumOf { i -> eqvalues[i, l] * eqvalues[i, k] } - } - } - - /** - * производные уравнений для метода Ньютона - * - * @param source - * @param set - * @param fitPars - * @param weight - * @return - */ - private fun getEqDerivValues( - weight: QoWeight, theta: Map = weight.theta, - ): Matrix = space.run { - val fitDim = symbols.size - //Возвращает производную k-того Eq по l-тому параметру - val res = Array(fitDim) { DoubleArray(fitDim) } - val sderiv = buildMatrix(data.size, symbols.size) { i, l -> - distanceDerivative(symbols[l], i, theta) - } - - buildMatrix(symbols.size, symbols.size) { k, l -> - val base = (0 until data.size).sumOf { i -> - require(weight.dispersion[i] > 0) - sderiv[i, l] * weight.derivs[k, i] / weight.dispersion[i] - } - prior?.let { prior -> - //Check if this one is correct - val pi = prior(theta) - val deriv1 = prior.derivative(symbols[k])(theta) - val deriv2 = prior.derivative(symbols[l])(theta) - base + deriv1 * deriv2 / pi / pi - } ?: base - } - } - - - /** - * Значения уравнений метода квазиоптимальных весов - * - * @param source - * @param set - * @param fitPars - * @param weight - * @return - */ - private fun getEqValues(weight: QoWeight, theta: Map = weight.theta): Point { - val distances = DoubleBuffer(data.size) { i -> distance(i, theta) } - - return DoubleBuffer(symbols.size) { k -> - val base = (0 until data.size).sumOf { i -> distances[i] * weight.derivs[k, i] / weight.dispersion[i] } - //Поправка на априорную вероятность - prior?.let { prior -> - base - prior.derivative(symbols[k])(theta) / prior(theta) - } ?: base - } - } - - - /** - * The state of QOW fitter - * Created by Alexander Nozik on 17-Oct-16. - */ - private inner class QoWeight( - val theta: Map, - ) { - - init { - require(data.size > 0) { "The state does not contain data" } - } - - /** - * Derivatives of the spectrum over parameters. First index in the point number, second one - index of parameter - */ - val derivs: Matrix by lazy { - space.buildMatrix(data.size, symbols.size) { i, k -> - distanceDerivative(symbols[k], i, theta) - } - } - - /** - * Array of dispersions in each point - */ - val dispersion: Point by lazy { - DoubleBuffer(data.size) { i -> getDispersion(i, theta) } - } - - } - - private fun newtonianStep( - weight: QoWeight, - par: Map, - eqvalues: Point, - ): Map = space.run { - val start = par.toPoint() - val invJacob = solver.inverse(getEqDerivValues(weight, par)) - - val step = invJacob.dot(eqvalues) - return par + (start - step).toMap() - } - - private fun newtonianRun( - weight: QoWeight, - maxSteps: Int = 100, - tolerance: Double = 0.0, - fast: Boolean = false, - ): ParamSet { - - var dis: Double//норма невязки - // Для удобства работаем всегда с полным набором параметров - var par = startingPoint - - logger?.log { "Starting newtonian iteration from: \n\t$par" } - - var eqvalues = getEqValues(weight, par)//значения функций - - dis = DoubleL2Norm.norm(eqvalues)// невязка - logger?.log { "Starting discrepancy is $dis" } - var i = 0 - var flag = false - while (!flag) { - i++ - logger?.log { "Starting step number $i" } - - val currentSolution = if (fast) { - //Берет значения матрицы в той точке, где считается вес - newtonianStep(weight, weight.theta, eqvalues) - } else { - //Берет значения матрицы в точке par - newtonianStep(weight, par, eqvalues) - } - // здесь должен стоять учет границ параметров - logger?.log { "Parameter values after step are: \n\t$currentSolution" } - - eqvalues = getEqValues(weight, currentSolution) - val currentDis = DoubleL2Norm.norm(eqvalues)// невязка после шага - - logger?.log { "The discrepancy after step is: $currentDis." } - - if (currentDis >= dis && i > 1) { - //дополнительно проверяем, чтобы был сделан хотя бы один шаг - flag = true - logger?.log { "The discrepancy does not decrease. Stopping iteration." } - } else { - par = currentSolution - dis = currentDis - } - if (i >= maxSteps) { - flag = true - logger?.log { "Maximum number of iterations reached. Stopping iteration." } - } - if (dis <= tolerance) { - flag = true - logger?.log { "Tolerance threshold is reached. Stopping iteration." } - } - } - - return par - } - - -// -// override fun run(state: FitState, parentLog: History?, meta: Meta): FitResult { -// val log = Chronicle("QOW", parentLog) -// val action = meta.getString(FIT_STAGE_TYPE, TASK_RUN) -// log.report("QOW fit engine started task '{}'", action) -// return when (action) { -// TASK_SINGLE -> makeRun(state, log, meta) -// TASK_COVARIANCE -> generateErrors(state, log, meta) -// TASK_RUN -> { -// var res = makeRun(state, log, meta) -// res = makeRun(res.optState().get(), log, meta) -// generateErrors(res.optState().get(), log, meta) -// } -// else -> throw IllegalArgumentException("Unknown task") -// } -// } - -// private fun makeRun(state: FitState, log: History, meta: Meta): FitResult { -// /*Инициализация объектов, задание исходных значений*/ -// log.report("Starting fit using quasioptimal weights method.") -// -// val fitPars = getFitPars(state, meta) -// -// val curWeight = QoWeight(state, fitPars, state.parameters) -// -// // вычисляем вес в allPar. Потом можно будет попробовать ручное задание веса -// log.report("The starting weight is: \n\t{}", -// MathUtils.toString(curWeight.theta)) -// -// //Стартовая точка такая же как и параметр веса -// /*Фитирование*/ -// val res = newtonianRun(state, curWeight, log, meta) -// -// /*Генерация результата*/ -// -// return FitResult.build(state.edit().setPars(res).build(), *fitPars) -// } - - /** - * generateErrors. - */ - private fun generateErrors(): Matrix { - logger?.log { """ - Starting errors estimation using quasioptimal weights method. The starting weight is: - ${curWeight.theta} - """.trimIndent()} - val curWeight = QoWeight(startingPoint) - - val covar = getCovariance(curWeight) - - val decomposition = EigenDecomposition(covar.matrix) - var valid = true - for (lambda in decomposition.realEigenvalues) { - if (lambda <= 0) { - log.report("The covariance matrix is not positive defined. Error estimation is not valid") - valid = false - } - } - } - - - override suspend fun optimize(): OptimizationResult { - val curWeight = QoWeight(startingPoint) - logger?.log { - """ - Starting fit using quasioptimal weights method. The starting weight is: - ${curWeight.theta} - """.trimIndent() - } - val res = newtonianRun(curWeight) - } - - - companion object : OptimizationProblemFactory { - override fun build(symbols: List): QowFit { - TODO("Not yet implemented") - } - - - /** - * Constant `QOW_ENGINE_NAME="QOW"` - */ - const val QOW_ENGINE_NAME = "QOW" - - /** - * Constant `QOW_METHOD_FAST="fast"` - */ - const val QOW_METHOD_FAST = "fast" - - - } -} - diff --git a/kmath-optimization/src/commonMain/tmp/minuit/AnalyticalGradientCalculator.kt b/kmath-optimization/src/commonMain/tmp/minuit/AnalyticalGradientCalculator.kt deleted file mode 100644 index 912fa22eb..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/AnalyticalGradientCalculator.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction - -/** - * - * @version $Id$ - */ -internal class AnalyticalGradientCalculator(fcn: MultiFunction?, state: MnUserTransformation, checkGradient: Boolean) : - GradientCalculator { - private val function: MultiFunction? - private val theCheckGradient: Boolean - private val theTransformation: MnUserTransformation - fun checkGradient(): Boolean { - return theCheckGradient - } - - /** {@inheritDoc} */ - fun gradient(par: MinimumParameters): FunctionGradient { -// double[] grad = theGradCalc.gradientValue(theTransformation.andThen(par.vec()).data()); - val point: DoubleArray = theTransformation.transform(par.vec()).toArray() - require(!(function.getDimension() !== theTransformation.parameters().size())) { "Invalid parameter size" } - val v: RealVector = ArrayRealVector(par.vec().getDimension()) - for (i in 0 until par.vec().getDimension()) { - val ext: Int = theTransformation.extOfInt(i) - if (theTransformation.parameter(ext).hasLimits()) { - val dd: Double = theTransformation.dInt2Ext(i, par.vec().getEntry(i)) - v.setEntry(i, dd * function.derivValue(ext, point)) - } else { - v.setEntry(i, function.derivValue(ext, point)) - } - } - return FunctionGradient(v) - } - - /** {@inheritDoc} */ - fun gradient(par: MinimumParameters, grad: FunctionGradient?): FunctionGradient { - return gradient(par) - } - - init { - function = fcn - theTransformation = state - theCheckGradient = checkGradient - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimizer.kt deleted file mode 100644 index 9363492ad..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimizer.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class CombinedMinimizer : ModularFunctionMinimizer() { - private val theMinBuilder: CombinedMinimumBuilder = CombinedMinimumBuilder() - private val theMinSeedGen: MnSeedGenerator = MnSeedGenerator() - override fun builder(): MinimumBuilder { - return theMinBuilder - } - - override fun seedGenerator(): MinimumSeedGenerator { - return theMinSeedGen - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt deleted file mode 100644 index 8c5452575..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/CombinedMinimumBuilder.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MINUITPlugin -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * - * @version $Id$ - */ -internal class CombinedMinimumBuilder : MinimumBuilder { - private val theSimplexMinimizer: SimplexMinimizer = SimplexMinimizer() - private val theVMMinimizer: VariableMetricMinimizer = VariableMetricMinimizer() - - /** {@inheritDoc} */ - override fun minimum( - fcn: MnFcn?, - gc: GradientCalculator?, - seed: MinimumSeed?, - strategy: MnStrategy?, - maxfcn: Int, - toler: Double - ): FunctionMinimum { - val min: FunctionMinimum = theVMMinimizer.minimize(fcn!!, gc, seed, strategy, maxfcn, toler) - if (!min.isValid()) { - MINUITPlugin.logStatic("CombinedMinimumBuilder: migrad method fails, will try with simplex method first.") - val str = MnStrategy(2) - val min1: FunctionMinimum = theSimplexMinimizer.minimize(fcn, gc, seed, str, maxfcn, toler) - if (!min1.isValid()) { - MINUITPlugin.logStatic("CombinedMinimumBuilder: both migrad and simplex method fail.") - return min1 - } - val seed1: MinimumSeed = theVMMinimizer.seedGenerator().generate(fcn, gc, min1.userState(), str) - val min2: FunctionMinimum = theVMMinimizer.minimize(fcn, gc, seed1, str, maxfcn, toler) - if (!min2.isValid()) { - MINUITPlugin.logStatic("CombinedMinimumBuilder: both migrad and method fails also at 2nd attempt.") - MINUITPlugin.logStatic("CombinedMinimumBuilder: return simplex minimum.") - return min1 - } - return min2 - } - return min - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/ContoursError.kt b/kmath-optimization/src/commonMain/tmp/minuit/ContoursError.kt deleted file mode 100644 index 214d94c80..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/ContoursError.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * ContoursError class. - * - * @author Darksnake - * @version $Id$ - */ -class ContoursError internal constructor( - private val theParX: Int, - private val theParY: Int, - points: List, - xmnos: MinosError, - ymnos: MinosError, - nfcn: Int -) { - private val theNFcn: Int - private val thePoints: List = points - private val theXMinos: MinosError - private val theYMinos: MinosError - - /** - * - * nfcn. - * - * @return a int. - */ - fun nfcn(): Int { - return theNFcn - } - - /** - * - * points. - * - * @return a [List] object. - */ - fun points(): List { - return thePoints - } - - /** - * {@inheritDoc} - */ - override fun toString(): String { - return MnPrint.toString(this) - } - - /** - * - * xMinosError. - * - * @return a [hep.dataforge.MINUIT.MinosError] object. - */ - fun xMinosError(): MinosError { - return theXMinos - } - - /** - * - * xRange. - * - * @return - */ - fun xRange(): Range { - return theXMinos.range() - } - - /** - * - * xmin. - * - * @return a double. - */ - fun xmin(): Double { - return theXMinos.min() - } - - /** - * - * xpar. - * - * @return a int. - */ - fun xpar(): Int { - return theParX - } - - /** - * - * yMinosError. - * - * @return a [hep.dataforge.MINUIT.MinosError] object. - */ - fun yMinosError(): MinosError { - return theYMinos - } - - /** - * - * yRange. - * - * @return - */ - fun yRange(): Range { - return theYMinos.range() - } - - /** - * - * ymin. - * - * @return a double. - */ - fun ymin(): Double { - return theYMinos.min() - } - - /** - * - * ypar. - * - * @return a int. - */ - fun ypar(): Int { - return theParY - } - - init { - theXMinos = xmnos - theYMinos = ymnos - theNFcn = nfcn - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt b/kmath-optimization/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt deleted file mode 100644 index 9eb2443e4..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/DavidonErrorUpdator.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.RealVector -import ru.inr.mass.minuit.* - -/** - * - * @version $Id$ - */ -internal class DavidonErrorUpdator : MinimumErrorUpdator { - /** {@inheritDoc} */ - fun update(s0: MinimumState, p1: MinimumParameters, g1: FunctionGradient): MinimumError { - val V0: MnAlgebraicSymMatrix = s0.error().invHessian() - val dx: RealVector = MnUtils.sub(p1.vec(), s0.vec()) - val dg: RealVector = MnUtils.sub(g1.getGradient(), s0.gradient().getGradient()) - val delgam: Double = MnUtils.innerProduct(dx, dg) - val gvg: Double = MnUtils.similarity(dg, V0) - val vg: RealVector = MnUtils.mul(V0, dg) - var Vupd: MnAlgebraicSymMatrix = - MnUtils.sub(MnUtils.div(MnUtils.outerProduct(dx), delgam), MnUtils.div(MnUtils.outerProduct(vg), gvg)) - if (delgam > gvg) { - Vupd = MnUtils.add(Vupd, - MnUtils.mul(MnUtils.outerProduct(MnUtils.sub(MnUtils.div(dx, delgam), MnUtils.div(vg, gvg))), gvg)) - } - val sum_upd: Double = MnUtils.absoluteSumOfElements(Vupd) - Vupd = MnUtils.add(Vupd, V0) - val dcov: Double = 0.5 * (s0.error().dcovar() + sum_upd / MnUtils.absoluteSumOfElements(Vupd)) - return MinimumError(Vupd, dcov) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/FunctionGradient.kt b/kmath-optimization/src/commonMain/tmp/minuit/FunctionGradient.kt deleted file mode 100644 index a0866d916..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/FunctionGradient.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector - -/** - * - * @version $Id$ - */ -class FunctionGradient { - private var theAnalytical = false - private var theG2ndDerivative: RealVector - private var theGStepSize: RealVector - private var theGradient: RealVector - private var theValid = false - - constructor(n: Int) { - theGradient = ArrayRealVector(n) - theG2ndDerivative = ArrayRealVector(n) - theGStepSize = ArrayRealVector(n) - } - - constructor(grd: RealVector) { - theGradient = grd - theG2ndDerivative = ArrayRealVector(grd.getDimension()) - theGStepSize = ArrayRealVector(grd.getDimension()) - theValid = true - theAnalytical = true - } - - constructor(grd: RealVector, g2: RealVector, gstep: RealVector) { - theGradient = grd - theG2ndDerivative = g2 - theGStepSize = gstep - theValid = true - theAnalytical = false - } - - fun getGradient(): RealVector { - return theGradient - } - - fun getGradientDerivative(): RealVector { - return theG2ndDerivative - } - - fun getStep(): RealVector { - return theGStepSize - } - - fun isAnalytical(): Boolean { - return theAnalytical - } - - fun isValid(): Boolean { - return theValid - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/FunctionMinimum.kt b/kmath-optimization/src/commonMain/tmp/minuit/FunctionMinimum.kt deleted file mode 100644 index e43523291..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/FunctionMinimum.kt +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.minuit.* -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * Result of the minimization. - * - * - * The FunctionMinimum is the output of the minimizers and contains the - * minimization result. The methods - * - * * userState(), - * * userParameters() and - * * userCovariance() - * - * are provided. These can be used as new input to a new minimization after some - * manipulation. The parameters and/or the FunctionMinimum can be printed using - * the toString() method or the MnPrint class. - * - * @author Darksnake - */ -class FunctionMinimum { - private var theAboveMaxEdm = false - private var theErrorDef: Double - private var theReachedCallLimit = false - private var theSeed: MinimumSeed - private var theStates: MutableList - private var theUserState: MnUserParameterState - - internal constructor(seed: MinimumSeed, up: Double) { - theSeed = seed - theStates = ArrayList() - theStates.add(MinimumState(seed.parameters(), - seed.error(), - seed.gradient(), - seed.parameters().fval(), - seed.nfcn())) - theErrorDef = up - theUserState = MnUserParameterState() - } - - internal constructor(seed: MinimumSeed, states: MutableList, up: Double) { - theSeed = seed - theStates = states - theErrorDef = up - theUserState = MnUserParameterState() - } - - internal constructor(seed: MinimumSeed, states: MutableList, up: Double, x: MnReachedCallLimit?) { - theSeed = seed - theStates = states - theErrorDef = up - theReachedCallLimit = true - theUserState = MnUserParameterState() - } - - internal constructor(seed: MinimumSeed, states: MutableList, up: Double, x: MnAboveMaxEdm?) { - theSeed = seed - theStates = states - theErrorDef = up - theAboveMaxEdm = true - theReachedCallLimit = false - theUserState = MnUserParameterState() - } - - // why not - fun add(state: MinimumState) { - theStates.add(state) - } - - /** - * returns the expected vertical distance to the minimum (EDM) - * - * @return a double. - */ - fun edm(): Double { - return lastState().edm() - } - - fun error(): MinimumError { - return lastState().error() - } - - /** - * - * - * errorDef. - * - * @return a double. - */ - fun errorDef(): Double { - return theErrorDef - } - - /** - * Returns the function value at the minimum. - * - * @return a double. - */ - fun fval(): Double { - return lastState().fval() - } - - fun grad(): FunctionGradient { - return lastState().gradient() - } - - fun hasAccurateCovar(): Boolean { - return state().error().isAccurate() - } - - fun hasCovariance(): Boolean { - return state().error().isAvailable() - } - - fun hasMadePosDefCovar(): Boolean { - return state().error().isMadePosDef() - } - - fun hasPosDefCovar(): Boolean { - return state().error().isPosDef() - } - - fun hasReachedCallLimit(): Boolean { - return theReachedCallLimit - } - - fun hasValidCovariance(): Boolean { - return state().error().isValid() - } - - fun hasValidParameters(): Boolean { - return state().parameters().isValid() - } - - fun hesseFailed(): Boolean { - return state().error().hesseFailed() - } - - fun isAboveMaxEdm(): Boolean { - return theAboveMaxEdm - } - - /** - * In general, if this returns true, the minimizer did find a - * minimum without running into troubles. However, in some cases a minimum - * cannot be found, then the return value will be false. - * Reasons for the minimization to fail are - * - * * the number of allowed function calls has been exhausted - * * the minimizer could not improve the values of the parameters (and - * knowing that it has not converged yet) - * * a problem with the calculation of the covariance matrix - * - * Additional methods for the analysis of the state at the minimum are - * provided. - * - * @return a boolean. - */ - fun isValid(): Boolean { - return state().isValid() && !isAboveMaxEdm() && !hasReachedCallLimit() - } - - private fun lastState(): MinimumState { - return theStates[theStates.size - 1] - } - // forward interface of last state - /** - * returns the total number of function calls during the minimization. - * - * @return a int. - */ - fun nfcn(): Int { - return lastState().nfcn() - } - - fun parameters(): MinimumParameters { - return lastState().parameters() - } - - fun seed(): MinimumSeed { - return theSeed - } - - fun state(): MinimumState { - return lastState() - } - - fun states(): List { - return theStates - } - - /** - * {@inheritDoc} - * - * @return - */ - override fun toString(): String { - return MnPrint.toString(this) - } - - /** - * - * - * userCovariance. - * - * @return a [hep.dataforge.MINUIT.MnUserCovariance] object. - */ - fun userCovariance(): MnUserCovariance { - if (!theUserState.isValid()) { - theUserState = MnUserParameterState(state(), errorDef(), seed().trafo()) - } - return theUserState.covariance() - } - - /** - * - * - * userParameters. - * - * @return a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - fun userParameters(): MnUserParameters { - if (!theUserState.isValid()) { - theUserState = MnUserParameterState(state(), errorDef(), seed().trafo()) - } - return theUserState.parameters() - } - - /** - * user representation of state at minimum - * - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun userState(): MnUserParameterState { - if (!theUserState.isValid()) { - theUserState = MnUserParameterState(state(), errorDef(), seed().trafo()) - } - return theUserState - } - - internal class MnAboveMaxEdm - internal class MnReachedCallLimit -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/GradientCalculator.kt b/kmath-optimization/src/commonMain/tmp/minuit/GradientCalculator.kt deleted file mode 100644 index 379de1b6d..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/GradientCalculator.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -interface GradientCalculator { - /** - * - * gradient. - * - * @param par a [hep.dataforge.MINUIT.MinimumParameters] object. - * @return a [hep.dataforge.MINUIT.FunctionGradient] object. - */ - fun gradient(par: MinimumParameters?): FunctionGradient - - /** - * - * gradient. - * - * @param par a [hep.dataforge.MINUIT.MinimumParameters] object. - * @param grad a [hep.dataforge.MINUIT.FunctionGradient] object. - * @return a [hep.dataforge.MINUIT.FunctionGradient] object. - */ - fun gradient(par: MinimumParameters?, grad: FunctionGradient?): FunctionGradient -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/HessianGradientCalculator.kt b/kmath-optimization/src/commonMain/tmp/minuit/HessianGradientCalculator.kt deleted file mode 100644 index 150d192f9..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/HessianGradientCalculator.kt +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector -import ru.inr.mass.minuit.* - -/** - * - * @version $Id$ - */ -internal class HessianGradientCalculator(fcn: MnFcn, par: MnUserTransformation, stra: MnStrategy) : GradientCalculator { - private val theFcn: MnFcn = fcn - private val theStrategy: MnStrategy - private val theTransformation: MnUserTransformation - fun deltaGradient(par: MinimumParameters, gradient: FunctionGradient): Pair { - require(par.isValid()) { "parameters are invalid" } - val x: RealVector = par.vec().copy() - val grd: RealVector = gradient.getGradient().copy() - val g2: RealVector = gradient.getGradientDerivative() - val gstep: RealVector = gradient.getStep() - val fcnmin: Double = par.fval() - // std::cout<<"fval: "< optstp) { - d = optstp - } - if (d < dmin) { - d = dmin - } - var chgold = 10000.0 - var dgmin = 0.0 - var grdold = 0.0 - var grdnew = 0.0 - for (j in 0 until ncycle()) { - x.setEntry(i, xtf + d) - val fs1: Double = theFcn.value(x) - x.setEntry(i, xtf - d) - val fs2: Double = theFcn.value(x) - x.setEntry(i, xtf) - // double sag = 0.5*(fs1+fs2-2.*fcnmin); - grdold = grd.getEntry(i) - grdnew = (fs1 - fs2) / (2.0 * d) - dgmin = precision().eps() * (abs(fs1) + abs(fs2)) / d - if (abs(grdnew) < precision().eps()) { - break - } - val change: Double = abs((grdold - grdnew) / grdnew) - if (change > chgold && j > 1) { - break - } - chgold = change - grd.setEntry(i, grdnew) - if (change < 0.05) { - break - } - if (abs(grdold - grdnew) < dgmin) { - break - } - if (d < dmin) { - break - } - d *= 0.2 - } - dgrd.setEntry(i, max(dgmin, abs(grdold - grdnew))) - } - return Pair(FunctionGradient(grd, g2, gstep), dgrd) - } - - fun fcn(): MnFcn { - return theFcn - } - - fun gradTolerance(): Double { - return strategy().gradientTolerance() - } - - /** {@inheritDoc} */ - fun gradient(par: MinimumParameters): FunctionGradient { - val gc = InitialGradientCalculator(theFcn, theTransformation, theStrategy) - val gra: FunctionGradient = gc.gradient(par) - return gradient(par, gra) - } - - /** {@inheritDoc} */ - fun gradient(par: MinimumParameters, gradient: FunctionGradient): FunctionGradient { - return deltaGradient(par, gradient).getFirst() - } - - fun ncycle(): Int { - return strategy().hessianGradientNCycles() - } - - fun precision(): MnMachinePrecision { - return theTransformation.precision() - } - - fun stepTolerance(): Double { - return strategy().gradientStepTolerance() - } - - fun strategy(): MnStrategy { - return theStrategy - } - - fun trafo(): MnUserTransformation { - return theTransformation - } - - init { - theTransformation = par - theStrategy = stra - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/InitialGradientCalculator.kt b/kmath-optimization/src/commonMain/tmp/minuit/InitialGradientCalculator.kt deleted file mode 100644 index 794556414..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/InitialGradientCalculator.kt +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector -import ru.inr.mass.minuit.* - -/** - * Calculating derivatives via finite differences - * @version $Id$ - */ -internal class InitialGradientCalculator(fcn: MnFcn, par: MnUserTransformation, stra: MnStrategy) { - private val theFcn: MnFcn = fcn - private val theStrategy: MnStrategy - private val theTransformation: MnUserTransformation - fun fcn(): MnFcn { - return theFcn - } - - fun gradTolerance(): Double { - return strategy().gradientTolerance() - } - - fun gradient(par: MinimumParameters): FunctionGradient { - require(par.isValid()) { "Parameters are invalid" } - val n: Int = trafo().variableParameters() - require(n == par.vec().getDimension()) { "Parameters have invalid size" } - val gr: RealVector = ArrayRealVector(n) - val gr2: RealVector = ArrayRealVector(n) - val gst: RealVector = ArrayRealVector(n) - - // initial starting values - for (i in 0 until n) { - val exOfIn: Int = trafo().extOfInt(i) - val `var`: Double = par.vec().getEntry(i) //parameter value - val werr: Double = trafo().parameter(exOfIn).error() //parameter error - val sav: Double = trafo().int2ext(i, `var`) //value after transformation - var sav2 = sav + werr //value after transfomation + error - if (trafo().parameter(exOfIn).hasLimits()) { - if (trafo().parameter(exOfIn).hasUpperLimit() - && sav2 > trafo().parameter(exOfIn).upperLimit() - ) { - sav2 = trafo().parameter(exOfIn).upperLimit() - } - } - var var2: Double = trafo().ext2int(exOfIn, sav2) - val vplu = var2 - `var` - sav2 = sav - werr - if (trafo().parameter(exOfIn).hasLimits()) { - if (trafo().parameter(exOfIn).hasLowerLimit() - && sav2 < trafo().parameter(exOfIn).lowerLimit() - ) { - sav2 = trafo().parameter(exOfIn).lowerLimit() - } - } - var2 = trafo().ext2int(exOfIn, sav2) - val vmin = var2 - `var` - val dirin: Double = 0.5 * (abs(vplu) + abs(vmin)) - val g2: Double = 2.0 * theFcn.errorDef() / (dirin * dirin) - val gsmin: Double = 8.0 * precision().eps2() * (abs(`var`) + precision().eps2()) - var gstep: Double = max(gsmin, 0.1 * dirin) - val grd = g2 * dirin - if (trafo().parameter(exOfIn).hasLimits()) { - if (gstep > 0.5) { - gstep = 0.5 - } - } - gr.setEntry(i, grd) - gr2.setEntry(i, g2) - gst.setEntry(i, gstep) - } - return FunctionGradient(gr, gr2, gst) - } - - fun gradient(par: MinimumParameters, gra: FunctionGradient?): FunctionGradient { - return gradient(par) - } - - fun ncycle(): Int { - return strategy().gradientNCycles() - } - - fun precision(): MnMachinePrecision { - return theTransformation.precision() - } - - fun stepTolerance(): Double { - return strategy().gradientStepTolerance() - } - - fun strategy(): MnStrategy { - return theStrategy - } - - fun trafo(): MnUserTransformation { - return theTransformation - } - - init { - theTransformation = par - theStrategy = stra - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MINOSResult.kt b/kmath-optimization/src/commonMain/tmp/minuit/MINOSResult.kt deleted file mode 100644 index c33994648..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MINOSResult.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package space.kscience.kmath.optimization.minuit - - -/** - * Контейнер для несимметричных оценок и доверительных интервалов - * - * @author Darksnake - * @version $Id: $Id - */ -class MINOSResult -/** - * - * Constructor for MINOSResult. - * - * @param list an array of [String] objects. - */(private val names: Array, private val errl: DoubleArray?, private val errp: DoubleArray?) : - IntervalEstimate { - fun getNames(): NameList { - return NameList(names) - } - - fun getInterval(parName: String?): Pair { - val index: Int = getNames().getNumberByName(parName) - return Pair(ValueFactory.of(errl!![index]), ValueFactory.of(errp!![index])) - } - - val cL: Double - get() = 0.68 - - /** {@inheritDoc} */ - fun print(out: PrintWriter) { - if (errl != null || errp != null) { - out.println() - out.println("Assymetrical errors:") - out.println() - out.println("Name\tLower\tUpper") - for (i in 0 until getNames().size()) { - out.print(getNames().get(i)) - out.print("\t") - if (errl != null) { - out.print(errl[i]) - } else { - out.print("---") - } - out.print("\t") - if (errp != null) { - out.print(errp[i]) - } else { - out.print("---") - } - out.println() - } - } - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MINUITFitter.kt b/kmath-optimization/src/commonMain/tmp/minuit/MINUITFitter.kt deleted file mode 100644 index a26321249..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MINUITFitter.kt +++ /dev/null @@ -1,205 +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.optimization.minuit - -import ru.inr.mass.minuit.* - -/** - * - * - * MINUITFitter class. - * - * @author Darksnake - * @version $Id: $Id - */ -class MINUITFitter : Fitter { - fun run(state: FitState, parentLog: History?, meta: Meta): FitResult { - val log = Chronicle("MINUIT", parentLog) - val action: String = meta.getString("action", TASK_RUN) - log.report("MINUIT fit engine started action '{}'", action) - return when (action) { - TASK_COVARIANCE -> runHesse(state, log, meta) - TASK_SINGLE, TASK_RUN -> runFit(state, log, meta) - else -> throw IllegalArgumentException("Unknown task") - } - } - - @NotNull - fun getName(): String { - return MINUIT_ENGINE_NAME - } - - /** - * - * - * runHesse. - * - * @param state a [hep.dataforge.stat.fit.FitState] object. - * @param log - * @return a [FitResult] object. - */ - fun runHesse(state: FitState, log: History, meta: Meta?): FitResult { - val strategy: Int - strategy = Global.INSTANCE.getInt("MINUIT_STRATEGY", 2) - log.report("Generating errors using MnHesse 2-nd order gradient calculator.") - val fcn: MultiFunction - val fitPars: Array = Fitter.Companion.getFitPars(state, meta) - val pars: ParamSet = state.getParameters() - fcn = MINUITUtils.getFcn(state, pars, fitPars) - val hesse = MnHesse(strategy) - val mnState: MnUserParameterState = hesse.calculate(fcn, MINUITUtils.getFitParameters(pars, fitPars)) - val allPars: ParamSet = pars.copy() - for (fitPar in fitPars) { - allPars.setParValue(fitPar, mnState.value(fitPar)) - allPars.setParError(fitPar, mnState.error(fitPar)) - } - val newState: FitState.Builder = state.edit() - newState.setPars(allPars) - if (mnState.hasCovariance()) { - val mnCov: MnUserCovariance = mnState.covariance() - var j: Int - val cov = Array(mnState.variableParameters()) { DoubleArray(mnState.variableParameters()) } - for (i in 0 until mnState.variableParameters()) { - j = 0 - while (j < mnState.variableParameters()) { - cov[i][j] = mnCov.get(i, j) - j++ - } - } - newState.setCovariance(NamedMatrix(fitPars, cov), true) - } - return FitResult.build(newState.build(), fitPars) - } - - fun runFit(state: FitState, log: History, meta: Meta): FitResult { - val minuit: MnApplication - log.report("Starting fit using Minuit.") - val strategy: Int - strategy = Global.INSTANCE.getInt("MINUIT_STRATEGY", 2) - var force: Boolean - force = Global.INSTANCE.getBoolean("FORCE_DERIVS", false) - val fitPars: Array = Fitter.Companion.getFitPars(state, meta) - for (fitPar in fitPars) { - if (!state.modelProvidesDerivs(fitPar)) { - force = true - log.reportError("Model does not provide derivatives for parameter '{}'", fitPar) - } - } - if (force) { - log.report("Using MINUIT gradient calculator.") - } - val fcn: MultiFunction - val pars: ParamSet = state.getParameters().copy() - fcn = MINUITUtils.getFcn(state, pars, fitPars) - val method: String = meta.getString("method", MINUIT_MIGRAD) - when (method) { - MINUIT_MINOS, MINUIT_MINIMIZE -> minuit = - MnMinimize(fcn, MINUITUtils.getFitParameters(pars, fitPars), strategy) - MINUIT_SIMPLEX -> minuit = MnSimplex(fcn, MINUITUtils.getFitParameters(pars, fitPars), strategy) - else -> minuit = MnMigrad(fcn, MINUITUtils.getFitParameters(pars, fitPars), strategy) - } - if (force) { - minuit.setUseAnalyticalDerivatives(false) - log.report("Forced to use MINUIT internal derivative calculator!") - } - -// minuit.setUseAnalyticalDerivatives(true); - val minimum: FunctionMinimum - val maxSteps: Int = meta.getInt("iterations", -1) - val tolerance: Double = meta.getDouble("tolerance", -1) - minimum = if (maxSteps > 0) { - if (tolerance > 0) { - minuit.minimize(maxSteps, tolerance) - } else { - minuit.minimize(maxSteps) - } - } else { - minuit.minimize() - } - if (!minimum.isValid()) { - log.report("Minimization failed!") - } - log.report("MINUIT run completed in {} function calls.", minimum.nfcn()) - - /* - * Генерация результата - */ - val allPars: ParamSet = pars.copy() - for (fitPar in fitPars) { - allPars.setParValue(fitPar, minimum.userParameters().value(fitPar)) - allPars.setParError(fitPar, minimum.userParameters().error(fitPar)) - } - val newState: FitState.Builder = state.edit() - newState.setPars(allPars) - var valid: Boolean = minimum.isValid() - if (minimum.userCovariance().nrow() > 0) { - var j: Int - val cov = Array(minuit.variableParameters()) { DoubleArray(minuit.variableParameters()) } - if (cov[0].length == 1) { - cov[0][0] = minimum.userParameters().error(0) * minimum.userParameters().error(0) - } else { - for (i in 0 until minuit.variableParameters()) { - j = 0 - while (j < minuit.variableParameters()) { - cov[i][j] = minimum.userCovariance().get(i, j) - j++ - } - } - } - newState.setCovariance(NamedMatrix(fitPars, cov), true) - } - if (method == MINUIT_MINOS) { - log.report("Starting MINOS procedure for precise error estimation.") - val minos = MnMinos(fcn, minimum, strategy) - var mnError: MinosError - val errl = DoubleArray(fitPars.size) - val errp = DoubleArray(fitPars.size) - for (i in fitPars.indices) { - mnError = minos.minos(i) - if (mnError.isValid()) { - errl[i] = mnError.lower() - errp[i] = mnError.upper() - } else { - valid = false - } - } - val minosErrors = MINOSResult(fitPars, errl, errp) - newState.setInterval(minosErrors) - } - return FitResult.build(newState.build(), valid, fitPars) - } - - companion object { - /** - * Constant `MINUIT_MIGRAD="MIGRAD"` - */ - const val MINUIT_MIGRAD = "MIGRAD" - - /** - * Constant `MINUIT_MINIMIZE="MINIMIZE"` - */ - const val MINUIT_MINIMIZE = "MINIMIZE" - - /** - * Constant `MINUIT_SIMPLEX="SIMPLEX"` - */ - const val MINUIT_SIMPLEX = "SIMPLEX" - - /** - * Constant `MINUIT_MINOS="MINOS"` - */ - const val MINUIT_MINOS = "MINOS" //MINOS errors - - /** - * Constant `MINUIT_HESSE="HESSE"` - */ - const val MINUIT_HESSE = "HESSE" //HESSE errors - - /** - * Constant `MINUIT_ENGINE_NAME="MINUIT"` - */ - const val MINUIT_ENGINE_NAME = "MINUIT" - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MINUITPlugin.kt b/kmath-optimization/src/commonMain/tmp/minuit/MINUITPlugin.kt deleted file mode 100644 index 7eaefd9d2..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MINUITPlugin.kt +++ /dev/null @@ -1,86 +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.optimization.minuit - -import hep.dataforge.context.* - -/** - * Мэнеджер для MINUITа. Пока не играет никакой активной роли кроме ведения - * внутреннего лога. - * - * @author Darksnake - * @version $Id: $Id - */ -@PluginDef(group = "hep.dataforge", - name = "MINUIT", - dependsOn = ["hep.dataforge:fitting"], - info = "The MINUIT fitter engine for DataForge fitting") -class MINUITPlugin : BasicPlugin() { - fun attach(@NotNull context: Context?) { - super.attach(context) - clearStaticLog() - } - - @Provides(Fitter.FITTER_TARGET) - fun getFitter(fitterName: String): Fitter? { - return if (fitterName == "MINUIT") { - MINUITFitter() - } else { - null - } - } - - @ProvidesNames(Fitter.FITTER_TARGET) - fun listFitters(): List { - return listOf("MINUIT") - } - - fun detach() { - clearStaticLog() - super.detach() - } - - class Factory : PluginFactory() { - fun build(meta: Meta?): Plugin { - return MINUITPlugin() - } - - fun getType(): java.lang.Class { - return MINUITPlugin::class.java - } - } - - companion object { - /** - * Constant `staticLog` - */ - private val staticLog: Chronicle? = Chronicle("MINUIT-STATIC", Global.INSTANCE.getHistory()) - - /** - * - * - * clearStaticLog. - */ - fun clearStaticLog() { - staticLog.clear() - } - - /** - * - * - * logStatic. - * - * @param str a [String] object. - * @param pars a [Object] object. - */ - fun logStatic(str: String?, vararg pars: Any?) { - checkNotNull(staticLog) { "MINUIT log is not initialized." } - staticLog.report(str, pars) - LoggerFactory.getLogger("MINUIT").info(String.format(str, *pars)) - // Out.out.printf(str,pars); -// Out.out.println(); - } - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MINUITUtils.kt b/kmath-optimization/src/commonMain/tmp/minuit/MINUITUtils.kt deleted file mode 100644 index 44c70cb42..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MINUITUtils.kt +++ /dev/null @@ -1,121 +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.optimization.minuit - -import hep.dataforge.MINUIT.FunctionMinimum - -internal object MINUITUtils { - fun getFcn(source: FitState, allPar: ParamSet, fitPars: Array): MultiFunction { - return MnFunc(source, allPar, fitPars) - } - - fun getFitParameters(set: ParamSet, fitPars: Array): MnUserParameters { - val pars = MnUserParameters() - var i: Int - var par: Param - i = 0 - while (i < fitPars.size) { - par = set.getByName(fitPars[i]) - pars.add(fitPars[i], par.getValue(), par.getErr()) - if (par.getLowerBound() > Double.NEGATIVE_INFINITY && par.getUpperBound() < Double.POSITIVE_INFINITY) { - pars.setLimits(i, par.getLowerBound(), par.getUpperBound()) - } else if (par.getLowerBound() > Double.NEGATIVE_INFINITY) { - pars.setLowerLimit(i, par.getLowerBound()) - } else if (par.getUpperBound() < Double.POSITIVE_INFINITY) { - pars.setUpperLimit(i, par.getUpperBound()) - } - i++ - } - return pars - } - - fun getValueSet(allPar: ParamSet, names: Array, values: DoubleArray): ParamSet { - assert(values.size == names.size) - assert(allPar.getNames().contains(names)) - val vector: ParamSet = allPar.copy() - for (i in values.indices) { - vector.setParValue(names[i], values[i]) - } - return vector - } - - fun isValidArray(ar: DoubleArray): Boolean { - for (i in ar.indices) { - if (java.lang.Double.isNaN(ar[i])) { - return false - } - } - return true - } - - /** - * - * - * printMINUITResult. - * - * @param out a [PrintWriter] object. - * @param minimum a [hep.dataforge.MINUIT.FunctionMinimum] object. - */ - fun printMINUITResult(out: PrintWriter, minimum: FunctionMinimum?) { - out.println() - out.println("***MINUIT INTERNAL FIT INFORMATION***") - out.println() - MnPrint.print(out, minimum) - out.println() - out.println("***END OF MINUIT INTERNAL FIT INFORMATION***") - out.println() - } - - internal class MnFunc(source: FitState, allPar: ParamSet, fitPars: Array) : MultiFunction { - var source: FitState - var allPar: ParamSet - var fitPars: Array - fun value(doubles: DoubleArray): Double { - assert(isValidArray(doubles)) - assert(doubles.size == fitPars.size) - return -2 * source.getLogProb(getValueSet(allPar, fitPars, doubles)) - // source.getChi2(getValueSet(allPar, fitPars, doubles)); - } - - @Throws(NotDefinedException::class) - fun derivValue(n: Int, doubles: DoubleArray): Double { - assert(isValidArray(doubles)) - assert(doubles.size == getDimension()) - val set: ParamSet = getValueSet(allPar, fitPars, doubles) - -// double res; -// double d, s, deriv; -// -// res = 0; -// for (int i = 0; i < source.getDataNum(); i++) { -// d = source.getDis(i, set); -// s = source.getDispersion(i, set); -// if (source.modelProvidesDerivs(fitPars[n])) { -// deriv = source.getDisDeriv(fitPars[n], i, set); -// } else { -// throw new NotDefinedException(); -// // Такого не должно быть, поскольку мы где-то наверху должы были проверить, что производные все есть. -// } -// res += 2 * d * deriv / s; -// } - return -2 * source.getLogProbDeriv(fitPars[n], set) - } - - fun getDimension(): Int { - return fitPars.size - } - - fun providesDeriv(n: Int): Boolean { - return source.modelProvidesDerivs(fitPars[n]) - } - - init { - this.source = source - this.allPar = allPar - this.fitPars = fitPars - assert(source.getModel().getNames().contains(fitPars)) - } - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinimumBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumBuilder.kt deleted file mode 100644 index 7d918c339..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinimumBuilder.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * - * @version $Id$ - */ -interface MinimumBuilder { - /** - * - * minimum. - * - * @param fcn a [hep.dataforge.MINUIT.MnFcn] object. - * @param gc a [hep.dataforge.MINUIT.GradientCalculator] object. - * @param seed a [hep.dataforge.MINUIT.MinimumSeed] object. - * @param strategy a [hep.dataforge.MINUIT.MnStrategy] object. - * @param maxfcn a int. - * @param toler a double. - * @return a [hep.dataforge.MINUIT.FunctionMinimum] object. - */ - fun minimum( - fcn: MnFcn?, - gc: GradientCalculator?, - seed: MinimumSeed?, - strategy: MnStrategy?, - maxfcn: Int, - toler: Double - ): FunctionMinimum -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinimumError.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumError.kt deleted file mode 100644 index 6993b9e6d..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinimumError.kt +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MINUITPlugin - -/** - * MinimumError keeps the inverse 2nd derivative (inverse Hessian) used for - * calculating the parameter step size (-V*g) and for the covariance update - * (ErrorUpdator). The covariance matrix is equal to twice the inverse Hessian. - * - * @version $Id$ - */ -class MinimumError { - private var theAvailable = false - private var theDCovar: Double - private var theHesseFailed = false - private var theInvertFailed = false - private var theMadePosDef = false - private var theMatrix: MnAlgebraicSymMatrix - private var thePosDef = false - private var theValid = false - - constructor(n: Int) { - theMatrix = MnAlgebraicSymMatrix(n) - theDCovar = 1.0 - } - - constructor(mat: MnAlgebraicSymMatrix, dcov: Double) { - theMatrix = mat - theDCovar = dcov - theValid = true - thePosDef = true - theAvailable = true - } - - constructor(mat: MnAlgebraicSymMatrix, x: MnHesseFailed?) { - theMatrix = mat - theDCovar = 1.0 - theValid = false - thePosDef = false - theMadePosDef = false - theHesseFailed = true - theInvertFailed = false - theAvailable = true - } - - constructor(mat: MnAlgebraicSymMatrix, x: MnMadePosDef?) { - theMatrix = mat - theDCovar = 1.0 - theValid = false - thePosDef = false - theMadePosDef = true - theHesseFailed = false - theInvertFailed = false - theAvailable = true - } - - constructor(mat: MnAlgebraicSymMatrix, x: MnInvertFailed?) { - theMatrix = mat - theDCovar = 1.0 - theValid = false - thePosDef = true - theMadePosDef = false - theHesseFailed = false - theInvertFailed = true - theAvailable = true - } - - constructor(mat: MnAlgebraicSymMatrix, x: MnNotPosDef?) { - theMatrix = mat - theDCovar = 1.0 - theValid = false - thePosDef = false - theMadePosDef = false - theHesseFailed = false - theInvertFailed = false - theAvailable = true - } - - fun dcovar(): Double { - return theDCovar - } - - fun hesseFailed(): Boolean { - return theHesseFailed - } - - fun hessian(): MnAlgebraicSymMatrix { - return try { - val tmp: MnAlgebraicSymMatrix = theMatrix.copy() - tmp.invert() - tmp - } catch (x: SingularMatrixException) { - MINUITPlugin.logStatic("BasicMinimumError inversion fails; return diagonal matrix.") - val tmp = MnAlgebraicSymMatrix(theMatrix.nrow()) - var i = 0 - while (i < theMatrix.nrow()) { - tmp[i, i] = 1.0 / theMatrix[i, i] - i++ - } - tmp - } - } - - fun invHessian(): MnAlgebraicSymMatrix { - return theMatrix - } - - fun invertFailed(): Boolean { - return theInvertFailed - } - - fun isAccurate(): Boolean { - return theDCovar < 0.1 - } - - fun isAvailable(): Boolean { - return theAvailable - } - - fun isMadePosDef(): Boolean { - return theMadePosDef - } - - fun isPosDef(): Boolean { - return thePosDef - } - - fun isValid(): Boolean { - return theValid - } - - fun matrix(): MnAlgebraicSymMatrix { - return MnUtils.mul(theMatrix, 2) - } - - internal class MnHesseFailed - internal class MnInvertFailed - internal class MnMadePosDef - internal class MnNotPosDef -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinimumErrorUpdator.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumErrorUpdator.kt deleted file mode 100644 index 6022aa5b7..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinimumErrorUpdator.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal interface MinimumErrorUpdator { - /** - * - * update. - * - * @param state a [hep.dataforge.MINUIT.MinimumState] object. - * @param par a [hep.dataforge.MINUIT.MinimumParameters] object. - * @param grad a [hep.dataforge.MINUIT.FunctionGradient] object. - * @return a [hep.dataforge.MINUIT.MinimumError] object. - */ - fun update(state: MinimumState?, par: MinimumParameters?, grad: FunctionGradient?): MinimumError? -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinimumParameters.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumParameters.kt deleted file mode 100644 index bed13ea0b..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinimumParameters.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector - -/** - * - * @version $Id$ - */ -class MinimumParameters { - private var theFVal = 0.0 - private var theHasStep = false - private var theParameters: RealVector - private var theStepSize: RealVector - private var theValid = false - - constructor(n: Int) { - theParameters = ArrayRealVector(n) - theStepSize = ArrayRealVector(n) - } - - constructor(avec: RealVector, fval: Double) { - theParameters = avec - theStepSize = ArrayRealVector(avec.getDimension()) - theFVal = fval - theValid = true - } - - constructor(avec: RealVector, dirin: RealVector, fval: Double) { - theParameters = avec - theStepSize = dirin - theFVal = fval - theValid = true - theHasStep = true - } - - fun dirin(): RealVector { - return theStepSize - } - - fun fval(): Double { - return theFVal - } - - fun hasStepSize(): Boolean { - return theHasStep - } - - fun isValid(): Boolean { - return theValid - } - - fun vec(): RealVector { - return theParameters - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinimumSeed.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumSeed.kt deleted file mode 100644 index 53a78da75..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinimumSeed.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package space.kscience.kmath.optimization.minuit - -import ru.inr.mass.minuit.* - -/** - * - * @version $Id$ - */ -class MinimumSeed(state: MinimumState, trafo: MnUserTransformation) { - private val theState: MinimumState = state - private val theTrafo: MnUserTransformation = trafo - private val theValid: Boolean = true - val edm: Double get() = state().edm() - - fun error(): MinimumError { - return state().error() - } - - fun fval(): Double { - return state().fval() - } - - fun gradient(): FunctionGradient { - return state().gradient() - } - - fun isValid(): Boolean { - return theValid - } - - fun nfcn(): Int { - return state().nfcn() - } - - fun parameters(): MinimumParameters { - return state().parameters() - } - - fun precision(): MnMachinePrecision { - return theTrafo.precision() - } - - fun state(): MinimumState { - return theState - } - - fun trafo(): MnUserTransformation { - return theTrafo - } - -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinimumSeedGenerator.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumSeedGenerator.kt deleted file mode 100644 index e152559b5..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinimumSeedGenerator.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * base class for seed generators (starting values); the seed generator prepares - * initial starting values from the input (MnUserParameterState) for the - * minimization; - * - * @version $Id$ - */ -interface MinimumSeedGenerator { - /** - * - * generate. - * - * @param fcn a [hep.dataforge.MINUIT.MnFcn] object. - * @param calc a [hep.dataforge.MINUIT.GradientCalculator] object. - * @param user a [hep.dataforge.MINUIT.MnUserParameterState] object. - * @param stra a [hep.dataforge.MINUIT.MnStrategy] object. - * @return a [hep.dataforge.MINUIT.MinimumSeed] object. - */ - fun generate(fcn: MnFcn?, calc: GradientCalculator?, user: MnUserParameterState?, stra: MnStrategy?): MinimumSeed -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinimumState.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinimumState.kt deleted file mode 100644 index 9f63e0e1f..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinimumState.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.RealVector - -/** - * MinimumState keeps the information (position, gradient, 2nd deriv, etc) after - * one minimization step (usually in MinimumBuilder). - * - * @version $Id$ - */ -class MinimumState { - private var theEDM = 0.0 - private var theError: MinimumError - private var theGradient: FunctionGradient - private var theNFcn = 0 - private var theParameters: MinimumParameters - - constructor(n: Int) { - theParameters = MinimumParameters(n) - theError = MinimumError(n) - theGradient = FunctionGradient(n) - } - - constructor(states: MinimumParameters, err: MinimumError, grad: FunctionGradient, edm: Double, nfcn: Int) { - theParameters = states - theError = err - theGradient = grad - theEDM = edm - theNFcn = nfcn - } - - constructor(states: MinimumParameters, edm: Double, nfcn: Int) { - theParameters = states - theError = MinimumError(states.vec().getDimension()) - theGradient = FunctionGradient(states.vec().getDimension()) - theEDM = edm - theNFcn = nfcn - } - - fun edm(): Double { - return theEDM - } - - fun error(): MinimumError { - return theError - } - - fun fval(): Double { - return theParameters.fval() - } - - fun gradient(): FunctionGradient { - return theGradient - } - - fun hasCovariance(): Boolean { - return theError.isAvailable() - } - - fun hasParameters(): Boolean { - return theParameters.isValid() - } - - fun isValid(): Boolean { - return if (hasParameters() && hasCovariance()) { - parameters().isValid() && error().isValid() - } else if (hasParameters()) { - parameters().isValid() - } else { - false - } - } - - fun nfcn(): Int { - return theNFcn - } - - fun parameters(): MinimumParameters { - return theParameters - } - - fun size(): Int { - return theParameters.vec().getDimension() - } - - fun vec(): RealVector { - return theParameters.vec() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinosError.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinosError.kt deleted file mode 100644 index c7cf10523..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinosError.kt +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * MinosError class. - * - * @author Darksnake - * @version $Id$ - */ -class MinosError { - private var theLower: MnCross - private var theMinValue = 0.0 - private var theParameter = 0 - private var theUpper: MnCross - - internal constructor() { - theUpper = MnCross() - theLower = MnCross() - } - - internal constructor(par: Int, min: Double, low: MnCross, up: MnCross) { - theParameter = par - theMinValue = min - theUpper = up - theLower = low - } - - /** - * - * atLowerLimit. - * - * @return a boolean. - */ - fun atLowerLimit(): Boolean { - return theLower.atLimit() - } - - /** - * - * atLowerMaxFcn. - * - * @return a boolean. - */ - fun atLowerMaxFcn(): Boolean { - return theLower.atMaxFcn() - } - - /** - * - * atUpperLimit. - * - * @return a boolean. - */ - fun atUpperLimit(): Boolean { - return theUpper.atLimit() - } - - /** - * - * atUpperMaxFcn. - * - * @return a boolean. - */ - fun atUpperMaxFcn(): Boolean { - return theUpper.atMaxFcn() - } - - /** - * - * isValid. - * - * @return a boolean. - */ - fun isValid(): Boolean { - return theLower.isValid() && theUpper.isValid() - } - - /** - * - * lower. - * - * @return a double. - */ - fun lower(): Double { - return -1.0 * lowerState().error(parameter()) * (1.0 + theLower.value()) - } - - /** - * - * lowerNewMin. - * - * @return a boolean. - */ - fun lowerNewMin(): Boolean { - return theLower.newMinimum() - } - - /** - * - * lowerState. - * - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun lowerState(): MnUserParameterState { - return theLower.state() - } - - /** - * - * lowerValid. - * - * @return a boolean. - */ - fun lowerValid(): Boolean { - return theLower.isValid() - } - - /** - * - * min. - * - * @return a double. - */ - fun min(): Double { - return theMinValue - } - - /** - * - * nfcn. - * - * @return a int. - */ - fun nfcn(): Int { - return theUpper.nfcn() + theLower.nfcn() - } - - /** - * - * parameter. - * - * @return a int. - */ - fun parameter(): Int { - return theParameter - } - - /** - * - * range. - * - * @return - */ - fun range(): Range { - return Range(lower(), upper()) - } - - /** - * {@inheritDoc} - */ - override fun toString(): String { - return MnPrint.toString(this) - } - - /** - * - * upper. - * - * @return a double. - */ - fun upper(): Double { - return upperState().error(parameter()) * (1.0 + theUpper.value()) - } - - /** - * - * upperNewMin. - * - * @return a boolean. - */ - fun upperNewMin(): Boolean { - return theUpper.newMinimum() - } - - /** - * - * upperState. - * - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun upperState(): MnUserParameterState { - return theUpper.state() - } - - /** - * - * upperValid. - * - * @return a boolean. - */ - fun upperValid(): Boolean { - return theUpper.isValid() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MinuitParameter.kt b/kmath-optimization/src/commonMain/tmp/minuit/MinuitParameter.kt deleted file mode 100644 index ff6834df4..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MinuitParameter.kt +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -class MinuitParameter { - private var theConst = false - private var theError = 0.0 - private var theFix = false - private var theLoLimValid = false - private var theLoLimit = 0.0 - private var theName: String - private var theNum: Int - private var theUpLimValid = false - private var theUpLimit = 0.0 - private var theValue: Double - - /** - * constructor for constant parameter - * - * @param num a int. - * @param name a [String] object. - * @param val a double. - */ - constructor(num: Int, name: String, `val`: Double) { - theNum = num - theValue = `val` - theConst = true - theName = name - } - - /** - * constructor for standard parameter - * - * @param num a int. - * @param name a [String] object. - * @param val a double. - * @param err a double. - */ - constructor(num: Int, name: String, `val`: Double, err: Double) { - theNum = num - theValue = `val` - theError = err - theName = name - } - - /** - * constructor for limited parameter - * - * @param num a int. - * @param name a [String] object. - * @param val a double. - * @param err a double. - * @param min a double. - * @param max a double. - */ - constructor(num: Int, name: String, `val`: Double, err: Double, min: Double, max: Double) { - theNum = num - theValue = `val` - theError = err - theLoLimit = min - theUpLimit = max - theLoLimValid = true - theUpLimValid = true - require(min != max) { "min == max" } - if (min > max) { - theLoLimit = max - theUpLimit = min - } - theName = name - } - - private constructor(other: MinuitParameter) { - theNum = other.theNum - theName = other.theName - theValue = other.theValue - theError = other.theError - theConst = other.theConst - theFix = other.theFix - theLoLimit = other.theLoLimit - theUpLimit = other.theUpLimit - theLoLimValid = other.theLoLimValid - theUpLimValid = other.theUpLimValid - } - - /** - * - * copy. - * - * @return a [hep.dataforge.MINUIT.MinuitParameter] object. - */ - fun copy(): MinuitParameter { - return MinuitParameter(this) - } - - /** - * - * error. - * - * @return a double. - */ - fun error(): Double { - return theError - } - - /** - * - * fix. - */ - fun fix() { - theFix = true - } - - /** - * - * hasLimits. - * - * @return a boolean. - */ - fun hasLimits(): Boolean { - return theLoLimValid || theUpLimValid - } - - /** - * - * hasLowerLimit. - * - * @return a boolean. - */ - fun hasLowerLimit(): Boolean { - return theLoLimValid - } - - /** - * - * hasUpperLimit. - * - * @return a boolean. - */ - fun hasUpperLimit(): Boolean { - return theUpLimValid - } - //state of parameter (fixed/const/limited) - /** - * - * isConst. - * - * @return a boolean. - */ - fun isConst(): Boolean { - return theConst - } - - /** - * - * isFixed. - * - * @return a boolean. - */ - fun isFixed(): Boolean { - return theFix - } - - /** - * - * lowerLimit. - * - * @return a double. - */ - fun lowerLimit(): Double { - return theLoLimit - } - - /** - * - * name. - * - * @return a [String] object. - */ - fun name(): String { - return theName - } - //access methods - /** - * - * number. - * - * @return a int. - */ - fun number(): Int { - return theNum - } - - /** - * - * release. - */ - fun release() { - theFix = false - } - - /** - * - * removeLimits. - */ - fun removeLimits() { - theLoLimit = 0.0 - theUpLimit = 0.0 - theLoLimValid = false - theUpLimValid = false - } - - /** - * - * setError. - * - * @param err a double. - */ - fun setError(err: Double) { - theError = err - theConst = false - } - - /** - * - * setLimits. - * - * @param low a double. - * @param up a double. - */ - fun setLimits(low: Double, up: Double) { - require(low != up) { "min == max" } - theLoLimit = low - theUpLimit = up - theLoLimValid = true - theUpLimValid = true - if (low > up) { - theLoLimit = up - theUpLimit = low - } - } - - /** - * - * setLowerLimit. - * - * @param low a double. - */ - fun setLowerLimit(low: Double) { - theLoLimit = low - theUpLimit = 0.0 - theLoLimValid = true - theUpLimValid = false - } - - /** - * - * setUpperLimit. - * - * @param up a double. - */ - fun setUpperLimit(up: Double) { - theLoLimit = 0.0 - theUpLimit = up - theLoLimValid = false - theUpLimValid = true - } - //interaction - /** - * - * setValue. - * - * @param val a double. - */ - fun setValue(`val`: Double) { - theValue = `val` - } - - /** - * - * upperLimit. - * - * @return a double. - */ - fun upperLimit(): Double { - return theUpLimit - } - - /** - * - * value. - * - * @return a double. - */ - fun value(): Double { - return theValue - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnAlgebraicSymMatrix.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnAlgebraicSymMatrix.kt deleted file mode 100644 index 4b75858e1..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnAlgebraicSymMatrix.kt +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector - -/** - * - * @version $Id$ - */ -class MnAlgebraicSymMatrix(n: Int) { - private val theData: DoubleArray - private val theNRow: Int - private val theSize: Int - - /** - * - * copy. - * - * @return a [hep.dataforge.MINUIT.MnAlgebraicSymMatrix] object. - */ - fun copy(): MnAlgebraicSymMatrix { - val copy = MnAlgebraicSymMatrix(theNRow) - java.lang.System.arraycopy(theData, 0, copy.theData, 0, theSize) - return copy - } - - fun data(): DoubleArray { - return theData - } - - fun eigenvalues(): ArrayRealVector { - val nrow = theNRow - val tmp = DoubleArray((nrow + 1) * (nrow + 1)) - val work = DoubleArray(1 + 2 * nrow) - for (i in 0 until nrow) { - for (j in 0..i) { - tmp[1 + i + (1 + j) * nrow] = get(i, j) - tmp[(1 + i) * nrow + (1 + j)] = get(i, j) - } - } - val info = mneigen(tmp, nrow, nrow, work.size, work, 1e-6) - if (info != 0) { - throw EigenvaluesException() - } - val result = ArrayRealVector(nrow) - for (i in 0 until nrow) { - result.setEntry(i, work[1 + i]) - } - return result - } - - operator fun get(row: Int, col: Int): Double { - if (row >= theNRow || col >= theNRow) { - throw ArrayIndexOutOfBoundsException() - } - return theData[theIndex(row, col)] - } - - @Throws(SingularMatrixException::class) - fun invert() { - if (theSize == 1) { - val tmp = theData[0] - if (tmp <= 0.0) { - throw SingularMatrixException() - } - theData[0] = 1.0 / tmp - } else { - val nrow = theNRow - val s = DoubleArray(nrow) - val q = DoubleArray(nrow) - val pp = DoubleArray(nrow) - for (i in 0 until nrow) { - val si = theData[theIndex(i, i)] - if (si < 0.0) { - throw SingularMatrixException() - } - s[i] = 1.0 / sqrt(si) - } - for (i in 0 until nrow) { - for (j in i until nrow) { - theData[theIndex(i, j)] *= s[i] * s[j] - } - } - for (i in 0 until nrow) { - var k = i - if (theData[theIndex(k, k)] == 0.0) { - throw SingularMatrixException() - } - q[k] = 1.0 / theData[theIndex(k, k)] - pp[k] = 1.0 - theData[theIndex(k, k)] = 0.0 - val kp1 = k + 1 - if (k != 0) { - for (j in 0 until k) { - val index = theIndex(j, k) - pp[j] = theData[index] - q[j] = theData[index] * q[k] - theData[index] = 0.0 - } - } - if (k != nrow - 1) { - for (j in kp1 until nrow) { - val index = theIndex(k, j) - pp[j] = theData[index] - q[j] = -theData[index] * q[k] - theData[index] = 0.0 - } - } - for (j in 0 until nrow) { - k = j - while (k < nrow) { - theData[theIndex(j, k)] += pp[j] * q[k] - k++ - } - } - } - for (j in 0 until nrow) { - for (k in j until nrow) { - theData[theIndex(j, k)] *= s[j] * s[k] - } - } - } - } - - fun ncol(): Int { - return nrow() - } - - fun nrow(): Int { - return theNRow - } - - operator fun set(row: Int, col: Int, value: Double) { - if (row >= theNRow || col >= theNRow) { - throw ArrayIndexOutOfBoundsException() - } - theData[theIndex(row, col)] = value - } - - fun size(): Int { - return theSize - } - - private fun theIndex(row: Int, col: Int): Int { - return if (row > col) { - col + row * (row + 1) / 2 - } else { - row + col * (col + 1) / 2 - } - } - - /** {@inheritDoc} */ - override fun toString(): String { - return MnPrint.toString(this) - } /* mneig_ */ - - private inner class EigenvaluesException : RuntimeException() - companion object { - private fun mneigen(a: DoubleArray, ndima: Int, n: Int, mits: Int, work: DoubleArray, precis: Double): Int { - - /* System generated locals */ - var i__2: Int - var i__3: Int - - /* Local variables */ - var b: Double - var c__: Double - var f: Double - var h__: Double - var i__: Int - var j: Int - var k: Int - var l: Int - var m = 0 - var r__: Double - var s: Double - var i0: Int - var i1: Int - var j1: Int - var m1: Int - var hh: Double - var gl: Double - var pr: Double - var pt: Double - - /* PRECIS is the machine precision EPSMAC */ - /* Parameter adjustments */ - val a_dim1: Int = ndima - val a_offset: Int = 1 + a_dim1 * 1 - - /* Function Body */ - var ifault = 1 - i__ = n - var i__1: Int = n - i1 = 2 - while (i1 <= i__1) { - l = i__ - 2 - f = a[i__ + (i__ - 1) * a_dim1] - gl = 0.0 - if (l >= 1) { - i__2 = l - k = 1 - while (k <= i__2) { - - /* Computing 2nd power */ - val r__1 = a[i__ + k * a_dim1] - gl += r__1 * r__1 - ++k - } - } - /* Computing 2nd power */h__ = gl + f * f - if (gl <= 1e-35) { - work[i__] = 0.0 - work[n + i__] = f - } else { - ++l - gl = sqrt(h__) - if (f >= 0.0) { - gl = -gl - } - work[n + i__] = gl - h__ -= f * gl - a[i__ + (i__ - 1) * a_dim1] = f - gl - f = 0.0 - i__2 = l - j = 1 - while (j <= i__2) { - a[j + i__ * a_dim1] = a[i__ + j * a_dim1] / h__ - gl = 0.0 - i__3 = j - k = 1 - while (k <= i__3) { - gl += a[j + k * a_dim1] * a[i__ + k * a_dim1] - ++k - } - if (j < l) { - j1 = j + 1 - i__3 = l - k = j1 - while (k <= i__3) { - gl += a[k + j * a_dim1] * a[i__ + k * a_dim1] - ++k - } - } - work[n + j] = gl / h__ - f += gl * a[j + i__ * a_dim1] - ++j - } - hh = f / (h__ + h__) - i__2 = l - j = 1 - while (j <= i__2) { - f = a[i__ + j * a_dim1] - gl = work[n + j] - hh * f - work[n + j] = gl - i__3 = j - k = 1 - while (k <= i__3) { - a[j + k * a_dim1] = a[j + k * a_dim1] - f * work[n + k] - (gl - * a[i__ + k * a_dim1]) - ++k - } - ++j - } - work[i__] = h__ - } - --i__ - ++i1 - } - work[1] = 0.0 - work[n + 1] = 0.0 - i__1 = n - i__ = 1 - while (i__ <= i__1) { - l = i__ - 1 - if (work[i__] != 0.0 && l != 0) { - i__3 = l - j = 1 - while (j <= i__3) { - gl = 0.0 - i__2 = l - k = 1 - while (k <= i__2) { - gl += a[i__ + k * a_dim1] * a[k + j * a_dim1] - ++k - } - i__2 = l - k = 1 - while (k <= i__2) { - a[k + j * a_dim1] -= gl * a[k + i__ * a_dim1] - ++k - } - ++j - } - } - work[i__] = a[i__ + i__ * a_dim1] - a[i__ + i__ * a_dim1] = 1.0 - if (l != 0) { - i__2 = l - j = 1 - while (j <= i__2) { - a[i__ + j * a_dim1] = 0.0 - a[j + i__ * a_dim1] = 0.0 - ++j - } - } - ++i__ - } - val n1: Int = n - 1 - i__1 = n - i__ = 2 - while (i__ <= i__1) { - i0 = n + i__ - 1 - work[i0] = work[i0 + 1] - ++i__ - } - work[n + n] = 0.0 - b = 0.0 - f = 0.0 - i__1 = n - l = 1 - while (l <= i__1) { - j = 0 - h__ = precis * (abs(work[l]) + abs(work[n + l])) - if (b < h__) { - b = h__ - } - i__2 = n - m1 = l - while (m1 <= i__2) { - m = m1 - if (abs(work[n + m]) <= b) { - break - } - ++m1 - } - if (m != l) { - while (true) { - if (j == mits) { - return ifault - } - ++j - pt = (work[l + 1] - work[l]) / (work[n + l] * 2.0) - r__ = sqrt(pt * pt + 1.0) - pr = pt + r__ - if (pt < 0.0) { - pr = pt - r__ - } - h__ = work[l] - work[n + l] / pr - i__2 = n - i__ = l - while (i__ <= i__2) { - work[i__] -= h__ - ++i__ - } - f += h__ - pt = work[m] - c__ = 1.0 - s = 0.0 - m1 = m - 1 - i__ = m - i__2 = m1 - i1 = l - while (i1 <= i__2) { - j = i__ - --i__ - gl = c__ * work[n + i__] - h__ = c__ * pt - if (abs(pt) < abs(work[n + i__])) { - c__ = pt / work[n + i__] - r__ = sqrt(c__ * c__ + 1.0) - work[n + j] = s * work[n + i__] * r__ - s = 1.0 / r__ - c__ /= r__ - } else { - c__ = work[n + i__] / pt - r__ = sqrt(c__ * c__ + 1.0) - work[n + j] = s * pt * r__ - s = c__ / r__ - c__ = 1.0 / r__ - } - pt = c__ * work[i__] - s * gl - work[j] = h__ + s * (c__ * gl + s * work[i__]) - i__3 = n - k = 1 - while (k <= i__3) { - h__ = a[k + j * a_dim1] - a[k + j * a_dim1] = s * a[k + i__ * a_dim1] + c__ * h__ - a[k + i__ * a_dim1] = c__ * a[k + i__ * a_dim1] - s * h__ - ++k - } - ++i1 - } - work[n + l] = s * pt - work[l] = c__ * pt - if (abs(work[n + l]) <= b) { - break - } - } - } - work[l] += f - ++l - } - i__1 = n1 - i__ = 1 - while (i__ <= i__1) { - k = i__ - pt = work[i__] - i1 = i__ + 1 - i__3 = n - j = i1 - while (j <= i__3) { - if (work[j] < pt) { - k = j - pt = work[j] - } - ++j - } - if (k != i__) { - work[k] = work[i__] - work[i__] = pt - i__3 = n - j = 1 - while (j <= i__3) { - pt = a[j + i__ * a_dim1] - a[j + i__ * a_dim1] = a[j + k * a_dim1] - a[j + k * a_dim1] = pt - ++j - } - } - ++i__ - } - ifault = 0 - return ifault - } /* mneig_ */ - } - - init { - require(n >= 0) { "Invalid matrix size: $n" } - theSize = n * (n + 1) / 2 - theNRow = n - theData = DoubleArray(theSize) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnApplication.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnApplication.kt deleted file mode 100644 index 025eea4ae..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnApplication.kt +++ /dev/null @@ -1,554 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* - -/** - * Base class for minimizers. - * - * @version $Id$ - * @author Darksnake - */ -abstract class MnApplication { - /* package protected */ - var checkAnalyticalDerivatives: Boolean - - /* package protected */ /* package protected */ - var theErrorDef = 1.0 /* package protected */ - var theFCN: MultiFunction? - - /* package protected */ /* package protected */ - var theNumCall /* package protected */ = 0 - var theState: MnUserParameterState - - /* package protected */ - var theStrategy: MnStrategy - - /* package protected */ - var useAnalyticalDerivatives: Boolean - - /* package protected */ - internal constructor(fcn: MultiFunction?, state: MnUserParameterState, stra: MnStrategy) { - theFCN = fcn - theState = state - theStrategy = stra - checkAnalyticalDerivatives = true - useAnalyticalDerivatives = true - } - - internal constructor(fcn: MultiFunction?, state: MnUserParameterState, stra: MnStrategy, nfcn: Int) { - theFCN = fcn - theState = state - theStrategy = stra - theNumCall = nfcn - checkAnalyticalDerivatives = true - useAnalyticalDerivatives = true - } - - /** - * - * MultiFunction. - * - * @return a [MultiFunction] object. - */ - fun MultiFunction(): MultiFunction? { - return theFCN - } - - /** - * add free parameter - * - * @param err a double. - * @param val a double. - * @param name a [String] object. - */ - fun add(name: String, `val`: Double, err: Double) { - theState.add(name, `val`, err) - } - - /** - * add limited parameter - * - * @param up a double. - * @param low a double. - * @param name a [String] object. - * @param val a double. - * @param err a double. - */ - fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) { - theState.add(name, `val`, err, low, up) - } - - /** - * add const parameter - * - * @param name a [String] object. - * @param val a double. - */ - fun add(name: String, `val`: Double) { - theState.add(name, `val`) - } - - /** - * - * checkAnalyticalDerivatives. - * - * @return a boolean. - */ - fun checkAnalyticalDerivatives(): Boolean { - return checkAnalyticalDerivatives - } - - /** - * - * covariance. - * - * @return a [hep.dataforge.MINUIT.MnUserCovariance] object. - */ - fun covariance(): MnUserCovariance { - return theState.covariance() - } - - /** - * - * error. - * - * @param index a int. - * @return a double. - */ - fun error(index: Int): Double { - return theState.error(index) - } - - /** - * - * error. - * - * @param name a [String] object. - * @return a double. - */ - fun error(name: String?): Double { - return theState.error(name) - } - - /** - * - * errorDef. - * - * @return a double. - */ - fun errorDef(): Double { - return theErrorDef - } - - /** - * - * errors. - * - * @return an array of double. - */ - fun errors(): DoubleArray { - return theState.errors() - } - - fun ext2int(i: Int, value: Double): Double { - return theState.ext2int(i, value) - } - - fun extOfInt(i: Int): Int { - return theState.extOfInt(i) - } - //interaction via external number of parameter - /** - * - * fix. - * - * @param index a int. - */ - fun fix(index: Int) { - theState.fix(index) - } - //interaction via name of parameter - /** - * - * fix. - * - * @param name a [String] object. - */ - fun fix(name: String?) { - theState.fix(name) - } - - /** - * convert name into external number of parameter - * - * @param name a [String] object. - * @return a int. - */ - fun index(name: String?): Int { - return theState.index(name) - } - - // transformation internal <-> external - fun int2ext(i: Int, value: Double): Double { - return theState.int2ext(i, value) - } - - fun intOfExt(i: Int): Int { - return theState.intOfExt(i) - } - - /** - * - * minimize. - * - * @return a [hep.dataforge.MINUIT.FunctionMinimum] object. - */ - fun minimize(): FunctionMinimum { - return minimize(DEFAULT_MAXFCN) - } - - /** - * - * minimize. - * - * @param maxfcn a int. - * @return a [hep.dataforge.MINUIT.FunctionMinimum] object. - */ - fun minimize(maxfcn: Int): FunctionMinimum { - return minimize(maxfcn, DEFAULT_TOLER) - } - - /** - * Causes minimization of the FCN and returns the result in form of a - * FunctionMinimum. - * - * @param maxfcn specifies the (approximate) maximum number of function - * calls after which the calculation will be stopped even if it has not yet - * converged. - * @param toler specifies the required tolerance on the function value at - * the minimum. The default tolerance value is 0.1, and the minimization - * will stop when the estimated vertical distance to the minimum (EDM) is - * less than 0:001*tolerance*errorDef - * @return a [hep.dataforge.MINUIT.FunctionMinimum] object. - */ - fun minimize(maxfcn: Int, toler: Double): FunctionMinimum { - var maxfcn = maxfcn - check(theState.isValid()) { "Invalid state" } - val npar = variableParameters() - if (maxfcn == 0) { - maxfcn = 200 + 100 * npar + 5 * npar * npar - } - val min: FunctionMinimum = minimizer().minimize(theFCN, - theState, - theStrategy, - maxfcn, - toler, - theErrorDef, - useAnalyticalDerivatives, - checkAnalyticalDerivatives) - theNumCall += min.nfcn() - theState = min.userState() - return min - } - - abstract fun minimizer(): ModularFunctionMinimizer - - // facade: forward interface of MnUserParameters and MnUserTransformation - fun minuitParameters(): List { - return theState.minuitParameters() - } - - /** - * convert external number into name of parameter - * - * @param index a int. - * @return a [String] object. - */ - fun name(index: Int): String { - return theState.name(index) - } - - /** - * - * numOfCalls. - * - * @return a int. - */ - fun numOfCalls(): Int { - return theNumCall - } - - /** - * access to single parameter - * @param i - * @return - */ - fun parameter(i: Int): MinuitParameter { - return theState.parameter(i) - } - - /** - * - * parameters. - * - * @return a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - fun parameters(): MnUserParameters { - return theState.parameters() - } - - /** - * access to parameters and errors in column-wise representation - * - * @return an array of double. - */ - fun params(): DoubleArray { - return theState.params() - } - - /** - * - * precision. - * - * @return a [hep.dataforge.MINUIT.MnMachinePrecision] object. - */ - fun precision(): MnMachinePrecision { - return theState.precision() - } - - /** - * - * release. - * - * @param index a int. - */ - fun release(index: Int) { - theState.release(index) - } - - /** - * - * release. - * - * @param name a [String] object. - */ - fun release(name: String?) { - theState.release(name) - } - - /** - * - * removeLimits. - * - * @param index a int. - */ - fun removeLimits(index: Int) { - theState.removeLimits(index) - } - - /** - * - * removeLimits. - * - * @param name a [String] object. - */ - fun removeLimits(name: String?) { - theState.removeLimits(name) - } - - /** - * Minuit does a check of the user gradient at the beginning, if this is not - * wanted the set this to "false". - * - * @param check a boolean. - */ - fun setCheckAnalyticalDerivatives(check: Boolean) { - checkAnalyticalDerivatives = check - } - - /** - * - * setError. - * - * @param index a int. - * @param err a double. - */ - fun setError(index: Int, err: Double) { - theState.setError(index, err) - } - - /** - * - * setError. - * - * @param name a [String] object. - * @param err a double. - */ - fun setError(name: String?, err: Double) { - theState.setError(name, err) - } - - /** - * errorDef() is the error definition of the function. E.g. is 1 if function - * is Chi2 and 0.5 if function is -logLikelihood. If the user wants instead - * the 2-sigma errors, errorDef() = 4, as Chi2(x+n*sigma) = Chi2(x) + n*n. - * - * @param errorDef a double. - */ - fun setErrorDef(errorDef: Double) { - theErrorDef = errorDef - } - - /** - * - * setLimits. - * - * @param index a int. - * @param low a double. - * @param up a double. - */ - fun setLimits(index: Int, low: Double, up: Double) { - theState.setLimits(index, low, up) - } - - /** - * - * setLimits. - * - * @param name a [String] object. - * @param low a double. - * @param up a double. - */ - fun setLimits(name: String?, low: Double, up: Double) { - theState.setLimits(name, low, up) - } - - /** - * - * setPrecision. - * - * @param prec a double. - */ - fun setPrecision(prec: Double) { - theState.setPrecision(prec) - } - - /** - * By default if the function to be minimized implements MultiFunction then - * the analytical gradient provided by the function will be used. Set this - * to - * false to disable this behaviour and force numerical - * calculation of the gradient. - * - * @param use a boolean. - */ - fun setUseAnalyticalDerivatives(use: Boolean) { - useAnalyticalDerivatives = use - } - - /** - * - * setValue. - * - * @param index a int. - * @param val a double. - */ - fun setValue(index: Int, `val`: Double) { - theState.setValue(index, `val`) - } - - /** - * - * setValue. - * - * @param name a [String] object. - * @param val a double. - */ - fun setValue(name: String?, `val`: Double) { - theState.setValue(name, `val`) - } - - /** - * - * state. - * - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun state(): MnUserParameterState { - return theState - } - - /** - * - * strategy. - * - * @return a [hep.dataforge.MINUIT.MnStrategy] object. - */ - fun strategy(): MnStrategy { - return theStrategy - } - - /** - * - * useAnalyticalDerivaties. - * - * @return a boolean. - */ - fun useAnalyticalDerivaties(): Boolean { - return useAnalyticalDerivatives - } - - /** - * - * value. - * - * @param index a int. - * @return a double. - */ - fun value(index: Int): Double { - return theState.value(index) - } - - /** - * - * value. - * - * @param name a [String] object. - * @return a double. - */ - fun value(name: String?): Double { - return theState.value(name) - } - - /** - * - * variableParameters. - * - * @return a int. - */ - fun variableParameters(): Int { - return theState.variableParameters() - } - - companion object { - var DEFAULT_MAXFCN = 0 - var DEFAULT_STRATEGY = 1 - var DEFAULT_TOLER = 0.1 - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnContours.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnContours.kt deleted file mode 100644 index 1b700f4e2..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnContours.kt +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* - -/** - * API class for Contours error analysis (2-dim errors). Minimization has to be - * done before and minimum must be valid. Possibility to ask only for the points - * or the points and associated Minos errors. - * - * @version $Id$ - * @author Darksnake - */ -class MnContours(fcn: MultiFunction?, min: FunctionMinimum?, stra: MnStrategy?) { - private var theFCN: MultiFunction? = null - private var theMinimum: FunctionMinimum? = null - private var theStrategy: MnStrategy? = null - - /** - * construct from FCN + minimum - * - * @param fcn a [MultiFunction] object. - * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. - */ - constructor(fcn: MultiFunction?, min: FunctionMinimum?) : this(fcn, min, MnApplication.DEFAULT_STRATEGY) - - /** - * construct from FCN + minimum + strategy - * - * @param stra a int. - * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, min: FunctionMinimum?, stra: Int) : this(fcn, min, MnStrategy(stra)) - - /** - * - * contour. - * - * @param px a int. - * @param py a int. - * @return a [hep.dataforge.MINUIT.ContoursError] object. - */ - fun contour(px: Int, py: Int): ContoursError { - return contour(px, py, 1.0) - } - - /** - * - * contour. - * - * @param px a int. - * @param py a int. - * @param errDef a double. - * @return a [hep.dataforge.MINUIT.ContoursError] object. - */ - fun contour(px: Int, py: Int, errDef: Double): ContoursError { - return contour(px, py, errDef, 20) - } - - /** - * Causes a CONTOURS error analysis and returns the result in form of - * ContoursError. As a by-product ContoursError keeps the MinosError - * information of parameters parx and pary. The result ContoursError can be - * easily printed using MnPrint or toString(). - * - * @param npoints a int. - * @param px a int. - * @param py a int. - * @param errDef a double. - * @return a [hep.dataforge.MINUIT.ContoursError] object. - */ - fun contour(px: Int, py: Int, errDef: Double, npoints: Int): ContoursError { - var errDef = errDef - errDef *= theMinimum!!.errorDef() - assert(npoints > 3) - val maxcalls: Int = 100 * (npoints + 5) * (theMinimum!!.userState().variableParameters() + 1) - var nfcn = 0 - val result: MutableList = java.util.ArrayList(npoints) - val states: List = java.util.ArrayList() - val toler = 0.05 - - //get first four points - val minos = MnMinos(theFCN, theMinimum, theStrategy) - val valx: Double = theMinimum!!.userState().value(px) - val valy: Double = theMinimum!!.userState().value(py) - val mex: MinosError = minos.minos(px, errDef) - nfcn += mex.nfcn() - if (!mex.isValid()) { - MINUITPlugin.logStatic("MnContours is unable to find first two points.") - return ContoursError(px, py, result, mex, mex, nfcn) - } - val ex: Range = mex.range() - val mey: MinosError = minos.minos(py, errDef) - nfcn += mey.nfcn() - if (!mey.isValid()) { - MINUITPlugin.logStatic("MnContours is unable to find second two points.") - return ContoursError(px, py, result, mex, mey, nfcn) - } - val ey: Range = mey.range() - val migrad = MnMigrad(theFCN, - theMinimum!!.userState().copy(), - MnStrategy(max(0, theStrategy!!.strategy() - 1))) - migrad.fix(px) - migrad.setValue(px, valx + ex.getSecond()) - val exy_up: FunctionMinimum = migrad.minimize() - nfcn += exy_up.nfcn() - if (!exy_up.isValid()) { - MINUITPlugin.logStatic("MnContours is unable to find upper y value for x parameter $px.") - return ContoursError(px, py, result, mex, mey, nfcn) - } - migrad.setValue(px, valx + ex.getFirst()) - val exy_lo: FunctionMinimum = migrad.minimize() - nfcn += exy_lo.nfcn() - if (!exy_lo.isValid()) { - MINUITPlugin.logStatic("MnContours is unable to find lower y value for x parameter $px.") - return ContoursError(px, py, result, mex, mey, nfcn) - } - val migrad1 = MnMigrad(theFCN, - theMinimum!!.userState().copy(), - MnStrategy(max(0, theStrategy!!.strategy() - 1))) - migrad1.fix(py) - migrad1.setValue(py, valy + ey.getSecond()) - val eyx_up: FunctionMinimum = migrad1.minimize() - nfcn += eyx_up.nfcn() - if (!eyx_up.isValid()) { - MINUITPlugin.logStatic("MnContours is unable to find upper x value for y parameter $py.") - return ContoursError(px, py, result, mex, mey, nfcn) - } - migrad1.setValue(py, valy + ey.getFirst()) - val eyx_lo: FunctionMinimum = migrad1.minimize() - nfcn += eyx_lo.nfcn() - if (!eyx_lo.isValid()) { - MINUITPlugin.logStatic("MnContours is unable to find lower x value for y parameter $py.") - return ContoursError(px, py, result, mex, mey, nfcn) - } - val scalx: Double = 1.0 / (ex.getSecond() - ex.getFirst()) - val scaly: Double = 1.0 / (ey.getSecond() - ey.getFirst()) - result.add(Range(valx + ex.getFirst(), exy_lo.userState().value(py))) - result.add(Range(eyx_lo.userState().value(px), valy + ey.getFirst())) - result.add(Range(valx + ex.getSecond(), exy_up.userState().value(py))) - result.add(Range(eyx_up.userState().value(px), valy + ey.getSecond())) - val upar: MnUserParameterState = theMinimum!!.userState().copy() - upar.fix(px) - upar.fix(py) - val par = intArrayOf(px, py) - val cross = MnFunctionCross(theFCN, upar, theMinimum!!.fval(), theStrategy, errDef) - for (i in 4 until npoints) { - var idist1: Range = result[result.size - 1] - var idist2: Range = result[0] - var pos2 = 0 - val distx: Double = idist1.getFirst() - idist2.getFirst() - val disty: Double = idist1.getSecond() - idist2.getSecond() - var bigdis = scalx * scalx * distx * distx + scaly * scaly * disty * disty - for (j in 0 until result.size - 1) { - val ipair: Range = result[j] - val distx2: Double = ipair.getFirst() - result[j + 1].getFirst() - val disty2: Double = ipair.getSecond() - result[j + 1].getSecond() - val dist = scalx * scalx * distx2 * distx2 + scaly * scaly * disty2 * disty2 - if (dist > bigdis) { - bigdis = dist - idist1 = ipair - idist2 = result[j + 1] - pos2 = j + 1 - } - } - val a1 = 0.5 - val a2 = 0.5 - var sca = 1.0 - while (true) { - if (nfcn > maxcalls) { - MINUITPlugin.logStatic("MnContours: maximum number of function calls exhausted.") - return ContoursError(px, py, result, mex, mey, nfcn) - } - val xmidcr: Double = a1 * idist1.getFirst() + a2 * idist2.getFirst() - val ymidcr: Double = a1 * idist1.getSecond() + a2 * idist2.getSecond() - val xdir: Double = idist2.getSecond() - idist1.getSecond() - val ydir: Double = idist1.getFirst() - idist2.getFirst() - val scalfac: Double = - sca * max(abs(xdir * scalx), abs(ydir * scaly)) - val xdircr = xdir / scalfac - val ydircr = ydir / scalfac - val pmid = doubleArrayOf(xmidcr, ymidcr) - val pdir = doubleArrayOf(xdircr, ydircr) - val opt: MnCross = cross.cross(par, pmid, pdir, toler, maxcalls) - nfcn += opt.nfcn() - if (opt.isValid()) { - val aopt: Double = opt.value() - if (pos2 == 0) { - result.add(Range(xmidcr + aopt * xdircr, ymidcr + aopt * ydircr)) - } else { - result.add(pos2, Range(xmidcr + aopt * xdircr, ymidcr + aopt * ydircr)) - } - break - } - if (sca < 0.0) { - MINUITPlugin.logStatic("MnContours is unable to find point " + (i + 1) + " on contour.") - MINUITPlugin.logStatic("MnContours finds only $i points.") - return ContoursError(px, py, result, mex, mey, nfcn) - } - sca = -1.0 - } - } - return ContoursError(px, py, result, mex, mey, nfcn) - } - - /** - * - * points. - * - * @param px a int. - * @param py a int. - * @return a [List] object. - */ - fun points(px: Int, py: Int): List { - return points(px, py, 1.0) - } - - /** - * - * points. - * - * @param px a int. - * @param py a int. - * @param errDef a double. - * @return a [List] object. - */ - fun points(px: Int, py: Int, errDef: Double): List { - return points(px, py, errDef, 20) - } - - /** - * Calculates one function contour of FCN with respect to parameters parx - * and pary. The return value is a list of (x,y) points. FCN minimized - * always with respect to all other n - 2 variable parameters (if any). - * MINUITPlugin will try to find n points on the contour (default 20). To - * calculate more than one contour, the user needs to set the error - * definition in its FCN to the appropriate value for the desired confidence - * level and call this method for each contour. - * - * @param npoints a int. - * @param px a int. - * @param py a int. - * @param errDef a double. - * @return a [List] object. - */ - fun points(px: Int, py: Int, errDef: Double, npoints: Int): List { - val cont: ContoursError = contour(px, py, errDef, npoints) - return cont.points() - } - - fun strategy(): MnStrategy? { - return theStrategy - } - - /** - * construct from FCN + minimum + strategy - * - * @param stra a [hep.dataforge.MINUIT.MnStrategy] object. - * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. - * @param fcn a [MultiFunction] object. - */ - init { - theFCN = fcn - theMinimum = min - theStrategy = stra - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnCovarianceSqueeze.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnCovarianceSqueeze.kt deleted file mode 100644 index 7614a93b0..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnCovarianceSqueeze.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MINUITPlugin - -/** - * - * @version $Id$ - */ -internal object MnCovarianceSqueeze { - fun squeeze(cov: MnUserCovariance, n: Int): MnUserCovariance { - assert(cov.nrow() > 0) - assert(n < cov.nrow()) - val hess = MnAlgebraicSymMatrix(cov.nrow()) - for (i in 0 until cov.nrow()) { - for (j in i until cov.nrow()) { - hess[i, j] = cov[i, j] - } - } - try { - hess.invert() - } catch (x: SingularMatrixException) { - MINUITPlugin.logStatic("MnUserCovariance inversion failed; return diagonal matrix;") - val result = MnUserCovariance(cov.nrow() - 1) - var i = 0 - var j = 0 - while (i < cov.nrow()) { - if (i == n) { - i++ - continue - } - result[j, j] = cov[i, i] - j++ - i++ - } - return result - } - val squeezed: MnAlgebraicSymMatrix = squeeze(hess, n) - try { - squeezed.invert() - } catch (x: SingularMatrixException) { - MINUITPlugin.logStatic("MnUserCovariance back-inversion failed; return diagonal matrix;") - val result = MnUserCovariance(squeezed.nrow()) - var i = 0 - while (i < squeezed.nrow()) { - result[i, i] = 1.0 / squeezed[i, i] - i++ - } - return result - } - return MnUserCovariance(squeezed.data(), squeezed.nrow()) - } - - fun squeeze(err: MinimumError, n: Int): MinimumError { - val hess: MnAlgebraicSymMatrix = err.hessian() - val squeezed: MnAlgebraicSymMatrix = squeeze(hess, n) - try { - squeezed.invert() - } catch (x: SingularMatrixException) { - MINUITPlugin.logStatic("MnCovarianceSqueeze: MinimumError inversion fails; return diagonal matrix.") - val tmp = MnAlgebraicSymMatrix(squeezed.nrow()) - var i = 0 - while (i < squeezed.nrow()) { - tmp[i, i] = 1.0 / squeezed[i, i] - i++ - } - return MinimumError(tmp, MnInvertFailed()) - } - return MinimumError(squeezed, err.dcovar()) - } - - fun squeeze(hess: MnAlgebraicSymMatrix, n: Int): MnAlgebraicSymMatrix { - assert(hess.nrow() > 0) - assert(n < hess.nrow()) - val hs = MnAlgebraicSymMatrix(hess.nrow() - 1) - var i = 0 - var j = 0 - while (i < hess.nrow()) { - if (i == n) { - i++ - continue - } - var k = i - var l = j - while (k < hess.nrow()) { - if (k == n) { - k++ - continue - } - hs[j, l] = hess[i, k] - l++ - k++ - } - j++ - i++ - } - return hs - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnCross.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnCross.kt deleted file mode 100644 index f1487b106..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnCross.kt +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * MnCross class. - * - * @version $Id$ - * @author Darksnake - */ -class MnCross { - private var theLimset = false - private var theMaxFcn = false - private var theNFcn = 0 - private var theNewMin = false - private var theState: MnUserParameterState - private var theValid = false - private var theValue = 0.0 - - internal constructor() { - theState = MnUserParameterState() - } - - internal constructor(nfcn: Int) { - theState = MnUserParameterState() - theNFcn = nfcn - } - - internal constructor(value: Double, state: MnUserParameterState, nfcn: Int) { - theValue = value - theState = state - theNFcn = nfcn - theValid = true - } - - internal constructor(state: MnUserParameterState, nfcn: Int, x: CrossParLimit?) { - theState = state - theNFcn = nfcn - theLimset = true - } - - internal constructor(state: MnUserParameterState, nfcn: Int, x: CrossFcnLimit?) { - theState = state - theNFcn = nfcn - theMaxFcn = true - } - - internal constructor(state: MnUserParameterState, nfcn: Int, x: CrossNewMin?) { - theState = state - theNFcn = nfcn - theNewMin = true - } - - fun atLimit(): Boolean { - return theLimset - } - - fun atMaxFcn(): Boolean { - return theMaxFcn - } - - fun isValid(): Boolean { - return theValid - } - - fun newMinimum(): Boolean { - return theNewMin - } - - fun nfcn(): Int { - return theNFcn - } - - fun state(): MnUserParameterState { - return theState - } - - fun value(): Double { - return theValue - } - - internal class CrossFcnLimit - internal class CrossNewMin - internal class CrossParLimit -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnEigen.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnEigen.kt deleted file mode 100644 index d7aade0c9..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnEigen.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.RealVector - -/** - * Calculates and the eigenvalues of the user covariance matrix - * MnUserCovariance. - * - * @version $Id$ - * @author Darksnake - */ -object MnEigen { - /* Calculate eigenvalues of the covariance matrix. - * Will perform the calculation of the eigenvalues of the covariance matrix - * and return the result in the form of a double array. - * The eigenvalues are ordered from the smallest to the largest eigenvalue. - */ - /** - * - * eigenvalues. - * - * @param covar a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @return an array of double. - */ - fun eigenvalues(covar: MnUserCovariance): DoubleArray { - val cov = MnAlgebraicSymMatrix(covar.nrow()) - for (i in 0 until covar.nrow()) { - for (j in i until covar.nrow()) { - cov[i, j] = covar[i, j] - } - } - val eigen: RealVector = cov.eigenvalues() - return eigen.toArray() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnFcn.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnFcn.kt deleted file mode 100644 index b11f71035..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnFcn.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction - -/** - * Функция, которая помнит количество вызовов себя и ErrorDef - * @version $Id$ - */ -class MnFcn(fcn: MultiFunction?, errorDef: Double) { - private val theErrorDef: Double - private val theFCN: MultiFunction? - protected var theNumCall: Int - fun errorDef(): Double { - return theErrorDef - } - - fun fcn(): MultiFunction? { - return theFCN - } - - fun numOfCalls(): Int { - return theNumCall - } - - fun value(v: RealVector): Double { - theNumCall++ - return theFCN.value(v.toArray()) - } - - init { - theFCN = fcn - theNumCall = 0 - theErrorDef = errorDef - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnFunctionCross.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnFunctionCross.kt deleted file mode 100644 index a05590e53..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnFunctionCross.kt +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* -import kotlin.math.* - -/** - * - * @version $Id$ - */ -internal class MnFunctionCross( - fcn: MultiFunction?, - state: MnUserParameterState, - fval: Double, - stra: MnStrategy?, - errorDef: Double -) { - private val theErrorDef: Double - private val theFCN: MultiFunction? - private val theFval: Double - private val theState: MnUserParameterState - private val theStrategy: MnStrategy? - fun cross(par: IntArray, pmid: DoubleArray, pdir: DoubleArray, tlr: Double, maxcalls: Int): MnCross { - val npar = par.size - var nfcn = 0 - val prec: MnMachinePrecision = theState.precision() - val tlf = tlr * theErrorDef - var tla = tlr - val maxitr = 15 - var ipt = 0 - val aminsv = theFval - val aim = aminsv + theErrorDef - var aopt = 0.0 - var limset = false - val alsb = DoubleArray(3) - val flsb = DoubleArray(3) - val up = theErrorDef - var aulim = 100.0 - for (i in par.indices) { - val kex = par[i] - if (theState.parameter(kex).hasLimits()) { - val zmid = pmid[i] - val zdir = pdir[i] - if (abs(zdir) < theState.precision().eps()) { - continue - } - if (zdir > 0.0 && theState.parameter(kex).hasUpperLimit()) { - val zlim: Double = theState.parameter(kex).upperLimit() - aulim = min(aulim, (zlim - zmid) / zdir) - } else if (zdir < 0.0 && theState.parameter(kex).hasLowerLimit()) { - val zlim: Double = theState.parameter(kex).lowerLimit() - aulim = min(aulim, (zlim - zmid) / zdir) - } - } - } - if (aulim < aopt + tla) { - limset = true - } - val migrad = MnMigrad(theFCN, theState, MnStrategy(max(0, theStrategy!!.strategy() - 1))) - for (i in 0 until npar) { - migrad.setValue(par[i], pmid[i]) - } - val min0: FunctionMinimum = migrad.minimize(maxcalls, tlr) - nfcn += min0.nfcn() - if (min0.hasReachedCallLimit()) { - return MnCross(min0.userState(), nfcn, MnCross.CrossFcnLimit()) - } - if (!min0.isValid()) { - return MnCross(nfcn) - } - if (limset && min0.fval() < aim) { - return MnCross(min0.userState(), nfcn, MnCross.CrossParLimit()) - } - ipt++ - alsb[0] = 0.0 - flsb[0] = min0.fval() - flsb[0] = max(flsb[0], aminsv + 0.1 * up) - aopt = sqrt(up / (flsb[0] - aminsv)) - 1.0 - if (abs(flsb[0] - aim) < tlf) { - return MnCross(aopt, min0.userState(), nfcn) - } - if (aopt > 1.0) { - aopt = 1.0 - } - if (aopt < -0.5) { - aopt = -0.5 - } - limset = false - if (aopt > aulim) { - aopt = aulim - limset = true - } - for (i in 0 until npar) { - migrad.setValue(par[i], pmid[i] + aopt * pdir[i]) - } - var min1: FunctionMinimum = migrad.minimize(maxcalls, tlr) - nfcn += min1.nfcn() - if (min1.hasReachedCallLimit()) { - return MnCross(min1.userState(), nfcn, MnCross.CrossFcnLimit()) - } - if (!min1.isValid()) { - return MnCross(nfcn) - } - if (limset && min1.fval() < aim) { - return MnCross(min1.userState(), nfcn, MnCross.CrossParLimit()) - } - ipt++ - alsb[1] = aopt - flsb[1] = min1.fval() - var dfda = (flsb[1] - flsb[0]) / (alsb[1] - alsb[0]) - var ecarmn = 0.0 - var ecarmx = 0.0 - var ibest = 0 - var iworst = 0 - var noless = 0 - var min2: FunctionMinimum? = null - L300@ while (true) { - if (dfda < 0.0) { - val maxlk = maxitr - ipt - for (it in 0 until maxlk) { - alsb[0] = alsb[1] - flsb[0] = flsb[1] - aopt = alsb[0] + 0.2 * it - limset = false - if (aopt > aulim) { - aopt = aulim - limset = true - } - for (i in 0 until npar) { - migrad.setValue(par[i], pmid[i] + aopt * pdir[i]) - } - min1 = migrad.minimize(maxcalls, tlr) - nfcn += min1.nfcn() - if (min1.hasReachedCallLimit()) { - return MnCross(min1.userState(), nfcn, MnCross.CrossFcnLimit()) - } - if (!min1.isValid()) { - return MnCross(nfcn) - } - if (limset && min1.fval() < aim) { - return MnCross(min1.userState(), nfcn, MnCross.CrossParLimit()) - } - ipt++ - alsb[1] = aopt - flsb[1] = min1.fval() - dfda = (flsb[1] - flsb[0]) / (alsb[1] - alsb[0]) - if (dfda > 0.0) { - break - } - } - if (ipt > maxitr) { - return MnCross(nfcn) - } - } - L460@ while (true) { - aopt = alsb[1] + (aim - flsb[1]) / dfda - val fdist: Double = - min(abs(aim - flsb[0]), abs(aim - flsb[1])) - val adist: Double = - min(abs(aopt - alsb[0]), abs(aopt - alsb[1])) - tla = tlr - if (abs(aopt) > 1.0) { - tla = tlr * abs(aopt) - } - if (adist < tla && fdist < tlf) { - return MnCross(aopt, min1.userState(), nfcn) - } - if (ipt > maxitr) { - return MnCross(nfcn) - } - val bmin: Double = min(alsb[0], alsb[1]) - 1.0 - if (aopt < bmin) { - aopt = bmin - } - val bmax: Double = max(alsb[0], alsb[1]) + 1.0 - if (aopt > bmax) { - aopt = bmax - } - limset = false - if (aopt > aulim) { - aopt = aulim - limset = true - } - for (i in 0 until npar) { - migrad.setValue(par[i], pmid[i] + aopt * pdir[i]) - } - min2 = migrad.minimize(maxcalls, tlr) - nfcn += min2.nfcn() - if (min2.hasReachedCallLimit()) { - return MnCross(min2.userState(), nfcn, CrossFcnLimit()) - } - if (!min2.isValid()) { - return MnCross(nfcn) - } - if (limset && min2.fval() < aim) { - return MnCross(min2.userState(), nfcn, MnCross.CrossParLimit()) - } - ipt++ - alsb[2] = aopt - flsb[2] = min2.fval() - ecarmn = abs(flsb[2] - aim) - ecarmx = 0.0 - ibest = 2 - iworst = 0 - noless = 0 - for (i in 0..2) { - val ecart: Double = abs(flsb[i] - aim) - if (ecart > ecarmx) { - ecarmx = ecart - iworst = i - } - if (ecart < ecarmn) { - ecarmn = ecart - ibest = i - } - if (flsb[i] < aim) { - noless++ - } - } - if (noless == 1 || noless == 2) { - break@L300 - } - if (noless == 0 && ibest != 2) { - return MnCross(nfcn) - } - if (noless == 3 && ibest != 2) { - alsb[1] = alsb[2] - flsb[1] = flsb[2] - continue@L300 - } - flsb[iworst] = flsb[2] - alsb[iworst] = alsb[2] - dfda = (flsb[1] - flsb[0]) / (alsb[1] - alsb[0]) - } - } - do { - val parbol: MnParabola = MnParabolaFactory.create(MnParabolaPoint(alsb[0], flsb[0]), - MnParabolaPoint(alsb[1], flsb[1]), - MnParabolaPoint( - alsb[2], flsb[2])) - val coeff1: Double = parbol.c() - val coeff2: Double = parbol.b() - val coeff3: Double = parbol.a() - val determ = coeff2 * coeff2 - 4.0 * coeff3 * (coeff1 - aim) - if (determ < prec.eps()) { - return MnCross(nfcn) - } - val rt: Double = sqrt(determ) - val x1 = (-coeff2 + rt) / (2.0 * coeff3) - val x2 = (-coeff2 - rt) / (2.0 * coeff3) - val s1 = coeff2 + 2.0 * x1 * coeff3 - val s2 = coeff2 + 2.0 * x2 * coeff3 - if (s1 * s2 > 0.0) { - MINUITPlugin.logStatic("MnFunctionCross problem 1") - } - aopt = x1 - var slope = s1 - if (s2 > 0.0) { - aopt = x2 - slope = s2 - } - tla = tlr - if (abs(aopt) > 1.0) { - tla = tlr * abs(aopt) - } - if (abs(aopt - alsb[ibest]) < tla && abs(flsb[ibest] - aim) < tlf) { - return MnCross(aopt, min2!!.userState(), nfcn) - } - var ileft = 3 - var iright = 3 - var iout = 3 - ibest = 0 - ecarmx = 0.0 - ecarmn = abs(aim - flsb[0]) - for (i in 0..2) { - val ecart: Double = abs(flsb[i] - aim) - if (ecart < ecarmn) { - ecarmn = ecart - ibest = i - } - if (ecart > ecarmx) { - ecarmx = ecart - } - if (flsb[i] > aim) { - if (iright == 3) { - iright = i - } else if (flsb[i] > flsb[iright]) { - iout = i - } else { - iout = iright - iright = i - } - } else if (ileft == 3) { - ileft = i - } else if (flsb[i] < flsb[ileft]) { - iout = i - } else { - iout = ileft - ileft = i - } - } - if (ecarmx > 10.0 * abs(flsb[iout] - aim)) { - aopt = 0.5 * (aopt + 0.5 * (alsb[iright] + alsb[ileft])) - } - var smalla = 0.1 * tla - if (slope * smalla > tlf) { - smalla = tlf / slope - } - val aleft = alsb[ileft] + smalla - val aright = alsb[iright] - smalla - if (aopt < aleft) { - aopt = aleft - } - if (aopt > aright) { - aopt = aright - } - if (aleft > aright) { - aopt = 0.5 * (aleft + aright) - } - limset = false - if (aopt > aulim) { - aopt = aulim - limset = true - } - for (i in 0 until npar) { - migrad.setValue(par[i], pmid[i] + aopt * pdir[i]) - } - min2 = migrad.minimize(maxcalls, tlr) - nfcn += min2.nfcn() - if (min2.hasReachedCallLimit()) { - return MnCross(min2.userState(), nfcn, CrossFcnLimit()) - } - if (!min2.isValid()) { - return MnCross(nfcn) - } - if (limset && min2.fval() < aim) { - return MnCross(min2.userState(), nfcn, CrossParLimit()) - } - ipt++ - alsb[iout] = aopt - flsb[iout] = min2.fval() - ibest = iout - } while (ipt < maxitr) - return MnCross(nfcn) - } - - init { - theFCN = fcn - theState = state - theFval = fval - theStrategy = stra - theErrorDef = errorDef - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnGlobalCorrelationCoeff.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnGlobalCorrelationCoeff.kt deleted file mode 100644 index 939dd7fa0..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnGlobalCorrelationCoeff.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.SingularMatrixException - -/** - * - * MnGlobalCorrelationCoeff class. - * - * @version $Id$ - * @author Darksnake - */ -class MnGlobalCorrelationCoeff { - private var theGlobalCC: DoubleArray - private var theValid = false - - internal constructor() { - theGlobalCC = DoubleArray(0) - } - - internal constructor(cov: MnAlgebraicSymMatrix) { - try { - val inv: MnAlgebraicSymMatrix = cov.copy() - inv.invert() - theGlobalCC = DoubleArray(cov.nrow()) - for (i in 0 until cov.nrow()) { - val denom: Double = inv[i, i] * cov[i, i] - if (denom < 1.0 && denom > 0.0) { - theGlobalCC[i] = 0 - } else { - theGlobalCC[i] = sqrt(1.0 - 1.0 / denom) - } - } - theValid = true - } catch (x: SingularMatrixException) { - theValid = false - theGlobalCC = DoubleArray(0) - } - } - - /** - * - * globalCC. - * - * @return an array of double. - */ - fun globalCC(): DoubleArray { - return theGlobalCC - } - - /** - * - * isValid. - * - * @return a boolean. - */ - fun isValid(): Boolean { - return theValid - } - - /** {@inheritDoc} */ - override fun toString(): String { - return MnPrint.toString(this) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnHesse.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnHesse.kt deleted file mode 100644 index 3bb6c4551..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnHesse.kt +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* - -/** - * With MnHesse the user can instructs MINUITPlugin to calculate, by finite - * differences, the Hessian or error matrix. That is, it calculates the full - * matrix of second derivatives of the function with respect to the currently - * variable parameters, and inverts it. - * - * @version $Id$ - * @author Darksnake - */ -class MnHesse { - private var theStrategy: MnStrategy - - /** - * default constructor with default strategy - */ - constructor() { - theStrategy = MnStrategy(1) - } - - /** - * constructor with user-defined strategy level - * - * @param stra a int. - */ - constructor(stra: Int) { - theStrategy = MnStrategy(stra) - } - - /** - * conctructor with specific strategy - * - * @param stra a [hep.dataforge.MINUIT.MnStrategy] object. - */ - constructor(stra: MnStrategy) { - theStrategy = stra - } - /// - /// low-level API - /// - /** - * - * calculate. - * - * @param fcn a [MultiFunction] object. - * @param par an array of double. - * @param err an array of double. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray): MnUserParameterState { - return calculate(fcn, par, err, 0) - } - - /** - * FCN + parameters + errors - * - * @param maxcalls a int. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - * @param err an array of double. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, maxcalls: Int): MnUserParameterState { - return calculate(fcn, MnUserParameterState(par, err), maxcalls) - } - - /** - * - * calculate. - * - * @param fcn a [MultiFunction] object. - * @param par an array of double. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance): MnUserParameterState { - return calculate(fcn, par, cov, 0) - } - - /** - * FCN + parameters + MnUserCovariance - * - * @param maxcalls a int. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, maxcalls: Int): MnUserParameterState { - return calculate(fcn, MnUserParameterState(par, cov), maxcalls) - } - /// - /// high-level API - /// - /** - * - * calculate. - * - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, par: MnUserParameters): MnUserParameterState { - return calculate(fcn, par, 0) - } - - /** - * FCN + MnUserParameters - * - * @param maxcalls a int. - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, par: MnUserParameters, maxcalls: Int): MnUserParameterState { - return calculate(fcn, MnUserParameterState(par), maxcalls) - } - - /** - * - * calculate. - * - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance?): MnUserParameterState { - return calculate(fcn, par, 0) - } - - /** - * FCN + MnUserParameters + MnUserCovariance - * - * @param maxcalls a int. - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate( - fcn: MultiFunction?, - par: MnUserParameters, - cov: MnUserCovariance, - maxcalls: Int - ): MnUserParameterState { - return calculate(fcn, MnUserParameterState(par, cov), maxcalls) - } - - /** - * FCN + MnUserParameterState - * - * @param maxcalls a int. - * @param fcn a [MultiFunction] object. - * @param state a [hep.dataforge.MINUIT.MnUserParameterState] object. - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun calculate(fcn: MultiFunction?, state: MnUserParameterState, maxcalls: Int): MnUserParameterState { - val errDef = 1.0 // FixMe! - val n: Int = state.variableParameters() - val mfcn = MnUserFcn(fcn, errDef, state.getTransformation()) - val x: RealVector = ArrayRealVector(n) - for (i in 0 until n) { - x.setEntry(i, state.intParameters()[i]) - } - val amin: Double = mfcn.value(x) - val gc = Numerical2PGradientCalculator(mfcn, state.getTransformation(), theStrategy) - val par = MinimumParameters(x, amin) - val gra: FunctionGradient = gc.gradient(par) - val tmp: MinimumState = calculate(mfcn, - MinimumState(par, MinimumError(MnAlgebraicSymMatrix(n), 1.0), gra, state.edm(), state.nfcn()), - state.getTransformation(), - maxcalls) - return MnUserParameterState(tmp, errDef, state.getTransformation()) - } - - /// - /// internal interface - /// - fun calculate(mfcn: MnFcn, st: MinimumState, trafo: MnUserTransformation, maxcalls: Int): MinimumState { - var maxcalls = maxcalls - val prec: MnMachinePrecision = trafo.precision() - // make sure starting at the right place - val amin: Double = mfcn.value(st.vec()) - val aimsag: Double = sqrt(prec.eps2()) * (abs(amin) + mfcn.errorDef()) - - // diagonal elements first - val n: Int = st.parameters().vec().getDimension() - if (maxcalls == 0) { - maxcalls = 200 + 100 * n + 5 * n * n - } - var vhmat = MnAlgebraicSymMatrix(n) - var g2: RealVector = st.gradient().getGradientDerivative().copy() - var gst: RealVector = st.gradient().getStep().copy() - var grd: RealVector = st.gradient().getGradient().copy() - var dirin: RealVector = st.gradient().getStep().copy() - val yy: RealVector = ArrayRealVector(n) - if (st.gradient().isAnalytical()) { - val igc = InitialGradientCalculator(mfcn, trafo, theStrategy) - val tmp: FunctionGradient = igc.gradient(st.parameters()) - gst = tmp.getStep().copy() - dirin = tmp.getStep().copy() - g2 = tmp.getGradientDerivative().copy() - } - return try { - val x: RealVector = st.parameters().vec().copy() - for (i in 0 until n) { - val xtf: Double = x.getEntry(i) - val dmin: Double = 8.0 * prec.eps2() * (abs(xtf) + prec.eps2()) - var d: Double = abs(gst.getEntry(i)) - if (d < dmin) { - d = dmin - } - for (icyc in 0 until ncycles()) { - var sag = 0.0 - var fs1 = 0.0 - var fs2 = 0.0 - var multpy = 0 - while (multpy < 5) { - x.setEntry(i, xtf + d) - fs1 = mfcn.value(x) - x.setEntry(i, xtf - d) - fs2 = mfcn.value(x) - x.setEntry(i, xtf) - sag = 0.5 * (fs1 + fs2 - 2.0 * amin) - if (sag > prec.eps2()) { - break - } - if (trafo.parameter(i).hasLimits()) { - if (d > 0.5) { - throw MnHesseFailedException("MnHesse: 2nd derivative zero for parameter") - } - d *= 10.0 - if (d > 0.5) { - d = 0.51 - } - multpy++ - continue - } - d *= 10.0 - multpy++ - } - if (multpy >= 5) { - throw MnHesseFailedException("MnHesse: 2nd derivative zero for parameter") - } - val g2bfor: Double = g2.getEntry(i) - g2.setEntry(i, 2.0 * sag / (d * d)) - grd.setEntry(i, (fs1 - fs2) / (2.0 * d)) - gst.setEntry(i, d) - dirin.setEntry(i, d) - yy.setEntry(i, fs1) - val dlast = d - d = sqrt(2.0 * aimsag / abs(g2.getEntry(i))) - if (trafo.parameter(i).hasLimits()) { - d = min(0.5, d) - } - if (d < dmin) { - d = dmin - } - - // see if converged - if (abs((d - dlast) / d) < tolerstp()) { - break - } - if (abs((g2.getEntry(i) - g2bfor) / g2.getEntry(i)) < tolerg2()) { - break - } - d = min(d, 10.0 * dlast) - d = max(d, 0.1 * dlast) - } - vhmat[i, i] = g2.getEntry(i) - if (mfcn.numOfCalls() - st.nfcn() > maxcalls) { - throw MnHesseFailedException("MnHesse: maximum number of allowed function calls exhausted.") - } - } - if (theStrategy.strategy() > 0) { - // refine first derivative - val hgc = HessianGradientCalculator(mfcn, trafo, theStrategy) - val gr: FunctionGradient = hgc.gradient(st.parameters(), FunctionGradient(grd, g2, gst)) - grd = gr.getGradient() - } - - //off-diagonal elements - for (i in 0 until n) { - x.setEntry(i, x.getEntry(i) + dirin.getEntry(i)) - for (j in i + 1 until n) { - x.setEntry(j, x.getEntry(j) + dirin.getEntry(j)) - val fs1: Double = mfcn.value(x) - val elem: Double = - (fs1 + amin - yy.getEntry(i) - yy.getEntry(j)) / (dirin.getEntry(i) * dirin.getEntry(j)) - vhmat[i, j] = elem - x.setEntry(j, x.getEntry(j) - dirin.getEntry(j)) - } - x.setEntry(i, x.getEntry(i) - dirin.getEntry(i)) - } - - //verify if matrix pos-def (still 2nd derivative) - val tmp: MinimumError = MnPosDef.test(MinimumError(vhmat, 1.0), prec) - vhmat = tmp.invHessian() - try { - vhmat.invert() - } catch (xx: SingularMatrixException) { - throw MnHesseFailedException("MnHesse: matrix inversion fails!") - } - val gr = FunctionGradient(grd, g2, gst) - if (tmp.isMadePosDef()) { - MINUITPlugin.logStatic("MnHesse: matrix is invalid!") - MINUITPlugin.logStatic("MnHesse: matrix is not pos. def.!") - MINUITPlugin.logStatic("MnHesse: matrix was forced pos. def.") - return MinimumState(st.parameters(), - MinimumError(vhmat, MnMadePosDef()), - gr, - st.edm(), - mfcn.numOfCalls()) - } - - //calculate edm - val err = MinimumError(vhmat, 0.0) - val edm: Double = VariableMetricEDMEstimator().estimate(gr, err) - MinimumState(st.parameters(), err, gr, edm, mfcn.numOfCalls()) - } catch (x: MnHesseFailedException) { - MINUITPlugin.logStatic(x.message) - MINUITPlugin.logStatic("MnHesse fails and will return diagonal matrix ") - var j = 0 - while (j < n) { - val tmp = if (g2.getEntry(j) < prec.eps2()) 1.0 else 1.0 / g2.getEntry(j) - vhmat[j, j] = if (tmp < prec.eps2()) 1.0 else tmp - j++ - } - MinimumState(st.parameters(), - MinimumError(vhmat, MnHesseFailed()), - st.gradient(), - st.edm(), - st.nfcn() + mfcn.numOfCalls()) - } - } - - /// forward interface of MnStrategy - fun ncycles(): Int { - return theStrategy.hessianNCycles() - } - - fun tolerg2(): Double { - return theStrategy.hessianG2Tolerance() - } - - fun tolerstp(): Double { - return theStrategy.hessianStepTolerance() - } - - private inner class MnHesseFailedException(message: String?) : java.lang.Exception(message) -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnLineSearch.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnLineSearch.kt deleted file mode 100644 index 7b1171d3c..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnLineSearch.kt +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.RealVector -import ru.inr.mass.minuit.* - -/** - * - * @version $Id$ - */ -internal object MnLineSearch { - fun search( - fcn: MnFcn, - st: MinimumParameters, - step: RealVector, - gdel: Double, - prec: MnMachinePrecision - ): MnParabolaPoint { - var overal = 1000.0 - var undral = -100.0 - val toler = 0.05 - var slamin = 0.0 - val slambg = 5.0 - val alpha = 2.0 - val maxiter = 12 - var niter = 0 - for (i in 0 until step.getDimension()) { - if (abs(step.getEntry(i)) < prec.eps()) { - continue - } - val ratio: Double = abs(st.vec().getEntry(i) / step.getEntry(i)) - if (abs(slamin) < prec.eps()) { - slamin = ratio - } - if (ratio < slamin) { - slamin = ratio - } - } - if (abs(slamin) < prec.eps()) { - slamin = prec.eps() - } - slamin *= prec.eps2() - val F0: Double = st.fval() - val F1: Double = fcn.value(MnUtils.add(st.vec(), step)) - var fvmin: Double = st.fval() - var xvmin = 0.0 - if (F1 < F0) { - fvmin = F1 - xvmin = 1.0 - } - var toler8 = toler - var slamax = slambg - var flast = F1 - var slam = 1.0 - var iterate = false - var p0 = MnParabolaPoint(0.0, F0) - var p1 = MnParabolaPoint(slam, flast) - var F2 = 0.0 - do { - // cut toler8 as function goes up - iterate = false - val pb: MnParabola = MnParabolaFactory.create(p0, gdel, p1) - var denom = 2.0 * (flast - F0 - gdel * slam) / (slam * slam) - if (abs(denom) < prec.eps()) { - denom = -0.1 * gdel - slam = 1.0 - } - if (abs(denom) > prec.eps()) { - slam = -gdel / denom - } - if (slam < 0.0) { - slam = slamax - } - if (slam > slamax) { - slam = slamax - } - if (slam < toler8) { - slam = toler8 - } - if (slam < slamin) { - return MnParabolaPoint(xvmin, fvmin) - } - if (abs(slam - 1.0) < toler8 && p1.y() < p0.y()) { - return MnParabolaPoint(xvmin, fvmin) - } - if (abs(slam - 1.0) < toler8) { - slam = 1.0 + toler8 - } - F2 = fcn.value(MnUtils.add(st.vec(), MnUtils.mul(step, slam))) - if (F2 < fvmin) { - fvmin = F2 - xvmin = slam - } - if (p0.y() - prec.eps() < fvmin && fvmin < p0.y() + prec.eps()) { - iterate = true - flast = F2 - toler8 = toler * slam - overal = slam - toler8 - slamax = overal - p1 = MnParabolaPoint(slam, flast) - niter++ - } - } while (iterate && niter < maxiter) - if (niter >= maxiter) { - // exhausted max number of iterations - return MnParabolaPoint(xvmin, fvmin) - } - var p2 = MnParabolaPoint(slam, F2) - do { - slamax = max(slamax, alpha * abs(xvmin)) - val pb: MnParabola = MnParabolaFactory.create(p0, p1, p2) - if (pb.a() < prec.eps2()) { - val slopem: Double = 2.0 * pb.a() * xvmin + pb.b() - slam = if (slopem < 0.0) { - xvmin + slamax - } else { - xvmin - slamax - } - } else { - slam = pb.min() - if (slam > xvmin + slamax) { - slam = xvmin + slamax - } - if (slam < xvmin - slamax) { - slam = xvmin - slamax - } - } - if (slam > 0.0) { - if (slam > overal) { - slam = overal - } - } else { - if (slam < undral) { - slam = undral - } - } - var F3 = 0.0 - do { - iterate = false - val toler9: Double = max(toler8, abs(toler8 * slam)) - // min. of parabola at one point - if (abs(p0.x() - slam) < toler9 || abs(p1.x() - slam) < toler9 || abs( - p2.x() - slam) < toler9 - ) { - return MnParabolaPoint(xvmin, fvmin) - } - F3 = fcn.value(MnUtils.add(st.vec(), MnUtils.mul(step, slam))) - // if latest point worse than all three previous, cut step - if (F3 > p0.y() && F3 > p1.y() && F3 > p2.y()) { - if (slam > xvmin) { - overal = min(overal, slam - toler8) - } - if (slam < xvmin) { - undral = max(undral, slam + toler8) - } - slam = 0.5 * (slam + xvmin) - iterate = true - niter++ - } - } while (iterate && niter < maxiter) - if (niter >= maxiter) { - // exhausted max number of iterations - return MnParabolaPoint(xvmin, fvmin) - } - - // find worst previous point out of three and replace - val p3 = MnParabolaPoint(slam, F3) - if (p0.y() > p1.y() && p0.y() > p2.y()) { - p0 = p3 - } else if (p1.y() > p0.y() && p1.y() > p2.y()) { - p1 = p3 - } else { - p2 = p3 - } - if (F3 < fvmin) { - fvmin = F3 - xvmin = slam - } else { - if (slam > xvmin) { - overal = min(overal, slam - toler8) - } - if (slam < xvmin) { - undral = max(undral, slam + toler8) - } - } - niter++ - } while (niter < maxiter) - return MnParabolaPoint(xvmin, fvmin) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnMachinePrecision.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnMachinePrecision.kt deleted file mode 100644 index 161ee0c0a..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnMachinePrecision.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * Determines the relative floating point arithmetic precision. The - * setPrecision() method can be used to override Minuit's own determination, - * when the user knows that the {FCN} function value is not calculated to the - * nominal machine accuracy. - * - * @version $Id$ - * @author Darksnake - */ -class MnMachinePrecision internal constructor() { - private var theEpsMa2 = 0.0 - private var theEpsMac = 0.0 - - /** - * eps returns the smallest possible number so that 1.+eps > 1. - * @return - */ - fun eps(): Double { - return theEpsMac - } - - /** - * eps2 returns 2*sqrt(eps) - * @return - */ - fun eps2(): Double { - return theEpsMa2 - } - - /** - * override Minuit's own determination - * - * @param prec a double. - */ - fun setPrecision(prec: Double) { - theEpsMac = prec - theEpsMa2 = 2.0 * sqrt(theEpsMac) - } - - init { - setPrecision(4.0E-7) - var epstry = 0.5 - val one = 1.0 - for (i in 0..99) { - epstry *= 0.5 - val epsp1 = one + epstry - val epsbak = epsp1 - one - if (epsbak < epstry) { - setPrecision(8.0 * epstry) - break - } - } - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnMigrad.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnMigrad.kt deleted file mode 100644 index 22616a1a6..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnMigrad.kt +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction - -/** - * MnMigrad provides minimization of the function by the method of MIGRAD, the - * most efficient and complete single method, recommended for general functions, - * and the functionality for parameters interaction. It also retains the result - * from the last minimization in case the user may want to do subsequent - * minimization steps with parameter interactions in between the minimization - * requests. The minimization produces as a by-product the error matrix of the - * parameters, which is usually reliable unless warning messages are produced. - * - * @version $Id$ - * @author Darksnake - */ -class MnMigrad -/** - * construct from MultiFunction + MnUserParameterState + MnStrategy - * - * @param str a [hep.dataforge.MINUIT.MnStrategy] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameterState] object. - * @param fcn a [MultiFunction] object. - */ - (fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) : MnApplication(fcn, par, str) { - private val theMinimizer: VariableMetricMinimizer = VariableMetricMinimizer() - - /** - * construct from MultiFunction + double[] for parameters and errors - * with default strategy - * - * @param err an array of double. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray) : this(fcn, par, err, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and errors - * - * @param stra a int. - * @param err an array of double. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn, - MnUserParameterState(par, err), - MnStrategy(stra)) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance) : this(fcn, par, cov, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters with default - * strategy - * - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters) : this(fcn, par, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters - * - * @param stra a int. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn, - MnUserParameterState(par), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn, - par, - cov, - DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - override fun minimizer(): ModularFunctionMinimizer { - return theMinimizer - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnMinimize.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnMinimize.kt deleted file mode 100644 index ea14a5453..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnMinimize.kt +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction - -/** - * Causes minimization of the function by the method of MIGRAD, as does the - * MnMigrad class, but switches to the SIMPLEX method if MIGRAD fails to - * converge. Constructor arguments, methods arguments and names of methods are - * the same as for MnMigrad or MnSimplex. - * - * @version $Id$ - * @author Darksnake - */ -class MnMinimize -/** - * construct from MultiFunction + MnUserParameterState + MnStrategy - * - * @param str a [hep.dataforge.MINUIT.MnStrategy] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameterState] object. - * @param fcn a [MultiFunction] object. - */ - (fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) : MnApplication(fcn, par, str) { - private val theMinimizer: CombinedMinimizer = CombinedMinimizer() - - /** - * construct from MultiFunction + double[] for parameters and errors - * with default strategy - * - * @param err an array of double. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray) : this(fcn, par, err, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and errors - * - * @param stra a int. - * @param err an array of double. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn, - MnUserParameterState(par, err), - MnStrategy(stra)) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance) : this(fcn, par, cov, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters with default - * strategy - * - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters) : this(fcn, par, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters - * - * @param stra a int. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn, - MnUserParameterState(par), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn, - par, - cov, - DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - override fun minimizer(): ModularFunctionMinimizer { - return theMinimizer - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnMinos.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnMinos.kt deleted file mode 100644 index d49379b3b..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnMinos.kt +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* -import kotlin.jvm.JvmOverloads - -/** - * API class for Minos error analysis (asymmetric errors). Minimization has to - * be done before and minimum must be valid; possibility to ask only for one - * side of the Minos error; - * - * @version $Id$ - * @author Darksnake - */ -class MnMinos(fcn: MultiFunction?, min: FunctionMinimum?, stra: MnStrategy?) { - private var theFCN: MultiFunction? = null - private var theMinimum: FunctionMinimum? = null - private var theStrategy: MnStrategy? = null - - /** - * construct from FCN + minimum - * - * @param fcn a [MultiFunction] object. - * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. - */ - constructor(fcn: MultiFunction?, min: FunctionMinimum?) : this(fcn, min, MnApplication.DEFAULT_STRATEGY) - - /** - * construct from FCN + minimum + strategy - * - * @param stra a int. - * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, min: FunctionMinimum?, stra: Int) : this(fcn, min, MnStrategy(stra)) - // public MnMinos(MultiFunction fcn, MnUserParameterState state, double errDef, MnStrategy stra) { - // theFCN = fcn; - // theStrategy = stra; - // - // MinimumState minState = null; - // - // MnUserTransformation transformation = state.getTransformation(); - // - // MinimumSeed seed = new MinimumSeed(minState, transformation); - // - // theMinimum = new FunctionMinimum(seed,errDef); - // } - /** - * - * loval. - * - * @param par a int. - * @return a [hep.dataforge.MINUIT.MnCross] object. - */ - fun loval(par: Int): MnCross { - return loval(par, 1.0) - } - - /** - * - * loval. - * - * @param par a int. - * @param errDef a double. - * @return a [hep.dataforge.MINUIT.MnCross] object. - */ - fun loval(par: Int, errDef: Double): MnCross { - return loval(par, errDef, MnApplication.DEFAULT_MAXFCN) - } - - /** - * - * loval. - * - * @param par a int. - * @param errDef a double. - * @param maxcalls a int. - * @return a [hep.dataforge.MINUIT.MnCross] object. - */ - fun loval(par: Int, errDef: Double, maxcalls: Int): MnCross { - var errDef = errDef - var maxcalls = maxcalls - errDef *= theMinimum!!.errorDef() - assert(theMinimum!!.isValid()) - assert(!theMinimum!!.userState().parameter(par).isFixed()) - assert(!theMinimum!!.userState().parameter(par).isConst()) - if (maxcalls == 0) { - val nvar: Int = theMinimum!!.userState().variableParameters() - maxcalls = 2 * (nvar + 1) * (200 + 100 * nvar + 5 * nvar * nvar) - } - val para = intArrayOf(par) - val upar: MnUserParameterState = theMinimum!!.userState().copy() - val err: Double = upar.error(par) - val `val`: Double = upar.value(par) - err - val xmid = doubleArrayOf(`val`) - val xdir = doubleArrayOf(-err) - val ind: Int = upar.intOfExt(par) - val m: MnAlgebraicSymMatrix = theMinimum!!.error().matrix() - val xunit: Double = sqrt(errDef / err) - for (i in 0 until m.nrow()) { - if (i == ind) { - continue - } - val xdev: Double = xunit * m[ind, i] - val ext: Int = upar.extOfInt(i) - upar.setValue(ext, upar.value(ext) - xdev) - } - upar.fix(par) - upar.setValue(par, `val`) - val toler = 0.1 - val cross = MnFunctionCross(theFCN, upar, theMinimum!!.fval(), theStrategy, errDef) - val aopt: MnCross = cross.cross(para, xmid, xdir, toler, maxcalls) - if (aopt.atLimit()) { - MINUITPlugin.logStatic("MnMinos parameter $par is at lower limit.") - } - if (aopt.atMaxFcn()) { - MINUITPlugin.logStatic("MnMinos maximum number of function calls exceeded for parameter $par") - } - if (aopt.newMinimum()) { - MINUITPlugin.logStatic("MnMinos new minimum found while looking for parameter $par") - } - if (!aopt.isValid()) { - MINUITPlugin.logStatic("MnMinos could not find lower value for parameter $par.") - } - return aopt - } - /** - * calculate one side (negative or positive error) of the parameter - * - * @param maxcalls a int. - * @param par a int. - * @param errDef a double. - * @return a double. - */ - /** - * - * lower. - * - * @param par a int. - * @param errDef a double. - * @return a double. - */ - /** - * - * lower. - * - * @param par a int. - * @return a double. - */ - @JvmOverloads - fun lower(par: Int, errDef: Double = 1.0, maxcalls: Int = MnApplication.DEFAULT_MAXFCN): Double { - val upar: MnUserParameterState = theMinimum!!.userState() - val err: Double = theMinimum!!.userState().error(par) - val aopt: MnCross = loval(par, errDef, maxcalls) - return if (aopt.isValid()) -1.0 * err * (1.0 + aopt.value()) else if (aopt.atLimit()) upar.parameter(par) - .lowerLimit() else upar.value(par) - } - - /** - * - * minos. - * - * @param par a int. - * @return a [hep.dataforge.MINUIT.MinosError] object. - */ - fun minos(par: Int): MinosError { - return minos(par, 1.0) - } - - /** - * - * minos. - * - * @param par a int. - * @param errDef a double. - * @return a [hep.dataforge.MINUIT.MinosError] object. - */ - fun minos(par: Int, errDef: Double): MinosError { - return minos(par, errDef, MnApplication.DEFAULT_MAXFCN) - } - - /** - * Causes a MINOS error analysis to be performed on the parameter whose - * number is specified. MINOS errors may be expensive to calculate, but are - * very reliable since they take account of non-linearities in the problem - * as well as parameter correlations, and are in general asymmetric. - * - * @param maxcalls Specifies the (approximate) maximum number of function - * calls per parameter requested, after which the calculation will be - * stopped for that parameter. - * @param errDef a double. - * @param par a int. - * @return a [hep.dataforge.MINUIT.MinosError] object. - */ - fun minos(par: Int, errDef: Double, maxcalls: Int): MinosError { - assert(theMinimum!!.isValid()) - assert(!theMinimum!!.userState().parameter(par).isFixed()) - assert(!theMinimum!!.userState().parameter(par).isConst()) - val up: MnCross = upval(par, errDef, maxcalls) - val lo: MnCross = loval(par, errDef, maxcalls) - return MinosError(par, theMinimum!!.userState().value(par), lo, up) - } - - /** - * - * range. - * - * @param par a int. - * @return - */ - fun range(par: Int): Range { - return range(par, 1.0) - } - - /** - * - * range. - * - * @param par a int. - * @param errDef a double. - * @return - */ - fun range(par: Int, errDef: Double): Range { - return range(par, errDef, MnApplication.DEFAULT_MAXFCN) - } - - /** - * Causes a MINOS error analysis for external parameter n. - * - * @param maxcalls a int. - * @param errDef a double. - * @return The lower and upper bounds of parameter - * @param par a int. - */ - fun range(par: Int, errDef: Double, maxcalls: Int): Range { - val mnerr: MinosError = minos(par, errDef, maxcalls) - return mnerr.range() - } - /** - * - * upper. - * - * @param par a int. - * @param errDef a double. - * @param maxcalls a int. - * @return a double. - */ - /** - * - * upper. - * - * @param par a int. - * @param errDef a double. - * @return a double. - */ - /** - * - * upper. - * - * @param par a int. - * @return a double. - */ - @JvmOverloads - fun upper(par: Int, errDef: Double = 1.0, maxcalls: Int = MnApplication.DEFAULT_MAXFCN): Double { - val upar: MnUserParameterState = theMinimum!!.userState() - val err: Double = theMinimum!!.userState().error(par) - val aopt: MnCross = upval(par, errDef, maxcalls) - return if (aopt.isValid()) err * (1.0 + aopt.value()) else if (aopt.atLimit()) upar.parameter(par) - .upperLimit() else upar.value(par) - } - - /** - * - * upval. - * - * @param par a int. - * @return a [hep.dataforge.MINUIT.MnCross] object. - */ - fun upval(par: Int): MnCross { - return upval(par, 1.0) - } - - /** - * - * upval. - * - * @param par a int. - * @param errDef a double. - * @return a [hep.dataforge.MINUIT.MnCross] object. - */ - fun upval(par: Int, errDef: Double): MnCross { - return upval(par, errDef, MnApplication.DEFAULT_MAXFCN) - } - - /** - * - * upval. - * - * @param par a int. - * @param errDef a double. - * @param maxcalls a int. - * @return a [hep.dataforge.MINUIT.MnCross] object. - */ - fun upval(par: Int, errDef: Double, maxcalls: Int): MnCross { - var errDef = errDef - var maxcalls = maxcalls - errDef *= theMinimum!!.errorDef() - assert(theMinimum!!.isValid()) - assert(!theMinimum!!.userState().parameter(par).isFixed()) - assert(!theMinimum!!.userState().parameter(par).isConst()) - if (maxcalls == 0) { - val nvar: Int = theMinimum!!.userState().variableParameters() - maxcalls = 2 * (nvar + 1) * (200 + 100 * nvar + 5 * nvar * nvar) - } - val para = intArrayOf(par) - val upar: MnUserParameterState = theMinimum!!.userState().copy() - val err: Double = upar.error(par) - val `val`: Double = upar.value(par) + err - val xmid = doubleArrayOf(`val`) - val xdir = doubleArrayOf(err) - val ind: Int = upar.intOfExt(par) - val m: MnAlgebraicSymMatrix = theMinimum!!.error().matrix() - val xunit: Double = sqrt(errDef / err) - for (i in 0 until m.nrow()) { - if (i == ind) { - continue - } - val xdev: Double = xunit * m[ind, i] - val ext: Int = upar.extOfInt(i) - upar.setValue(ext, upar.value(ext) + xdev) - } - upar.fix(par) - upar.setValue(par, `val`) - val toler = 0.1 - val cross = MnFunctionCross(theFCN, upar, theMinimum!!.fval(), theStrategy, errDef) - val aopt: MnCross = cross.cross(para, xmid, xdir, toler, maxcalls) - if (aopt.atLimit()) { - MINUITPlugin.logStatic("MnMinos parameter $par is at upper limit.") - } - if (aopt.atMaxFcn()) { - MINUITPlugin.logStatic("MnMinos maximum number of function calls exceeded for parameter $par") - } - if (aopt.newMinimum()) { - MINUITPlugin.logStatic("MnMinos new minimum found while looking for parameter $par") - } - if (!aopt.isValid()) { - MINUITPlugin.logStatic("MnMinos could not find upper value for parameter $par.") - } - return aopt - } - - /** - * construct from FCN + minimum + strategy - * - * @param stra a [hep.dataforge.MINUIT.MnStrategy] object. - * @param min a [hep.dataforge.MINUIT.FunctionMinimum] object. - * @param fcn a [MultiFunction] object. - */ - init { - theFCN = fcn - theMinimum = min - theStrategy = stra - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnParabola.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnParabola.kt deleted file mode 100644 index a0a56dedd..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnParabola.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * parabola = a*xx + b*x + c - * - * @version $Id$ - */ -internal class MnParabola(private val theA: Double, private val theB: Double, private val theC: Double) { - fun a(): Double { - return theA - } - - fun b(): Double { - return theB - } - - fun c(): Double { - return theC - } - - fun min(): Double { - return -theB / (2.0 * theA) - } - - fun x_neg(y: Double): Double { - return -sqrt(y / theA + min() * min() - theC / theA) + min() - } - - fun x_pos(y: Double): Double { - return sqrt(y / theA + min() * min() - theC / theA) + min() - } - - fun y(x: Double): Double { - return theA * x * x + theB * x + theC - } - - fun ymin(): Double { - return -theB * theB / (4.0 * theA) + theC - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnParabolaFactory.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnParabolaFactory.kt deleted file mode 100644 index f45d2b9c9..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnParabolaFactory.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal object MnParabolaFactory { - fun create(p1: MnParabolaPoint, p2: MnParabolaPoint, p3: MnParabolaPoint): MnParabola { - var x1: Double = p1.x() - var x2: Double = p2.x() - var x3: Double = p3.x() - val dx12 = x1 - x2 - val dx13 = x1 - x3 - val dx23 = x2 - x3 - val xm = (x1 + x2 + x3) / 3.0 - x1 -= xm - x2 -= xm - x3 -= xm - val y1: Double = p1.y() - val y2: Double = p2.y() - val y3: Double = p3.y() - val a = y1 / (dx12 * dx13) - y2 / (dx12 * dx23) + y3 / (dx13 * dx23) - var b = -y1 * (x2 + x3) / (dx12 * dx13) + y2 * (x1 + x3) / (dx12 * dx23) - y3 * (x1 + x2) / (dx13 * dx23) - var c = y1 - a * x1 * x1 - b * x1 - c += xm * (xm * a - b) - b -= 2.0 * xm * a - return MnParabola(a, b, c) - } - - fun create(p1: MnParabolaPoint, dxdy1: Double, p2: MnParabolaPoint): MnParabola { - val x1: Double = p1.x() - val xx1 = x1 * x1 - val x2: Double = p2.x() - val xx2 = x2 * x2 - val y1: Double = p1.y() - val y12: Double = p1.y() - p2.y() - val det = xx1 - xx2 - 2.0 * x1 * (x1 - x2) - val a = -(y12 + (x2 - x1) * dxdy1) / det - val b = -(-2.0 * x1 * y12 + (xx1 - xx2) * dxdy1) / det - val c = y1 - a * xx1 - b * x1 - return MnParabola(a, b, c) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnParabolaPoint.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnParabolaPoint.kt deleted file mode 100644 index 858e010e6..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnParabolaPoint.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class MnParabolaPoint(private val theX: Double, private val theY: Double) { - fun x(): Double { - return theX - } - - fun y(): Double { - return theY - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnParameterScan.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnParameterScan.kt deleted file mode 100644 index 7791c20e8..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnParameterScan.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction - -/** - * Scans the values of FCN as a function of one parameter and retains the best - * function and parameter values found - * - * @version $Id$ - */ -internal class MnParameterScan { - private var theAmin: Double - private var theFCN: MultiFunction? - private var theParameters: MnUserParameters - - constructor(fcn: MultiFunction, par: MnUserParameters) { - theFCN = fcn - theParameters = par - theAmin = fcn.value(par.params()) - } - - constructor(fcn: MultiFunction?, par: MnUserParameters, fval: Double) { - theFCN = fcn - theParameters = par - theAmin = fval - } - - fun fval(): Double { - return theAmin - } - - fun parameters(): MnUserParameters { - return theParameters - } - - fun scan(par: Int): List { - return scan(par, 41) - } - - fun scan(par: Int, maxsteps: Int): List { - return scan(par, maxsteps, 0.0, 0.0) - } - - /** - * returns pairs of (x,y) points, x=parameter value, y=function value of FCN - * @param high - * @return - */ - fun scan(par: Int, maxsteps: Int, low: Double, high: Double): List { - var maxsteps = maxsteps - var low = low - var high = high - if (maxsteps > 101) { - maxsteps = 101 - } - val result: MutableList = java.util.ArrayList(maxsteps + 1) - val params: DoubleArray = theParameters.params() - result.add(Range(params[par], theAmin)) - if (low > high) { - return result - } - if (maxsteps < 2) { - return result - } - if (low == 0.0 && high == 0.0) { - low = params[par] - 2.0 * theParameters.error(par) - high = params[par] + 2.0 * theParameters.error(par) - } - if (low == 0.0 && high == 0.0 && theParameters.parameter(par).hasLimits()) { - if (theParameters.parameter(par).hasLowerLimit()) { - low = theParameters.parameter(par).lowerLimit() - } - if (theParameters.parameter(par).hasUpperLimit()) { - high = theParameters.parameter(par).upperLimit() - } - } - if (theParameters.parameter(par).hasLimits()) { - if (theParameters.parameter(par).hasLowerLimit()) { - low = max(low, theParameters.parameter(par).lowerLimit()) - } - if (theParameters.parameter(par).hasUpperLimit()) { - high = min(high, theParameters.parameter(par).upperLimit()) - } - } - val x0 = low - val stp = (high - low) / (maxsteps - 1.0) - for (i in 0 until maxsteps) { - params[par] = x0 + i.toDouble() * stp - val fval: Double = theFCN.value(params) - if (fval < theAmin) { - theParameters.setValue(par, params[par]) - theAmin = fval - } - result.add(Range(params[par], fval)) - } - return result - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnPlot.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnPlot.kt deleted file mode 100644 index 656dd8d35..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnPlot.kt +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import java.lang.StringBuffer -import kotlin.jvm.JvmOverloads - -/** - * MnPlot produces a text-screen graphical output of (x,y) points. E.g. from - * Scan or Contours. - * - * @version $Id$ - * @author Darksnake - */ -class MnPlot @JvmOverloads constructor(private val thePageWidth: Int = 80, private val thePageLength: Int = 30) { - private var bh = 0.0 - private var bl = 0.0 - private var bwid = 0.0 - private var nb = 0 - fun length(): Int { - return thePageLength - } - - private fun mnbins(a1: Double, a2: Double, naa: Int) { - - //*-*-*-*-*-*-*-*-*-*-*Compute reasonable histogram intervals*-*-*-*-*-*-*-*-* - //*-* ====================================== - //*-* Function TO DETERMINE REASONABLE HISTOGRAM INTERVALS - //*-* GIVEN ABSOLUTE UPPER AND LOWER BOUNDS A1 AND A2 - //*-* AND DESIRED MAXIMUM NUMBER OF BINS NAA - //*-* PROGRAM MAKES REASONABLE BINNING FROM BL TO BH OF WIDTH BWID - //*-* F. JAMES, AUGUST, 1974 , stolen for Minuit, 1988 - //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* - - /* Local variables */ - var awid: Double - var ah: Double - var sigfig: Double - var sigrnd: Double - var alb: Double - var kwid: Int - var lwid: Int - var na = 0 - var log_: Int - val al: Double = if (a1 < a2) a1 else a2 - ah = if (a1 > a2) a1 else a2 - if (al == ah) { - ah = al + 1 - } - - //*-*- IF NAA .EQ. -1 , PROGRAM USES BWID INPUT FROM CALLING ROUTINE - var skip = naa == -1 && bwid > 0 - if (!skip) { - na = naa - 1 - if (na < 1) { - na = 1 - } - } - while (true) { - if (!skip) { - //*-*- GET NOMINAL BIN WIDTH IN EXPON FORM - awid = (ah - al) / na.toDouble() - log_ = log10(awid) - if (awid <= 1) { - --log_ - } - sigfig = awid * pow(10.0, -log_.toDouble()) - //*-*- ROUND MANTISSA UP TO 2, 2.5, 5, OR 10 - if (sigfig <= 2) { - sigrnd = 2.0 - } else if (sigfig <= 2.5) { - sigrnd = 2.5 - } else if (sigfig <= 5) { - sigrnd = 5.0 - } else { - sigrnd = 1.0 - ++log_ - } - bwid = sigrnd * pow(10.0, log_.toDouble()) - } - alb = al / bwid - lwid = alb.toInt() - if (alb < 0) { - --lwid - } - bl = bwid * lwid.toDouble() - alb = ah / bwid + 1 - kwid = alb.toInt() - if (alb < 0) { - --kwid - } - bh = bwid * kwid.toDouble() - nb = kwid - lwid - if (naa <= 5) { - if (naa == -1) { - return - } - //*-*- REQUEST FOR ONE BIN IS DIFFICULT CASE - if (naa > 1 || nb == 1) { - return - } - bwid *= 2.0 - nb = 1 - return - } - if (nb shl 1 != naa) { - return - } - ++na - skip = false - continue - } - } - - private fun mnplot(xpt: DoubleArray, ypt: DoubleArray, chpt: StringBuffer, nxypt: Int, npagwd: Int, npagln: Int) { - //*-*-*-*Plots points in array xypt onto one page with labelled axes*-*-*-*-* - //*-* =========================================================== - //*-* NXYPT is the number of points to be plotted - //*-* XPT(I) = x-coord. of ith point - //*-* YPT(I) = y-coord. of ith point - //*-* CHPT(I) = character to be plotted at this position - //*-* the input point arrays XPT, YPT, CHPT are destroyed. - //*-* - //*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* - - /* Local variables */ - var xmin: Double - var xmax: Double - var ymax: Double - var savx: Double - var savy: Double - var yprt: Double - var xbest: Double - var ybest: Double - val xvalus = DoubleArray(12) - val any: Double - val iten: Int - var j: Int - var k: Int - var maxnx: Int - var maxny: Int - var iquit: Int - var ni: Int - var linodd: Int - var ibk: Int - var isp1: Int - var ks: Int - var ix: Int - var overpr: Boolean - val cline = StringBuffer(npagwd) - for (ii in 0 until npagwd) { - cline.append(' ') - } - var chsav: Char - val chbest: Char - - /* Function Body */ - //*-* Computing MIN - maxnx = if (npagwd - 20 < 100) npagwd - 20 else 100 - if (maxnx < 10) { - maxnx = 10 - } - maxny = npagln - if (maxny < 10) { - maxny = 10 - } - if (nxypt <= 1) { - return - } - xbest = xpt[0] - ybest = ypt[0] - chbest = chpt.get(0) - //*-*- order the points by decreasing y - val km1: Int = nxypt - 1 - var i: Int = 1 - while (i <= km1) { - iquit = 0 - ni = nxypt - i - j = 1 - while (j <= ni) { - if (ypt[j - 1] > ypt[j]) { - ++j - continue - } - savx = xpt[j - 1] - xpt[j - 1] = xpt[j] - xpt[j] = savx - savy = ypt[j - 1] - ypt[j - 1] = ypt[j] - ypt[j] = savy - chsav = chpt.get(j - 1) - chpt.setCharAt(j - 1, chpt.get(j)) - chpt.setCharAt(j, chsav) - iquit = 1 - ++j - } - if (iquit == 0) { - break - } - ++i - } - //*-*- find extreme values - xmax = xpt[0] - xmin = xmax - i = 1 - while (i <= nxypt) { - if (xpt[i - 1] > xmax) { - xmax = xpt[i - 1] - } - if (xpt[i - 1] < xmin) { - xmin = xpt[i - 1] - } - ++i - } - val dxx: Double = (xmax - xmin) * .001 - xmax += dxx - xmin -= dxx - mnbins(xmin, xmax, maxnx) - xmin = bl - xmax = bh - var nx: Int = nb - val bwidx: Double = bwid - ymax = ypt[0] - var ymin: Double = ypt[nxypt - 1] - if (ymax == ymin) { - ymax = ymin + 1 - } - val dyy: Double = (ymax - ymin) * .001 - ymax += dyy - ymin -= dyy - mnbins(ymin, ymax, maxny) - ymin = bl - ymax = bh - var ny: Int = nb - val bwidy: Double = bwid - any = ny.toDouble() - //*-*- if first point is blank, it is an 'origin' - if (chbest != ' ') { - xbest = (xmax + xmin) * .5 - ybest = (ymax + ymin) * .5 - } - //*-*- find scale constants - val ax: Double = 1 / bwidx - val ay: Double = 1 / bwidy - val bx: Double = -ax * xmin + 2 - val by: Double = -ay * ymin - 2 - //*-*- convert points to grid positions - i = 1 - while (i <= nxypt) { - xpt[i - 1] = ax * xpt[i - 1] + bx - ypt[i - 1] = any - ay * ypt[i - 1] - by - ++i - } - val nxbest: Int = (ax * xbest + bx).toInt() - val nybest: Int = (any - ay * ybest - by).toInt() - //*-*- print the points - ny += 2 - nx += 2 - isp1 = 1 - linodd = 1 - overpr = false - i = 1 - while (i <= ny) { - ibk = 1 - while (ibk <= nx) { - cline.setCharAt(ibk - 1, ' ') - ++ibk - } - // cline.setCharAt(nx,'\0'); - // cline.setCharAt(nx+1,'\0'); - cline.setCharAt(0, '.') - cline.setCharAt(nx - 1, '.') - cline.setCharAt(nxbest - 1, '.') - if (i == 1 || i == nybest || i == ny) { - j = 1 - while (j <= nx) { - cline.setCharAt(j - 1, '.') - ++j - } - } - yprt = ymax - (i - 1.0) * bwidy - var isplset = false - if (isp1 <= nxypt) { - //*-*- find the points to be plotted on this line - k = isp1 - while (k <= nxypt) { - ks = ypt[k - 1].toInt() - if (ks > i) { - isp1 = k - isplset = true - break - } - ix = xpt[k - 1].toInt() - if (cline.get(ix - 1) != '.' && cline.get(ix - 1) != ' ') { - if (cline.get(ix - 1) == chpt.get(k - 1)) { - ++k - continue - } - overpr = true - //*-*- OVERPR is true if one or more positions contains more than - //*-*- one point - cline.setCharAt(ix - 1, '&') - ++k - continue - } - cline.setCharAt(ix - 1, chpt.get(k - 1)) - ++k - } - if (!isplset) { - isp1 = nxypt + 1 - } - } - if (linodd != 1 && i != ny) { - linodd = 1 - java.lang.System.out.printf(" %s", cline.substring(0, 60)) - } else { - java.lang.System.out.printf(" %14.7g ..%s", yprt, cline.substring(0, 60)) - linodd = 0 - } - println() - ++i - } - //*-*- print labels on x-axis every ten columns - ibk = 1 - while (ibk <= nx) { - cline.setCharAt(ibk - 1, ' ') - if (ibk % 10 == 1) { - cline.setCharAt(ibk - 1, '/') - } - ++ibk - } - java.lang.System.out.printf(" %s", cline) - java.lang.System.out.printf("\n") - ibk = 1 - while (ibk <= 12) { - xvalus[ibk - 1] = xmin + (ibk - 1.0) * 10 * bwidx - ++ibk - } - java.lang.System.out.printf(" ") - iten = (nx + 9) / 10 - ibk = 1 - while (ibk <= iten) { - java.lang.System.out.printf(" %9.4g", xvalus[ibk - 1]) - ++ibk - } - java.lang.System.out.printf("\n") - if (overpr) { - val chmess = " Overprint character is &" - java.lang.System.out.printf(" ONE COLUMN=%13.7g%s", bwidx, chmess) - } else { - val chmess = " " - java.lang.System.out.printf(" ONE COLUMN=%13.7g%s", bwidx, chmess) - } - println() - } - - /** - * - * plot. - * - * @param points a [List] object. - */ - fun plot(points: List) { - val x = DoubleArray(points.size) - val y = DoubleArray(points.size) - val chpt = StringBuffer(points.size) - for ((i, ipoint) in points.withIndex()) { - x[i] = ipoint.getFirst() - y[i] = ipoint.getSecond() - chpt.append('*') - } - mnplot(x, y, chpt, points.size, width(), length()) - } - - /** - * - * plot. - * - * @param xmin a double. - * @param ymin a double. - * @param points a [List] object. - */ - fun plot(xmin: Double, ymin: Double, points: List) { - val x = DoubleArray(points.size + 2) - x[0] = xmin - x[1] = xmin - val y = DoubleArray(points.size + 2) - y[0] = ymin - y[1] = ymin - val chpt = StringBuffer(points.size + 2) - chpt.append(' ') - chpt.append('X') - var i = 2 - for (ipoint in points) { - x[i] = ipoint.getFirst() - y[i] = ipoint.getSecond() - chpt.append('*') - i++ - } - mnplot(x, y, chpt, points.size + 2, width(), length()) - } - - fun width(): Int { - return thePageWidth - } - /** - * - * Constructor for MnPlot. - * - * @param thePageWidth a int. - * @param thePageLength a int. - */ - /** - * - * Constructor for MnPlot. - */ - init { - if (thePageWidth > 120) { - thePageWidth = 120 - } - if (thePageLength > 56) { - thePageLength = 56 - } - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnPosDef.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnPosDef.kt deleted file mode 100644 index f94e387d9..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnPosDef.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MINUITPlugin - -/** - * - * @version $Id$ - */ -internal object MnPosDef { - fun test(st: MinimumState, prec: MnMachinePrecision): MinimumState { - val err: MinimumError = test(st.error(), prec) - return MinimumState(st.parameters(), err, st.gradient(), st.edm(), st.nfcn()) - } - - fun test(e: MinimumError, prec: MnMachinePrecision): MinimumError { - val err: MnAlgebraicSymMatrix = e.invHessian().copy() - if (err.size() === 1 && err[0, 0] < prec.eps()) { - err[0, 0] = 1.0 - return MinimumError(err, MnMadePosDef()) - } - if (err.size() === 1 && err[0, 0] > prec.eps()) { - return e - } - // std::cout<<"MnPosDef init matrix= "< 0.0) { - os.printf(" limited || %10g", ipar.value()) - if (abs(ipar.value() - ipar.lowerLimit()) < par.precision().eps2()) { - os.print("* ") - atLoLim = true - } - if (abs(ipar.value() - ipar.upperLimit()) < par.precision().eps2()) { - os.print("**") - atHiLim = true - } - os.printf(" || %10g\n", ipar.error()) - } else { - os.printf(" free || %10g || no\n", ipar.value()) - } - } else { - if (ipar.error() > 0.0) { - os.printf(" free || %10g || %10g\n", ipar.value(), ipar.error()) - } else { - os.printf(" free || %10g || no\n", ipar.value()) - } - } - } - os.println() - if (atLoLim) { - os.print("* parameter is at lower limit") - } - if (atHiLim) { - os.print("** parameter is at upper limit") - } - os.println() - } - - /** - * - * print. - * - * @param os a [PrintWriter] object. - * @param matrix a [hep.dataforge.MINUIT.MnUserCovariance] object. - */ - fun print(os: PrintWriter, matrix: MnUserCovariance) { - os.println() - os.println("MnUserCovariance: ") - run { - os.println() - val n: Int = matrix.nrow() - for (i in 0 until n) { - for (j in 0 until n) { - os.printf("%10g ", matrix[i, j]) - } - os.println() - } - } - os.println() - os.println("MnUserCovariance parameter correlations: ") - run { - os.println() - val n: Int = matrix.nrow() - for (i in 0 until n) { - val di: Double = matrix[i, i] - for (j in 0 until n) { - val dj: Double = matrix[j, j] - os.printf("%g ", matrix[i, j] / sqrt(abs(di * dj))) - } - os.println() - } - } - } - - /** - * - * print. - * - * @param os a [PrintWriter] object. - * @param coeff a [hep.dataforge.MINUIT.MnGlobalCorrelationCoeff] object. - */ - fun print(os: PrintWriter, coeff: MnGlobalCorrelationCoeff) { - os.println() - os.println("MnGlobalCorrelationCoeff: ") - run { - os.println() - for (i in 0 until coeff.globalCC().length) { - os.printf("%g\n", coeff.globalCC()[i]) - } - } - } - - /** - * - * print. - * - * @param os a [PrintWriter] object. - * @param state a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun print(os: PrintWriter, state: MnUserParameterState) { - os.println() - if (!state.isValid()) { - os.println() - os.println("WARNING: MnUserParameterState is not valid.") - os.println() - } - os.println("# of function calls: " + state.nfcn()) - os.println("function value: " + state.fval()) - os.println("expected distance to the minimum (edm): " + state.edm()) - os.println("external parameters: " + state.parameters()) - if (state.hasCovariance()) { - os.println("covariance matrix: " + state.covariance()) - } - if (state.hasGlobalCC()) { - os.println("global correlation coefficients : " + state.globalCC()) - } - if (!state.isValid()) { - os.println("WARNING: MnUserParameterState is not valid.") - } - os.println() - } - - /** - * - * print. - * - * @param os a [PrintWriter] object. - * @param me a [hep.dataforge.MINUIT.MinosError] object. - */ - fun print(os: PrintWriter, me: MinosError) { - os.println() - os.printf("Minos # of function calls: %d\n", me.nfcn()) - if (!me.isValid()) { - os.println("Minos error is not valid.") - } - if (!me.lowerValid()) { - os.println("lower Minos error is not valid.") - } - if (!me.upperValid()) { - os.println("upper Minos error is not valid.") - } - if (me.atLowerLimit()) { - os.println("Minos error is lower limit of parameter " + me.parameter()) - } - if (me.atUpperLimit()) { - os.println("Minos error is upper limit of parameter " + me.parameter()) - } - if (me.atLowerMaxFcn()) { - os.println("Minos number of function calls for lower error exhausted.") - } - if (me.atUpperMaxFcn()) { - os.println("Minos number of function calls for upper error exhausted.") - } - if (me.lowerNewMin()) { - os.println("Minos found a new minimum in negative direction.") - os.println(me.lowerState()) - } - if (me.upperNewMin()) { - os.println("Minos found a new minimum in positive direction.") - os.println(me.upperState()) - } - os.println("# ext. || name || value@min || negative || positive ") - os.printf("%4d||%10s||%10g||%10g||%10g\n", - me.parameter(), - me.lowerState().name(me.parameter()), - me.min(), - me.lower(), - me.upper()) - os.println() - } - - /** - * - * print. - * - * @param os a [PrintWriter] object. - * @param ce a [hep.dataforge.MINUIT.ContoursError] object. - */ - fun print(os: PrintWriter, ce: ContoursError) { - os.println() - os.println("Contours # of function calls: " + ce.nfcn()) - os.println("MinosError in x: ") - os.println(ce.xMinosError()) - os.println("MinosError in y: ") - os.println(ce.yMinosError()) - val plot = MnPlot() - plot.plot(ce.xmin(), ce.ymin(), ce.points()) - for ((i, ipoint) in ce.points().withIndex()) { - os.printf("%d %10g %10g\n", i, ipoint.getFirst(), ipoint.getSecond()) - } - os.println() - } - - fun toString(x: RealVector): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(x: MnAlgebraicSymMatrix?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(min: FunctionMinimum?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, min) } - return writer.toString() - } - - fun toString(x: MinimumState?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(x: MnUserParameters?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(x: MnUserCovariance?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(x: MnGlobalCorrelationCoeff?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(x: MnUserParameterState?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(x: MinosError?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } - - fun toString(x: ContoursError?): String { - val writer: java.io.StringWriter = java.io.StringWriter() - PrintWriter(writer).use { pw -> print(pw, x) } - return writer.toString() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnScan.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnScan.kt deleted file mode 100644 index 63e565b4f..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnScan.kt +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* - -/** - * MnScan scans the value of the user function by varying one parameter. It is - * sometimes useful for debugging the user function or finding a reasonable - * starting point. - * construct from MultiFunction + MnUserParameterState + MnStrategy - * - * @param str a [hep.dataforge.MINUIT.MnStrategy] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameterState] object. - * @param fcn a [MultiFunction] object. - * @version $Id$ - * @author Darksnake - */ -class MnScan(fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) : MnApplication(fcn, par, str) { - private val theMinimizer: ScanMinimizer = ScanMinimizer() - - /** - * construct from MultiFunction + double[] for parameters and errors - * with default strategy - * - * @param err an array of double. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray) : this(fcn, par, err, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and errors - * - * @param stra a int. - * @param err an array of double. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn, - MnUserParameterState(par, err), - MnStrategy(stra)) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance) : this(fcn, par, cov, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters with default - * strategy - * - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters) : this(fcn, par, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters - * - * @param stra a int. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn, - MnUserParameterState(par), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn, - par, - cov, - DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - override fun minimizer(): ModularFunctionMinimizer { - return theMinimizer - } - - /** - * - * scan. - * - * @param par a int. - * @return a [List] object. - */ - fun scan(par: Int): List { - return scan(par, 41) - } - - /** - * - * scan. - * - * @param par a int. - * @param maxsteps a int. - * @return a [List] object. - */ - fun scan(par: Int, maxsteps: Int): List { - return scan(par, maxsteps, 0.0, 0.0) - } - - /** - * Scans the value of the user function by varying parameter number par, - * leaving all other parameters fixed at the current value. If par is not - * specified, all variable parameters are scanned in sequence. The number of - * points npoints in the scan is 40 by default, and cannot exceed 100. The - * range of the scan is by default 2 standard deviations on each side of the - * current best value, but can be specified as from low to high. After each - * scan, if a new minimum is found, the best parameter values are retained - * as start values for future scans or minimizations. The curve resulting - * from each scan can be plotted on the output terminal using MnPlot in - * order to show the approximate behaviour of the function. - * - * @param high a double. - * @param par a int. - * @param maxsteps a int. - * @param low a double. - * @return a [List] object. - */ - fun scan(par: Int, maxsteps: Int, low: Double, high: Double): List { - val scan = MnParameterScan(theFCN, theState.parameters()) - var amin: Double = scan.fval() - val result: List = scan.scan(par, maxsteps, low, high) - if (scan.fval() < amin) { - theState.setValue(par, scan.parameters().value(par)) - amin = scan.fval() - } - return result - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnSeedGenerator.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnSeedGenerator.kt deleted file mode 100644 index a42edf4f1..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnSeedGenerator.kt +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MINUITPlugin -import ru.inr.mass.minuit.* -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * - * @version $Id$ - */ -internal class MnSeedGenerator : MinimumSeedGenerator { - /** {@inheritDoc} */ - fun generate(fcn: MnFcn, gc: GradientCalculator, st: MnUserParameterState, stra: MnStrategy): MinimumSeed { - val n: Int = st.variableParameters() - val prec: MnMachinePrecision = st.precision() - - // initial starting values - val x: RealVector = ArrayRealVector(n) - for (i in 0 until n) { - x.setEntry(i, st.intParameters()[i]) - } - val fcnmin: Double = fcn.value(x) - val pa = MinimumParameters(x, fcnmin) - val dgrad: FunctionGradient - if (gc is AnalyticalGradientCalculator) { - val igc = InitialGradientCalculator(fcn, st.getTransformation(), stra) - val tmp: FunctionGradient = igc.gradient(pa) - val grd: FunctionGradient = gc.gradient(pa) - dgrad = FunctionGradient(grd.getGradient(), tmp.getGradientDerivative(), tmp.getStep()) - if (gc.checkGradient()) { - val good = true - val hgc = HessianGradientCalculator(fcn, st.getTransformation(), MnStrategy(2)) - val hgrd: Pair = hgc.deltaGradient(pa, dgrad) - for (i in 0 until n) { - val provided: Double = grd.getGradient().getEntry(i) - val calculated: Double = hgrd.getFirst().getGradient().getEntry(i) - val delta: Double = hgrd.getSecond().getEntry(i) - if (abs(calculated - provided) > delta) { - MINUITPlugin.logStatic("" - + "gradient discrepancy of external parameter \"%d\" " - + "(internal parameter \"%d\") too large. Expected: \"%f\", provided: \"%f\"", - st.getTransformation().extOfInt(i), i, provided, calculated) - -// -// MINUITPlugin.logStatic("gradient discrepancy of external parameter " -// + st.getTransformation().extOfInt(i) -// + " (internal parameter " + i + ") too large."); -// good = false; - } - } - if (!good) { - MINUITPlugin.logStatic("Minuit does not accept user specified gradient.") - // assert(good); - } - } - } else { - dgrad = gc.gradient(pa) - } - val mat = MnAlgebraicSymMatrix(n) - var dcovar = 1.0 - if (st.hasCovariance()) { - for (i in 0 until n) { - for (j in i until n) { - mat[i, j] = st.intCovariance()[i, j] - } - } - dcovar = 0.0 - } else { - for (i in 0 until n) { - mat[i, i] = if (abs(dgrad.getGradientDerivative() - .getEntry(i)) > prec.eps2() - ) 1.0 / dgrad.getGradientDerivative().getEntry(i) else 1.0 - } - } - val err = MinimumError(mat, dcovar) - val edm: Double = VariableMetricEDMEstimator().estimate(dgrad, err) - var state = MinimumState(pa, err, dgrad, edm, fcn.numOfCalls()) - if (NegativeG2LineSearch.hasNegativeG2(dgrad, prec)) { - state = if (gc is AnalyticalGradientCalculator) { - val ngc = Numerical2PGradientCalculator(fcn, st.getTransformation(), stra) - NegativeG2LineSearch.search(fcn, state, ngc, prec) - } else { - NegativeG2LineSearch.search(fcn, state, gc, prec) - } - } - if (stra.strategy() === 2 && !st.hasCovariance()) { - //calculate full 2nd derivative - val tmp: MinimumState = MnHesse(stra).calculate(fcn, state, st.getTransformation(), 0) - return MinimumSeed(tmp, st.getTransformation()) - } - return MinimumSeed(state, st.getTransformation()) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnSimplex.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnSimplex.kt deleted file mode 100644 index b00745f26..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnSimplex.kt +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* - -/** - * SIMPLEX is a function minimization method using the simplex method of Nelder - * and Mead. MnSimplex provides minimization of the function by the method of - * SIMPLEX and the functionality for parameters interaction. It also retains the - * result from the last minimization in case the user may want to do subsequent - * minimization steps with parameter interactions in between the minimization - * requests. As SIMPLEX is a stepping method it does not produce a covariance - * matrix. - * - * @version $Id$ - * @author Darksnake - */ -class MnSimplex -/** - * construct from MultiFunction + MnUserParameterState + MnStrategy - * - * @param str a [hep.dataforge.MINUIT.MnStrategy] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameterState] object. - * @param fcn a [MultiFunction] object. - */ - (fcn: MultiFunction?, par: MnUserParameterState, str: MnStrategy) : MnApplication(fcn, par, str) { - private val theMinimizer: SimplexMinimizer = SimplexMinimizer() - - /** - * construct from MultiFunction + double[] for parameters and errors - * with default strategy - * - * @param err an array of double. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray) : this(fcn, par, err, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and errors - * - * @param stra a int. - * @param err an array of double. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, err: DoubleArray, stra: Int) : this(fcn, - MnUserParameterState(par, err), - MnStrategy(stra)) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par an array of double. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance) : this(fcn, par, cov, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + double[] for parameters and - * MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par an array of double. - */ - constructor(fcn: MultiFunction?, par: DoubleArray, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters with default - * strategy - * - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters) : this(fcn, par, DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters - * - * @param stra a int. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, stra: Int) : this(fcn, - MnUserParameterState(par), - MnStrategy(stra)) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * with default strategy - * - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - * @param fcn a [MultiFunction] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance) : this(fcn, - par, - cov, - DEFAULT_STRATEGY) - - /** - * construct from MultiFunction + MnUserParameters + MnUserCovariance - * - * @param stra a int. - * @param cov a [hep.dataforge.MINUIT.MnUserCovariance] object. - * @param fcn a [MultiFunction] object. - * @param par a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - constructor(fcn: MultiFunction?, par: MnUserParameters, cov: MnUserCovariance, stra: Int) : this(fcn, - MnUserParameterState(par, cov), - MnStrategy(stra)) - - /** {@inheritDoc} */ - override fun minimizer(): ModularFunctionMinimizer { - return theMinimizer - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnStrategy.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnStrategy.kt deleted file mode 100644 index 31b894665..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnStrategy.kt +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * API class for defining three levels of strategies: low (0), medium (1), high - * (2). - * - * - * At many places in the analysis of the FCN (the user provided function), - * MINUIT must decide whether to be safe and waste a few function calls - * in order to know where it is, or to be fast and attempt to get the - * requested results with the fewest possible calls at a certain risk of not - * obtaining the precision desired by the user. In order to allow the user to - * infuence these decisions, the MnStrategy class allows the user to control - * different settings. MnStrategy can be instantiated with three different - * minimization quality levels for low (0), medium (1) and high (2) quality. - * Default settings for iteration cycles and tolerances are initialized then. - * - * - * The default setting is set for medium quality. Value 0 (low) indicates to - * MINUIT that it should economize function calls; it is intended for cases - * where there are many variable parameters and/or the function takes a long - * time to calculate and/or the user is not interested in very precise values - * for parameter errors. On the other hand, value 2 (high) indicates that MINUIT - * is allowed to waste function calls in order to be sure that all values are - * precise; it is it is intended for cases where the function is evaluated in a - * relatively short time and/or where the parameter errors must be calculated - * reliably. - * - * In addition all constants set in MnStrategy can be changed individually by - * the user, e.g. the number of iteration cycles in the numerical gradient. - * - * - * - * - * Acts on: Migrad (behavioural), Minos (lowers strategy by 1 for Minos-own - * minimization), Hesse (iterations), Numerical2PDerivative (iterations) - * - * @author Darksnake - * @version $Id$ - */ -class MnStrategy { - private var theGradNCyc = 0 - private var theGradTlr = 0.0 - private var theGradTlrStp = 0.0 - private var theHessGradNCyc = 0 - - //default strategy - private var theHessNCyc = 0 - private var theHessTlrG2 = 0.0 - private var theHessTlrStp = 0.0 - private var theStrategy = 0 - - /** - * Creates a MnStrategy object with the default strategy (medium) - */ - constructor() { - setMediumStrategy() - } - //user defined strategy (0, 1, >=2) - /** - * Creates a MnStrategy object with the user specified strategy. - * - * @param stra The use defined strategy, 0=low, 1 medium, 2=high. - */ - constructor(stra: Int) { - if (stra == 0) { - setLowStrategy() - } else if (stra == 1) { - setMediumStrategy() - } else { - setHighStrategy() - } - } - - /** - * - * gradientNCycles. - * - * @return a int. - */ - fun gradientNCycles(): Int { - return theGradNCyc - } - - /** - * - * gradientStepTolerance. - * - * @return a double. - */ - fun gradientStepTolerance(): Double { - return theGradTlrStp - } - - /** - * - * gradientTolerance. - * - * @return a double. - */ - fun gradientTolerance(): Double { - return theGradTlr - } - - /** - * - * hessianG2Tolerance. - * - * @return a double. - */ - fun hessianG2Tolerance(): Double { - return theHessTlrG2 - } - - /** - * - * hessianGradientNCycles. - * - * @return a int. - */ - fun hessianGradientNCycles(): Int { - return theHessGradNCyc - } - - /** - * - * hessianNCycles. - * - * @return a int. - */ - fun hessianNCycles(): Int { - return theHessNCyc - } - - /** - * - * hessianStepTolerance. - * - * @return a double. - */ - fun hessianStepTolerance(): Double { - return theHessTlrStp - } - - /** - * - * isHigh. - * - * @return a boolean. - */ - fun isHigh(): Boolean { - return theStrategy >= 2 - } - - /** - * - * isLow. - * - * @return a boolean. - */ - fun isLow(): Boolean { - return theStrategy <= 0 - } - - /** - * - * isMedium. - * - * @return a boolean. - */ - fun isMedium(): Boolean { - return theStrategy == 1 - } - - /** - * - * setGradientNCycles. - * - * @param n a int. - */ - fun setGradientNCycles(n: Int) { - theGradNCyc = n - } - - /** - * - * setGradientStepTolerance. - * - * @param stp a double. - */ - fun setGradientStepTolerance(stp: Double) { - theGradTlrStp = stp - } - - /** - * - * setGradientTolerance. - * - * @param toler a double. - */ - fun setGradientTolerance(toler: Double) { - theGradTlr = toler - } - - /** - * - * setHessianG2Tolerance. - * - * @param toler a double. - */ - fun setHessianG2Tolerance(toler: Double) { - theHessTlrG2 = toler - } - - /** - * - * setHessianGradientNCycles. - * - * @param n a int. - */ - fun setHessianGradientNCycles(n: Int) { - theHessGradNCyc = n - } - - /** - * - * setHessianNCycles. - * - * @param n a int. - */ - fun setHessianNCycles(n: Int) { - theHessNCyc = n - } - - /** - * - * setHessianStepTolerance. - * - * @param stp a double. - */ - fun setHessianStepTolerance(stp: Double) { - theHessTlrStp = stp - } - - fun setHighStrategy() { - theStrategy = 2 - setGradientNCycles(5) - setGradientStepTolerance(0.1) - setGradientTolerance(0.02) - setHessianNCycles(7) - setHessianStepTolerance(0.1) - setHessianG2Tolerance(0.02) - setHessianGradientNCycles(6) - } - - /** - * - * setLowStrategy. - */ - fun setLowStrategy() { - theStrategy = 0 - setGradientNCycles(2) - setGradientStepTolerance(0.5) - setGradientTolerance(0.1) - setHessianNCycles(3) - setHessianStepTolerance(0.5) - setHessianG2Tolerance(0.1) - setHessianGradientNCycles(1) - } - - /** - * - * setMediumStrategy. - */ - fun setMediumStrategy() { - theStrategy = 1 - setGradientNCycles(3) - setGradientStepTolerance(0.3) - setGradientTolerance(0.05) - setHessianNCycles(5) - setHessianStepTolerance(0.3) - setHessianG2Tolerance(0.05) - setHessianGradientNCycles(2) - } - - /** - * - * strategy. - * - * @return a int. - */ - fun strategy(): Int { - return theStrategy - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUserCovariance.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserCovariance.kt deleted file mode 100644 index 297588f8e..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnUserCovariance.kt +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * MnUserCovariance is the external covariance matrix designed for the - * interaction of the user. The result of the minimization (internal covariance - * matrix) is converted into the user representable format. It can also be used - * as input prior to the minimization. The size of the covariance matrix is - * according to the number of variable parameters (free and limited). - * - * @version $Id$ - * @author Darksnake - */ -class MnUserCovariance { - private var theData: DoubleArray - private var theNRow: Int - - private constructor(other: MnUserCovariance) { - theData = other.theData.clone() - theNRow = other.theNRow - } - - internal constructor() { - theData = DoubleArray(0) - theNRow = 0 - } - - /* - * covariance matrix is stored in upper triangular packed storage format, - * e.g. the elements in the array are arranged like - * {a(0,0), a(0,1), a(1,1), a(0,2), a(1,2), a(2,2), ...}, - * the size is nrow*(nrow+1)/2. - */ - internal constructor(data: DoubleArray, nrow: Int) { - require(data.size == nrow * (nrow + 1) / 2) { "Inconsistent arguments" } - theData = data - theNRow = nrow - } - - /** - * - * Constructor for MnUserCovariance. - * - * @param nrow a int. - */ - constructor(nrow: Int) { - theData = DoubleArray(nrow * (nrow + 1) / 2) - theNRow = nrow - } - - /** - * - * copy. - * - * @return a [hep.dataforge.MINUIT.MnUserCovariance] object. - */ - fun copy(): MnUserCovariance { - return MnUserCovariance(this) - } - - fun data(): DoubleArray { - return theData - } - - /** - * - * get. - * - * @param row a int. - * @param col a int. - * @return a double. - */ - operator fun get(row: Int, col: Int): Double { - require(!(row >= theNRow || col >= theNRow)) - return if (row > col) { - theData[col + row * (row + 1) / 2] - } else { - theData[row + col * (col + 1) / 2] - } - } - - /** - * - * ncol. - * - * @return a int. - */ - fun ncol(): Int { - return theNRow - } - - /** - * - * nrow. - * - * @return a int. - */ - fun nrow(): Int { - return theNRow - } - - fun scale(f: Double) { - for (i in theData.indices) { - theData[i] *= f - } - } - - /** - * - * set. - * - * @param row a int. - * @param col a int. - * @param value a double. - */ - operator fun set(row: Int, col: Int, value: Double) { - require(!(row >= theNRow || col >= theNRow)) - if (row > col) { - theData[col + row * (row + 1) / 2] = value - } else { - theData[row + col * (col + 1) / 2] = value - } - } - - fun size(): Int { - return theData.size - } - - /** {@inheritDoc} */ - override fun toString(): String { - return MnPrint.toString(this) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUserFcn.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserFcn.kt deleted file mode 100644 index 8198a41ab..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnUserFcn.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction - -/** - * - * @version $Id$ - */ -internal class MnUserFcn(fcn: MultiFunction?, errDef: Double, trafo: MnUserTransformation) : MnFcn(fcn, errDef) { - private val theTransform: MnUserTransformation = trafo - override fun value(v: RealVector): Double { - return super.value(theTransform.transform(v)) - } - -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt deleted file mode 100644 index e80dd60a1..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameterState.kt +++ /dev/null @@ -1,756 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.minuit.* - -/** - * The class MnUserParameterState contains the MnUserParameters and the - * MnUserCovariance. It can be created on input by the user, or by MINUIT itself - * as user representable format of the result of the minimization. - * - * @version $Id$ - * @author Darksnake - */ -class MnUserParameterState { - private var theCovariance: MnUserCovariance - private var theCovarianceValid = false - private var theEDM = 0.0 - private var theFVal = 0.0 - private var theGCCValid = false - private var theGlobalCC: MnGlobalCorrelationCoeff? = null - private var theIntCovariance: MnUserCovariance - private var theIntParameters: MutableList - private var theNFcn = 0 - private var theParameters: MnUserParameters - private var theValid: Boolean - - internal constructor() { - theValid = false - theCovarianceValid = false - theParameters = MnUserParameters() - theCovariance = MnUserCovariance() - theIntParameters = java.util.ArrayList() - theIntCovariance = MnUserCovariance() - } - - private constructor(other: MnUserParameterState) { - theValid = other.theValid - theCovarianceValid = other.theCovarianceValid - theGCCValid = other.theGCCValid - theFVal = other.theFVal - theEDM = other.theEDM - theNFcn = other.theNFcn - theParameters = other.theParameters.copy() - theCovariance = other.theCovariance - theGlobalCC = other.theGlobalCC - theIntParameters = java.util.ArrayList(other.theIntParameters) - theIntCovariance = other.theIntCovariance.copy() - } - - /** - * construct from user parameters (before minimization) - * @param par - * @param err - */ - internal constructor(par: DoubleArray, err: DoubleArray) { - theValid = true - theParameters = MnUserParameters(par, err) - theCovariance = MnUserCovariance() - theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList(par.size) - for (i in par.indices) { - theIntParameters.add(par[i]) - } - theIntCovariance = MnUserCovariance() - } - - internal constructor(par: MnUserParameters) { - theValid = true - theParameters = par - theCovariance = MnUserCovariance() - theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList(par.variableParameters()) - theIntCovariance = MnUserCovariance() - val i = 0 - for (ipar in par.parameters()) { - if (ipar.isConst() || ipar.isFixed()) { - continue - } - if (ipar.hasLimits()) { - theIntParameters.add(ext2int(ipar.number(), ipar.value())) - } else { - theIntParameters.add(ipar.value()) - } - } - } - - /** - * construct from user parameters + covariance (before minimization) - * @param nrow - * @param cov - */ - internal constructor(par: DoubleArray, cov: DoubleArray, nrow: Int) { - theValid = true - theCovarianceValid = true - theCovariance = MnUserCovariance(cov, nrow) - theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList(par.size) - theIntCovariance = MnUserCovariance(cov, nrow) - val err = DoubleArray(par.size) - for (i in par.indices) { - assert(theCovariance[i, i] > 0.0) - err[i] = sqrt(theCovariance[i, i]) - theIntParameters.add(par[i]) - } - theParameters = MnUserParameters(par, err) - assert(theCovariance.nrow() === variableParameters()) - } - - internal constructor(par: DoubleArray, cov: MnUserCovariance) { - theValid = true - theCovarianceValid = true - theCovariance = cov - theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList(par.size) - theIntCovariance = cov.copy() - require(!(theCovariance.nrow() !== variableParameters())) { "Bad covariance size" } - val err = DoubleArray(par.size) - for (i in par.indices) { - require(theCovariance[i, i] > 0.0) { "Bad covariance" } - err[i] = sqrt(theCovariance[i, i]) - theIntParameters.add(par[i]) - } - theParameters = MnUserParameters(par, err) - } - - internal constructor(par: MnUserParameters, cov: MnUserCovariance) { - theValid = true - theCovarianceValid = true - theParameters = par - theCovariance = cov - theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList() - theIntCovariance = cov.copy() - theIntCovariance.scale(0.5) - val i = 0 - for (ipar in par.parameters()) { - if (ipar.isConst() || ipar.isFixed()) { - continue - } - if (ipar.hasLimits()) { - theIntParameters.add(ext2int(ipar.number(), ipar.value())) - } else { - theIntParameters.add(ipar.value()) - } - } - assert(theCovariance.nrow() === variableParameters()) - } - - /** - * construct from internal parameters (after minimization) - * @param trafo - * @param up - */ - internal constructor(st: MinimumState, up: Double, trafo: MnUserTransformation) { - theValid = st.isValid() - theCovarianceValid = false - theGCCValid = false - theFVal = st.fval() - theEDM = st.edm() - theNFcn = st.nfcn() - theParameters = MnUserParameters() - theCovariance = MnUserCovariance() - theGlobalCC = MnGlobalCorrelationCoeff() - theIntParameters = java.util.ArrayList() - theIntCovariance = MnUserCovariance() - for (ipar in trafo.parameters()) { - if (ipar.isConst()) { - add(ipar.name(), ipar.value()) - } else if (ipar.isFixed()) { - add(ipar.name(), ipar.value(), ipar.error()) - if (ipar.hasLimits()) { - if (ipar.hasLowerLimit() && ipar.hasUpperLimit()) { - setLimits(ipar.name(), ipar.lowerLimit(), ipar.upperLimit()) - } else if (ipar.hasLowerLimit() && !ipar.hasUpperLimit()) { - setLowerLimit(ipar.name(), ipar.lowerLimit()) - } else { - setUpperLimit(ipar.name(), ipar.upperLimit()) - } - } - fix(ipar.name()) - } else if (ipar.hasLimits()) { - val i: Int = trafo.intOfExt(ipar.number()) - val err: Double = if (st.hasCovariance()) sqrt(2.0 * up * st.error().invHessian()[i, i]) else st.parameters().dirin().getEntry(i) - add(ipar.name(), - trafo.int2ext(i, st.vec().getEntry(i)), - trafo.int2extError(i, st.vec().getEntry(i), err)) - if (ipar.hasLowerLimit() && ipar.hasUpperLimit()) { - setLimits(ipar.name(), ipar.lowerLimit(), ipar.upperLimit()) - } else if (ipar.hasLowerLimit() && !ipar.hasUpperLimit()) { - setLowerLimit(ipar.name(), ipar.lowerLimit()) - } else { - setUpperLimit(ipar.name(), ipar.upperLimit()) - } - } else { - val i: Int = trafo.intOfExt(ipar.number()) - val err: Double = if (st.hasCovariance()) sqrt(2.0 * up * st.error().invHessian()[i, i]) else st.parameters().dirin().getEntry(i) - add(ipar.name(), st.vec().getEntry(i), err) - } - } - theCovarianceValid = st.error().isValid() - if (theCovarianceValid) { - theCovariance = trafo.int2extCovariance(st.vec(), st.error().invHessian()) - theIntCovariance = MnUserCovariance(st.error().invHessian().data().clone(), st.error().invHessian().nrow()) - theCovariance.scale(2.0 * up) - theGlobalCC = MnGlobalCorrelationCoeff(st.error().invHessian()) - theGCCValid = true - assert(theCovariance.nrow() === variableParameters()) - } - } - - /** - * add free parameter name, value, error - * - * @param err a double. - * @param val a double. - * @param name a [String] object. - */ - fun add(name: String, `val`: Double, err: Double) { - theParameters.add(name, `val`, err) - theIntParameters.add(`val`) - theCovarianceValid = false - theGCCValid = false - theValid = true - } - - /** - * add limited parameter name, value, lower bound, upper bound - * - * @param name a [String] object. - * @param val a double. - * @param low a double. - * @param err a double. - * @param up a double. - */ - fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) { - theParameters.add(name, `val`, err, low, up) - theCovarianceValid = false - theIntParameters.add(ext2int(index(name), `val`)) - theGCCValid = false - theValid = true - } - - /** - * add const parameter name, value - * - * @param name a [String] object. - * @param val a double. - */ - fun add(name: String, `val`: Double) { - theParameters.add(name, `val`) - theValid = true - } - - /** - * - * copy. - * - * @return a [hep.dataforge.MINUIT.MnUserParameterState] object. - */ - fun copy(): MnUserParameterState { - return MnUserParameterState(this) - } - - /** - * Covariance matrix in the external representation - * - * @return a [hep.dataforge.MINUIT.MnUserCovariance] object. - */ - fun covariance(): MnUserCovariance { - return theCovariance - } - - /** - * Returns the expected vertival distance to the minimum (EDM) - * - * @return a double. - */ - fun edm(): Double { - return theEDM - } - - /** - * - * error. - * - * @param index a int. - * @return a double. - */ - fun error(index: Int): Double { - return theParameters.error(index) - } - - /** - * - * error. - * - * @param name a [String] object. - * @return a double. - */ - fun error(name: String?): Double { - return error(index(name)) - } - - /** - * - * errors. - * - * @return an array of double. - */ - fun errors(): DoubleArray { - return theParameters.errors() - } - - fun ext2int(i: Int, `val`: Double): Double { - return theParameters.trafo().ext2int(i, `val`) - } - - /** - * - * extOfInt. - * - * @param internal a int. - * @return a int. - */ - fun extOfInt(internal: Int): Int { - return theParameters.trafo().extOfInt(internal) - } - /// interaction via external number of parameter - /** - * - * fix. - * - * @param e a int. - */ - fun fix(e: Int) { - val i = intOfExt(e) - if (theCovarianceValid) { - theCovariance = MnCovarianceSqueeze.squeeze(theCovariance, i) - theIntCovariance = MnCovarianceSqueeze.squeeze(theIntCovariance, i) - } - theIntParameters.removeAt(i) - theParameters.fix(e) - theGCCValid = false - } - /// interaction via name of parameter - /** - * - * fix. - * - * @param name a [String] object. - */ - fun fix(name: String?) { - fix(index(name)) - } - - /** - * returns the function value at the minimum - * - * @return a double. - */ - fun fval(): Double { - return theFVal - } - - /** - * transformation internal <-> external - * @return - */ - fun getTransformation(): MnUserTransformation { - return theParameters.trafo() - } - - fun globalCC(): MnGlobalCorrelationCoeff? { - return theGlobalCC - } - - /** - * Returns - * true if the the state has a valid covariance, - * false otherwise. - * - * @return a boolean. - */ - fun hasCovariance(): Boolean { - return theCovarianceValid - } - - /** - * - * hasGlobalCC. - * - * @return a boolean. - */ - fun hasGlobalCC(): Boolean { - return theGCCValid - } - - /** - * convert name into external number of parameter - * - * @param name a [String] object. - * @return a int. - */ - fun index(name: String?): Int { - return theParameters.index(name) - } - - // transformation internal <-> external - fun int2ext(i: Int, `val`: Double): Double { - return theParameters.trafo().int2ext(i, `val`) - } - - fun intCovariance(): MnUserCovariance { - return theIntCovariance - } - - fun intOfExt(ext: Int): Int { - return theParameters.trafo().intOfExt(ext) - } - - /** - * Minuit internal representation - * @return - */ - fun intParameters(): List { - return theIntParameters - } - - /** - * Returns - * true if the the state is valid, - * false if not - * - * @return a boolean. - */ - fun isValid(): Boolean { - return theValid - } - - // facade: forward interface of MnUserParameters and MnUserTransformation - fun minuitParameters(): List { - return theParameters.parameters() - } - - /** - * convert external number into name of parameter - * - * @param index a int. - * @return a [String] object. - */ - fun name(index: Int): String { - return theParameters.name(index) - } - - /** - * Returns the number of function calls during the minimization. - * - * @return a int. - */ - fun nfcn(): Int { - return theNFcn - } - - fun parameter(i: Int): MinuitParameter { - return theParameters.parameter(i) - } - - //user external representation - fun parameters(): MnUserParameters { - return theParameters - } - - /** - * access to parameters and errors in column-wise representation - * - * @return an array of double. - */ - fun params(): DoubleArray { - return theParameters.params() - } - - /** - * - * precision. - * - * @return a [hep.dataforge.MINUIT.MnMachinePrecision] object. - */ - fun precision(): MnMachinePrecision { - return theParameters.precision() - } - - /** - * - * release. - * - * @param e a int. - */ - fun release(e: Int) { - theParameters.release(e) - theCovarianceValid = false - theGCCValid = false - val i = intOfExt(e) - if (parameter(e).hasLimits()) { - theIntParameters.add(i, ext2int(e, parameter(e).value())) - } else { - theIntParameters.add(i, parameter(e).value()) - } - } - - /** - * - * release. - * - * @param name a [String] object. - */ - fun release(name: String?) { - release(index(name)) - } - - /** - * - * removeLimits. - * - * @param e a int. - */ - fun removeLimits(e: Int) { - theParameters.removeLimits(e) - theCovarianceValid = false - theGCCValid = false - if (!parameter(e).isFixed() && !parameter(e).isConst()) { - theIntParameters[intOfExt(e)] = value(e) - } - } - - /** - * - * removeLimits. - * - * @param name a [String] object. - */ - fun removeLimits(name: String?) { - removeLimits(index(name)) - } - - /** - * - * setError. - * - * @param e a int. - * @param err a double. - * @param err a double. - */ - fun setError(e: Int, err: Double) { - theParameters.setError(e, err) - } - - /** - * - * setError. - * - * @param name a [String] object. - * @param err a double. - */ - fun setError(name: String?, err: Double) { - setError(index(name), err) - } - - /** - * - * setLimits. - * - * @param e a int. - * @param low a double. - * @param up a double. - */ - fun setLimits(e: Int, low: Double, up: Double) { - theParameters.setLimits(e, low, up) - theCovarianceValid = false - theGCCValid = false - if (!parameter(e).isFixed() && !parameter(e).isConst()) { - val i = intOfExt(e) - if (low < theIntParameters[i] && theIntParameters[i] < up) { - theIntParameters[i] = ext2int(e, theIntParameters[i]) - } else { - theIntParameters[i] = ext2int(e, 0.5 * (low + up)) - } - } - } - - /** - * - * setLimits. - * - * @param name a [String] object. - * @param low a double. - * @param up a double. - */ - fun setLimits(name: String?, low: Double, up: Double) { - setLimits(index(name), low, up) - } - - /** - * - * setLowerLimit. - * - * @param e a int. - * @param low a double. - */ - fun setLowerLimit(e: Int, low: Double) { - theParameters.setLowerLimit(e, low) - theCovarianceValid = false - theGCCValid = false - if (!parameter(e).isFixed() && !parameter(e).isConst()) { - val i = intOfExt(e) - if (low < theIntParameters[i]) { - theIntParameters[i] = ext2int(e, theIntParameters[i]) - } else { - theIntParameters[i] = ext2int(e, low + 0.5 * abs(low + 1.0)) - } - } - } - - /** - * - * setLowerLimit. - * - * @param name a [String] object. - * @param low a double. - */ - fun setLowerLimit(name: String?, low: Double) { - setLowerLimit(index(name), low) - } - - /** - * - * setPrecision. - * - * @param eps a double. - */ - fun setPrecision(eps: Double) { - theParameters.setPrecision(eps) - } - - /** - * - * setUpperLimit. - * - * @param e a int. - * @param up a double. - */ - fun setUpperLimit(e: Int, up: Double) { - theParameters.setUpperLimit(e, up) - theCovarianceValid = false - theGCCValid = false - if (!parameter(e).isFixed() && !parameter(e).isConst()) { - val i = intOfExt(e) - if (theIntParameters[i] < up) { - theIntParameters[i] = ext2int(e, theIntParameters[i]) - } else { - theIntParameters[i] = ext2int(e, up - 0.5 * abs(up + 1.0)) - } - } - } - - /** - * - * setUpperLimit. - * - * @param name a [String] object. - * @param up a double. - */ - fun setUpperLimit(name: String?, up: Double) { - setUpperLimit(index(name), up) - } - - /** - * - * setValue. - * - * @param e a int. - * @param val a double. - */ - fun setValue(e: Int, `val`: Double) { - theParameters.setValue(e, `val`) - if (!parameter(e).isFixed() && !parameter(e).isConst()) { - val i = intOfExt(e) - if (parameter(e).hasLimits()) { - theIntParameters[i] = ext2int(e, `val`) - } else { - theIntParameters[i] = `val` - } - } - } - - /** - * - * setValue. - * - * @param name a [String] object. - * @param val a double. - */ - fun setValue(name: String?, `val`: Double) { - setValue(index(name), `val`) - } - - /** {@inheritDoc} */ - override fun toString(): String { - return MnPrint.toString(this) - } - - /** - * - * value. - * - * @param index a int. - * @return a double. - */ - fun value(index: Int): Double { - return theParameters.value(index) - } - - /** - * - * value. - * - * @param name a [String] object. - * @return a double. - */ - fun value(name: String?): Double { - return value(index(name)) - } - - /** - * - * variableParameters. - * - * @return a int. - */ - fun variableParameters(): Int { - return theParameters.variableParameters() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameters.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameters.kt deleted file mode 100644 index 9bac54b25..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnUserParameters.kt +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * API class for the user interaction with the parameters. Serves as input to - * the minimizer as well as output from it; users can interact: fix/release - * parameters, set values and errors, etc.; parameters can be accessed via their - * parameter number or via their user-specified name. - * - * @version $Id$ - * @author Darksnake - */ -class MnUserParameters { - private var theTransformation: MnUserTransformation - - /** - * Creates a new instance of MnUserParameters - */ - constructor() { - theTransformation = MnUserTransformation() - } - - /** - * - * Constructor for MnUserParameters. - * - * @param par an array of double. - * @param err an array of double. - */ - constructor(par: DoubleArray, err: DoubleArray) { - theTransformation = MnUserTransformation(par, err) - } - - private constructor(other: MnUserParameters) { - theTransformation = other.theTransformation.copy() - } - - /** - * Add free parameter name, value, error - * - * - * When adding parameters, MINUIT assigns indices to each parameter which - * will be the same as in the double[] in the - * MultiFunction.valueOf(). That means the first parameter the user - * adds gets index 0, the second index 1, and so on. When calculating the - * function value inside FCN, MINUIT will call - * MultiFunction.valueOf() with the elements at their respective - * positions. - * - * @param err a double. - * @param val a double. - * @param name a [String] object. - */ - fun add(name: String, `val`: Double, err: Double) { - theTransformation.add(name, `val`, err) - } - - /** - * Add limited parameter name, value, lower bound, upper bound - * - * @param up a double. - * @param low a double. - * @param name a [String] object. - * @param val a double. - * @param err a double. - */ - fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) { - theTransformation.add(name, `val`, err, low, up) - } - - /** - * Add const parameter name, value - * - * @param name a [String] object. - * @param val a double. - */ - fun add(name: String, `val`: Double) { - theTransformation.add(name, `val`) - } - - /** - * - * copy. - * - * @return a [hep.dataforge.MINUIT.MnUserParameters] object. - */ - fun copy(): MnUserParameters { - return MnUserParameters(this) - } - - /** - * - * error. - * - * @param index a int. - * @return a double. - */ - fun error(index: Int): Double { - return theTransformation.error(index) - } - - /** - * - * error. - * - * @param name a [String] object. - * @return a double. - */ - fun error(name: String?): Double { - return theTransformation.error(name) - } - - fun errors(): DoubleArray { - return theTransformation.errors() - } - /// interaction via external number of parameter - /** - * Fixes the specified parameter (so that the minimizer will no longer vary - * it) - * - * @param index a int. - */ - fun fix(index: Int) { - theTransformation.fix(index) - } - /// interaction via name of parameter - /** - * Fixes the specified parameter (so that the minimizer will no longer vary - * it) - * - * @param name a [String] object. - */ - fun fix(name: String?) { - theTransformation.fix(name) - } - - /** - * convert name into external number of parameter - * @param name - * @return - */ - fun index(name: String?): Int { - return theTransformation.index(name) - } - - /** - * convert external number into name of parameter - * @param index - * @return - */ - fun name(index: Int): String { - return theTransformation.name(index) - } - - /** - * access to single parameter - * @param index - * @return - */ - fun parameter(index: Int): MinuitParameter { - return theTransformation.parameter(index) - } - - /** - * access to parameters (row-wise) - * @return - */ - fun parameters(): List { - return theTransformation.parameters() - } - - /** - * access to parameters and errors in column-wise representation - * @return - */ - fun params(): DoubleArray { - return theTransformation.params() - } - - /** - * - * precision. - * - * @return a [hep.dataforge.MINUIT.MnMachinePrecision] object. - */ - fun precision(): MnMachinePrecision { - return theTransformation.precision() - } - - /** - * Releases the specified parameter (so that the minimizer can vary it) - * - * @param index a int. - */ - fun release(index: Int) { - theTransformation.release(index) - } - - /** - * Releases the specified parameter (so that the minimizer can vary it) - * - * @param name a [String] object. - */ - fun release(name: String?) { - theTransformation.release(name) - } - - /** - * - * removeLimits. - * - * @param index a int. - */ - fun removeLimits(index: Int) { - theTransformation.removeLimits(index) - } - - /** - * - * removeLimits. - * - * @param name a [String] object. - */ - fun removeLimits(name: String?) { - theTransformation.removeLimits(name) - } - - /** - * - * setError. - * - * @param index a int. - * @param err a double. - */ - fun setError(index: Int, err: Double) { - theTransformation.setError(index, err) - } - - /** - * - * setError. - * - * @param name a [String] object. - * @param err a double. - */ - fun setError(name: String?, err: Double) { - theTransformation.setError(name, err) - } - - /** - * Set the lower and upper bound on the specified variable. - * - * @param up a double. - * @param low a double. - * @param index a int. - */ - fun setLimits(index: Int, low: Double, up: Double) { - theTransformation.setLimits(index, low, up) - } - - /** - * Set the lower and upper bound on the specified variable. - * - * @param up a double. - * @param low a double. - * @param name a [String] object. - */ - fun setLimits(name: String?, low: Double, up: Double) { - theTransformation.setLimits(name, low, up) - } - - /** - * - * setLowerLimit. - * - * @param index a int. - * @param low a double. - */ - fun setLowerLimit(index: Int, low: Double) { - theTransformation.setLowerLimit(index, low) - } - - /** - * - * setLowerLimit. - * - * @param name a [String] object. - * @param low a double. - */ - fun setLowerLimit(name: String?, low: Double) { - theTransformation.setLowerLimit(name, low) - } - - /** - * - * setPrecision. - * - * @param eps a double. - */ - fun setPrecision(eps: Double) { - theTransformation.setPrecision(eps) - } - - /** - * - * setUpperLimit. - * - * @param index a int. - * @param up a double. - */ - fun setUpperLimit(index: Int, up: Double) { - theTransformation.setUpperLimit(index, up) - } - - /** - * - * setUpperLimit. - * - * @param name a [String] object. - * @param up a double. - */ - fun setUpperLimit(name: String?, up: Double) { - theTransformation.setUpperLimit(name, up) - } - - /** - * Set the value of parameter. The parameter in question may be variable, - * fixed, or constant, but must be defined. - * - * @param index a int. - * @param val a double. - */ - fun setValue(index: Int, `val`: Double) { - theTransformation.setValue(index, `val`) - } - - /** - * Set the value of parameter. The parameter in question may be variable, - * fixed, or constant, but must be defined. - * - * @param name a [String] object. - * @param val a double. - */ - fun setValue(name: String?, `val`: Double) { - theTransformation.setValue(name, `val`) - } - - /** {@inheritDoc} */ - override fun toString(): String { - return MnPrint.toString(this) - } - - fun trafo(): MnUserTransformation { - return theTransformation - } - - /** - * - * value. - * - * @param index a int. - * @return a double. - */ - fun value(index: Int): Double { - return theTransformation.value(index) - } - - /** - * - * value. - * - * @param name a [String] object. - * @return a double. - */ - fun value(name: String?): Double { - return theTransformation.value(name) - } - - /** - * - * variableParameters. - * - * @return a int. - */ - fun variableParameters(): Int { - return theTransformation.variableParameters() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt deleted file mode 100644 index 1066ac2da..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnUserTransformation.kt +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector - -/** - * knows how to andThen between user specified parameters (external) and - * internal parameters used for minimization - * - * Жуткий октопус, который занимается преобразованием внешних параметров во внутренние - * TODO по возможности отказаться от использования этого монстра - * @version $Id$ - */ -class MnUserTransformation { - private val nameMap: MutableMap = HashMap() - private var theCache: MutableList - private var theExtOfInt: MutableList - private var theParameters: MutableList - private var thePrecision: MnMachinePrecision - - constructor() { - thePrecision = MnMachinePrecision() - theParameters = java.util.ArrayList() - theExtOfInt = java.util.ArrayList() - theCache = java.util.ArrayList(0) - } - - private constructor(other: MnUserTransformation) { - thePrecision = other.thePrecision - theParameters = java.util.ArrayList(other.theParameters.size) - for (par in other.theParameters) { - theParameters.add(par.copy()) - } - theExtOfInt = java.util.ArrayList(other.theExtOfInt) - theCache = java.util.ArrayList(other.theCache) - } - - constructor(par: DoubleArray, err: DoubleArray) { - thePrecision = MnMachinePrecision() - theParameters = java.util.ArrayList(par.size) - theExtOfInt = java.util.ArrayList(par.size) - theCache = java.util.ArrayList(par.size) - for (i in par.indices) { - add("p$i", par[i], err[i]) - } - } - - /** - * add free parameter - * @param err - * @param val - */ - fun add(name: String, `val`: Double, err: Double) { - require(!nameMap.containsKey(name)) { "duplicate name: $name" } - nameMap[name] = theParameters.size - theExtOfInt.add(theParameters.size) - theCache.add(`val`) - theParameters.add(MinuitParameter(theParameters.size, name, `val`, err)) - } - - /** - * add limited parameter - * @param up - * @param low - */ - fun add(name: String, `val`: Double, err: Double, low: Double, up: Double) { - require(!nameMap.containsKey(name)) { "duplicate name: $name" } - nameMap[name] = theParameters.size - theExtOfInt.add(theParameters.size) - theCache.add(`val`) - theParameters.add(MinuitParameter(theParameters.size, name, `val`, err, low, up)) - } - - /** - * add parameter - * @param name - * @param val - */ - fun add(name: String, `val`: Double) { - require(!nameMap.containsKey(name)) { "duplicate name: $name" } - nameMap[name] = theParameters.size - theCache.add(`val`) - theParameters.add(MinuitParameter(theParameters.size, name, `val`)) - } - - /** - * - * copy. - * - * @return a [hep.dataforge.MINUIT.MnUserTransformation] object. - */ - fun copy(): MnUserTransformation { - return MnUserTransformation(this) - } - - fun dInt2Ext(i: Int, `val`: Double): Double { - var dd = 1.0 - val parm: MinuitParameter = theParameters[theExtOfInt[i]] - if (parm.hasLimits()) { - dd = if (parm.hasUpperLimit() && parm.hasLowerLimit()) { - theDoubleLimTrafo.dInt2Ext(`val`, - parm.upperLimit(), - parm.lowerLimit()) - } else if (parm.hasUpperLimit() && !parm.hasLowerLimit()) { - theUpperLimTrafo.dInt2Ext(`val`, parm.upperLimit()) - } else { - theLowerLimTrafo.dInt2Ext(`val`, parm.lowerLimit()) - } - } - return dd - } - - fun error(index: Int): Double { - return theParameters[index].error() - } - - fun error(name: String?): Double { - return error(index(name)) - } - - fun errors(): DoubleArray { - val result = DoubleArray(theParameters.size) - var i = 0 - for (parameter in theParameters) { - result[i++] = parameter.error() - } - return result - } - - fun ext2int(i: Int, `val`: Double): Double { - val parm: MinuitParameter = theParameters[i] - return if (parm.hasLimits()) { - if (parm.hasUpperLimit() && parm.hasLowerLimit()) { - theDoubleLimTrafo.ext2int(`val`, - parm.upperLimit(), - parm.lowerLimit(), - precision()) - } else if (parm.hasUpperLimit() && !parm.hasLowerLimit()) { - theUpperLimTrafo.ext2int(`val`, - parm.upperLimit(), - precision()) - } else { - theLowerLimTrafo.ext2int(`val`, - parm.lowerLimit(), - precision()) - } - } else `val` - } - - fun extOfInt(internal: Int): Int { - return theExtOfInt[internal] - } - - /** - * interaction via external number of parameter - * @param index - */ - fun fix(index: Int) { - val iind = intOfExt(index) - theExtOfInt.removeAt(iind) - theParameters[index].fix() - } - - /** - * interaction via name of parameter - * @param name - */ - fun fix(name: String?) { - fix(index(name)) - } - - /** - * convert name into external number of parameter - * @param name - * @return - */ - fun index(name: String?): Int { - return nameMap[name]!! - } - - fun int2ext(i: Int, `val`: Double): Double { - val parm: MinuitParameter = theParameters[theExtOfInt[i]] - return if (parm.hasLimits()) { - if (parm.hasUpperLimit() && parm.hasLowerLimit()) { - theDoubleLimTrafo.int2ext(`val`, - parm.upperLimit(), - parm.lowerLimit()) - } else if (parm.hasUpperLimit() && !parm.hasLowerLimit()) { - theUpperLimTrafo.int2ext(`val`, parm.upperLimit()) - } else { - theLowerLimTrafo.int2ext(`val`, parm.lowerLimit()) - } - } else `val` - } - - fun int2extCovariance(vec: RealVector, cov: MnAlgebraicSymMatrix): MnUserCovariance { - val result = MnUserCovariance(cov.nrow()) - for (i in 0 until vec.getDimension()) { - var dxdi = 1.0 - if (theParameters[theExtOfInt[i]].hasLimits()) { - dxdi = dInt2Ext(i, vec.getEntry(i)) - } - for (j in i until vec.getDimension()) { - var dxdj = 1.0 - if (theParameters[theExtOfInt[j]].hasLimits()) { - dxdj = dInt2Ext(j, vec.getEntry(j)) - } - result[i, j] = dxdi * cov[i, j] * dxdj - } - } - return result - } - - fun int2extError(i: Int, `val`: Double, err: Double): Double { - var dx = err - val parm: MinuitParameter = theParameters[theExtOfInt[i]] - if (parm.hasLimits()) { - val ui = int2ext(i, `val`) - var du1 = int2ext(i, `val` + dx) - ui - val du2 = int2ext(i, `val` - dx) - ui - if (parm.hasUpperLimit() && parm.hasLowerLimit()) { - if (dx > 1.0) { - du1 = parm.upperLimit() - parm.lowerLimit() - } - dx = 0.5 * (abs(du1) + abs(du2)) - } else { - dx = 0.5 * (abs(du1) + abs(du2)) - } - } - return dx - } - - fun intOfExt(ext: Int): Int { - for (iind in theExtOfInt.indices) { - if (ext == theExtOfInt[iind]) { - return iind - } - } - throw IllegalArgumentException("ext=$ext") - } - - /** - * convert external number into name of parameter - * @param index - * @return - */ - fun name(index: Int): String { - return theParameters[index].name() - } - - /** - * access to single parameter - * @param index - * @return - */ - fun parameter(index: Int): MinuitParameter { - return theParameters[index] - } - - fun parameters(): List { - return theParameters - } - - //access to parameters and errors in column-wise representation - fun params(): DoubleArray { - val result = DoubleArray(theParameters.size) - var i = 0 - for (parameter in theParameters) { - result[i++] = parameter.value() - } - return result - } - - fun precision(): MnMachinePrecision { - return thePrecision - } - - fun release(index: Int) { - require(!theExtOfInt.contains(index)) { "index=$index" } - theExtOfInt.add(index) - Collections.sort(theExtOfInt) - theParameters[index].release() - } - - fun release(name: String?) { - release(index(name)) - } - - fun removeLimits(index: Int) { - theParameters[index].removeLimits() - } - - fun removeLimits(name: String?) { - removeLimits(index(name)) - } - - fun setError(index: Int, err: Double) { - theParameters[index].setError(err) - } - - fun setError(name: String?, err: Double) { - setError(index(name), err) - } - - fun setLimits(index: Int, low: Double, up: Double) { - theParameters[index].setLimits(low, up) - } - - fun setLimits(name: String?, low: Double, up: Double) { - setLimits(index(name), low, up) - } - - fun setLowerLimit(index: Int, low: Double) { - theParameters[index].setLowerLimit(low) - } - - fun setLowerLimit(name: String?, low: Double) { - setLowerLimit(index(name), low) - } - - fun setPrecision(eps: Double) { - thePrecision.setPrecision(eps) - } - - fun setUpperLimit(index: Int, up: Double) { - theParameters[index].setUpperLimit(up) - } - - fun setUpperLimit(name: String?, up: Double) { - setUpperLimit(index(name), up) - } - - fun setValue(index: Int, `val`: Double) { - theParameters[index].setValue(`val`) - theCache[index] = `val` - } - - fun setValue(name: String?, `val`: Double) { - setValue(index(name), `val`) - } - - fun transform(pstates: RealVector): ArrayRealVector { - // FixMe: Worry about efficiency here - val result = ArrayRealVector(theCache.size) - for (i in 0 until result.getDimension()) { - result.setEntry(i, theCache[i]) - } - for (i in 0 until pstates.getDimension()) { - if (theParameters[theExtOfInt[i]].hasLimits()) { - result.setEntry(theExtOfInt[i], int2ext(i, pstates.getEntry(i))) - } else { - result.setEntry(theExtOfInt[i], pstates.getEntry(i)) - } - } - return result - } - - //forwarded interface - fun value(index: Int): Double { - return theParameters[index].value() - } - - fun value(name: String?): Double { - return value(index(name)) - } - - fun variableParameters(): Int { - return theExtOfInt.size - } - - companion object { - private val theDoubleLimTrafo: SinParameterTransformation = SinParameterTransformation() - private val theLowerLimTrafo: SqrtLowParameterTransformation = SqrtLowParameterTransformation() - private val theUpperLimTrafo: SqrtUpParameterTransformation = SqrtUpParameterTransformation() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/MnUtils.kt b/kmath-optimization/src/commonMain/tmp/minuit/MnUtils.kt deleted file mode 100644 index d9f3e1bd5..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/MnUtils.kt +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector - -/** - * Utilities for operating on vectors and matrices - * - * @version $Id$ - */ -internal object MnUtils { - fun absoluteSumOfElements(m: MnAlgebraicSymMatrix): Double { - val data: DoubleArray = m.data() - var result = 0.0 - for (i in data.indices) { - result += abs(data[i]) - } - return result - } - - fun add(v1: RealVector, v2: RealVector?): RealVector { - return v1.add(v2) - } - - fun add(m1: MnAlgebraicSymMatrix, m2: MnAlgebraicSymMatrix): MnAlgebraicSymMatrix { - require(!(m1.size() !== m2.size())) { "Incompatible matrices" } - val result: MnAlgebraicSymMatrix = m1.copy() - val a: DoubleArray = result.data() - val b: DoubleArray = m2.data() - for (i in a.indices) { - a[i] += b[i] - } - return result - } - - fun div(m: MnAlgebraicSymMatrix?, scale: Double): MnAlgebraicSymMatrix { - return mul(m, 1 / scale) - } - - fun div(m: RealVector?, scale: Double): RealVector { - return mul(m, 1 / scale) - } - - fun innerProduct(v1: RealVector, v2: RealVector): Double { - require(!(v1.getDimension() !== v2.getDimension())) { "Incompatible vectors" } - var total = 0.0 - for (i in 0 until v1.getDimension()) { - total += v1.getEntry(i) * v2.getEntry(i) - } - return total - } - - fun mul(v1: RealVector, scale: Double): RealVector { - return v1.mapMultiply(scale) - } - - fun mul(m1: MnAlgebraicSymMatrix, scale: Double): MnAlgebraicSymMatrix { - val result: MnAlgebraicSymMatrix = m1.copy() - val a: DoubleArray = result.data() - for (i in a.indices) { - a[i] *= scale - } - return result - } - - fun mul(m1: MnAlgebraicSymMatrix, v1: RealVector): ArrayRealVector { - require(!(m1.nrow() !== v1.getDimension())) { "Incompatible arguments" } - val result = ArrayRealVector(m1.nrow()) - for (i in 0 until result.getDimension()) { - var total = 0.0 - for (k in 0 until result.getDimension()) { - total += m1[i, k] * v1.getEntry(k) - } - result.setEntry(i, total) - } - return result - } - - fun mul(m1: MnAlgebraicSymMatrix, m2: MnAlgebraicSymMatrix): MnAlgebraicSymMatrix { - require(!(m1.size() !== m2.size())) { "Incompatible matrices" } - val n: Int = m1.nrow() - val result = MnAlgebraicSymMatrix(n) - for (i in 0 until n) { - for (j in 0..i) { - var total = 0.0 - for (k in 0 until n) { - total += m1[i, k] * m2[k, j] - } - result[i, j] = total - } - } - return result - } - - fun outerProduct(v2: RealVector): MnAlgebraicSymMatrix { - // Fixme: check this. I am assuming this is just an outer-product of vector - // with itself. - val n: Int = v2.getDimension() - val result = MnAlgebraicSymMatrix(n) - val data: DoubleArray = v2.toArray() - for (i in 0 until n) { - for (j in 0..i) { - result[i, j] = data[i] * data[j] - } - } - return result - } - - fun similarity(avec: RealVector, mat: MnAlgebraicSymMatrix): Double { - val n: Int = avec.getDimension() - val tmp: RealVector = mul(mat, avec) - var result = 0.0 - for (i in 0 until n) { - result += tmp.getEntry(i) * avec.getEntry(i) - } - return result - } - - fun sub(v1: RealVector, v2: RealVector?): RealVector { - return v1.subtract(v2) - } - - fun sub(m1: MnAlgebraicSymMatrix, m2: MnAlgebraicSymMatrix): MnAlgebraicSymMatrix { - require(!(m1.size() !== m2.size())) { "Incompatible matrices" } - val result: MnAlgebraicSymMatrix = m1.copy() - val a: DoubleArray = result.data() - val b: DoubleArray = m2.data() - for (i in a.indices) { - a[i] -= b[i] - } - return result - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt deleted file mode 100644 index 84130d24f..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/ModularFunctionMinimizer.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import ru.inr.mass.maths.MultiFunction -import ru.inr.mass.minuit.* -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * - * @version $Id$ - */ -abstract class ModularFunctionMinimizer { - abstract fun builder(): MinimumBuilder - fun minimize( - fcn: MultiFunction?, - st: MnUserParameterState, - strategy: MnStrategy, - maxfcn: Int, - toler: Double, - errorDef: Double, - useAnalyticalGradient: Boolean, - checkGradient: Boolean - ): FunctionMinimum { - var maxfcn = maxfcn - val mfcn = MnUserFcn(fcn, errorDef, st.getTransformation()) - val gc: GradientCalculator - var providesAllDerivs = true - /* - * Проверяем в явном виде, что все аналитические производные присутствуют - * TODO сделать возможность того, что часть производных задается аналитически, а часть численно - */for (i in 0 until fcn.getDimension()) { - if (!fcn.providesDeriv(i)) providesAllDerivs = false - } - gc = if (providesAllDerivs && useAnalyticalGradient) { - AnalyticalGradientCalculator(fcn, st.getTransformation(), checkGradient) - } else { - Numerical2PGradientCalculator(mfcn, st.getTransformation(), strategy) - } - val npar: Int = st.variableParameters() - if (maxfcn == 0) { - maxfcn = 200 + 100 * npar + 5 * npar * npar - } - val mnseeds: MinimumSeed = seedGenerator().generate(mfcn, gc, st, strategy) - return minimize(mfcn, gc, mnseeds, strategy, maxfcn, toler) - } - - fun minimize( - mfcn: MnFcn, - gc: GradientCalculator?, - seed: MinimumSeed?, - strategy: MnStrategy?, - maxfcn: Int, - toler: Double - ): FunctionMinimum { - return builder().minimum(mfcn, gc, seed, strategy, maxfcn, toler * mfcn.errorDef()) - } - - abstract fun seedGenerator(): MinimumSeedGenerator -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt b/kmath-optimization/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt deleted file mode 100644 index 2e9ce5813..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/NegativeG2LineSearch.kt +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector -import ru.inr.mass.minuit.* - -/** - * In case that one of the components of the second derivative g2 calculated by - * the numerical gradient calculator is negative, a 1dim line search in the - * direction of that component is done in order to find a better position where - * g2 is again positive. - * - * @version $Id$ - */ -internal object NegativeG2LineSearch { - fun hasNegativeG2(grad: FunctionGradient, prec: MnMachinePrecision): Boolean { - for (i in 0 until grad.getGradient().getDimension()) { - if (grad.getGradientDerivative().getEntry(i) < prec.eps2()) { - return true - } - } - return false - } - - fun search(fcn: MnFcn, st: MinimumState, gc: GradientCalculator, prec: MnMachinePrecision): MinimumState { - val negG2 = hasNegativeG2(st.gradient(), prec) - if (!negG2) { - return st - } - val n: Int = st.parameters().vec().getDimension() - var dgrad: FunctionGradient = st.gradient() - var pa: MinimumParameters = st.parameters() - var iterate = false - var iter = 0 - do { - iterate = false - for (i in 0 until n) { - if (dgrad.getGradientDerivative().getEntry(i) < prec.eps2()) { - // do line search if second derivative negative - var step: RealVector = ArrayRealVector(n) - step.setEntry(i, dgrad.getStep().getEntry(i) * dgrad.getGradient().getEntry(i)) - if (abs(dgrad.getGradient().getEntry(i)) > prec.eps2()) { - step.setEntry(i, - step.getEntry(i) * (-1.0 / abs(dgrad.getGradient().getEntry(i)))) - } - val gdel: Double = step.getEntry(i) * dgrad.getGradient().getEntry(i) - val pp: MnParabolaPoint = MnLineSearch.search(fcn, pa, step, gdel, prec) - step = MnUtils.mul(step, pp.x()) - pa = MinimumParameters(MnUtils.add(pa.vec(), step), pp.y()) - dgrad = gc.gradient(pa, dgrad) - iterate = true - break - } - } - } while (iter++ < 2 * n && iterate) - val mat = MnAlgebraicSymMatrix(n) - for (i in 0 until n) { - mat[i, i] = if (abs(dgrad.getGradientDerivative() - .getEntry(i)) > prec.eps2() - ) 1.0 / dgrad.getGradientDerivative().getEntry(i) else 1.0 - } - val err = MinimumError(mat, 1.0) - val edm: Double = VariableMetricEDMEstimator().estimate(dgrad, err) - return MinimumState(pa, err, dgrad, edm, fcn.numOfCalls()) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/Numerical2PGradientCalculator.kt b/kmath-optimization/src/commonMain/tmp/minuit/Numerical2PGradientCalculator.kt deleted file mode 100644 index efa1d57af..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/Numerical2PGradientCalculator.kt +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.RealVector -import ru.inr.mass.minuit.* - -/** - * - * @version $Id$ - */ -internal class Numerical2PGradientCalculator(fcn: MnFcn, par: MnUserTransformation, stra: MnStrategy) : - GradientCalculator { - private val theFcn: MnFcn = fcn - private val theStrategy: MnStrategy - private val theTransformation: MnUserTransformation - fun fcn(): MnFcn { - return theFcn - } - - fun gradTolerance(): Double { - return strategy().gradientTolerance() - } - - /** {@inheritDoc} */ - fun gradient(par: MinimumParameters): FunctionGradient { - val gc = InitialGradientCalculator(theFcn, theTransformation, theStrategy) - val gra: FunctionGradient = gc.gradient(par) - return gradient(par, gra) - } - - /** {@inheritDoc} */ - fun gradient(par: MinimumParameters, gradient: FunctionGradient): FunctionGradient { - require(par.isValid()) { "Parameters are invalid" } - val x: RealVector = par.vec().copy() - val fcnmin: Double = par.fval() - val dfmin: Double = 8.0 * precision().eps2() * (abs(fcnmin) + theFcn.errorDef()) - val vrysml: Double = 8.0 * precision().eps() * precision().eps() - val n: Int = x.getDimension() - val grd: RealVector = gradient.getGradient().copy() - val g2: RealVector = gradient.getGradientDerivative().copy() - val gstep: RealVector = gradient.getStep().copy() - for (i in 0 until n) { - val xtf: Double = x.getEntry(i) - val epspri: Double = precision().eps2() + abs(grd.getEntry(i) * precision().eps2()) - var stepb4 = 0.0 - for (j in 0 until ncycle()) { - val optstp: Double = sqrt(dfmin / (abs(g2.getEntry(i)) + epspri)) - var step: Double = max(optstp, abs(0.1 * gstep.getEntry(i))) - if (trafo().parameter(trafo().extOfInt(i)).hasLimits()) { - if (step > 0.5) { - step = 0.5 - } - } - val stpmax: Double = 10.0 * abs(gstep.getEntry(i)) - if (step > stpmax) { - step = stpmax - } - val stpmin: Double = - max(vrysml, 8.0 * abs(precision().eps2() * x.getEntry(i))) - if (step < stpmin) { - step = stpmin - } - if (abs((step - stepb4) / step) < stepTolerance()) { - break - } - gstep.setEntry(i, step) - stepb4 = step - x.setEntry(i, xtf + step) - val fs1: Double = theFcn.value(x) - x.setEntry(i, xtf - step) - val fs2: Double = theFcn.value(x) - x.setEntry(i, xtf) - val grdb4: Double = grd.getEntry(i) - grd.setEntry(i, 0.5 * (fs1 - fs2) / step) - g2.setEntry(i, (fs1 + fs2 - 2.0 * fcnmin) / step / step) - if (abs(grdb4 - grd.getEntry(i)) / (abs(grd.getEntry(i)) + dfmin / step) < gradTolerance()) { - break - } - } - } - return FunctionGradient(grd, g2, gstep) - } - - fun ncycle(): Int { - return strategy().gradientNCycles() - } - - fun precision(): MnMachinePrecision { - return theTransformation.precision() - } - - fun stepTolerance(): Double { - return strategy().gradientStepTolerance() - } - - fun strategy(): MnStrategy { - return theStrategy - } - - fun trafo(): MnUserTransformation { - return theTransformation - } - - init { - theTransformation = par - theStrategy = stra - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/ScanBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/ScanBuilder.kt deleted file mode 100644 index 57f910a26..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/ScanBuilder.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector -import ru.inr.mass.minuit.* -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * Performs a minimization using the simplex method of Nelder and Mead (ref. - * Comp. J. 7, 308 (1965)). - * - * @version $Id$ - */ -internal class ScanBuilder : MinimumBuilder { - /** {@inheritDoc} */ - fun minimum( - mfcn: MnFcn, - gc: GradientCalculator?, - seed: MinimumSeed, - stra: MnStrategy?, - maxfcn: Int, - toler: Double - ): FunctionMinimum { - val x: RealVector = seed.parameters().vec().copy() - val upst = MnUserParameterState(seed.state(), mfcn.errorDef(), seed.trafo()) - val scan = MnParameterScan(mfcn.fcn(), upst.parameters(), seed.fval()) - var amin: Double = scan.fval() - val n: Int = seed.trafo().variableParameters() - val dirin: RealVector = ArrayRealVector(n) - for (i in 0 until n) { - val ext: Int = seed.trafo().extOfInt(i) - scan.scan(ext) - if (scan.fval() < amin) { - amin = scan.fval() - x.setEntry(i, seed.trafo().ext2int(ext, scan.parameters().value(ext))) - } - dirin.setEntry(i, sqrt(2.0 * mfcn.errorDef() * seed.error().invHessian()[i, i])) - } - val mp = MinimumParameters(x, dirin, amin) - val st = MinimumState(mp, 0.0, mfcn.numOfCalls()) - val states: MutableList = java.util.ArrayList(1) - states.add(st) - return FunctionMinimum(seed, states, mfcn.errorDef()) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/ScanMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/ScanMinimizer.kt deleted file mode 100644 index e39a49c0d..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/ScanMinimizer.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class ScanMinimizer : ModularFunctionMinimizer() { - private val theBuilder: ScanBuilder - private val theSeedGenerator: SimplexSeedGenerator = SimplexSeedGenerator() - override fun builder(): MinimumBuilder { - return theBuilder - } - - override fun seedGenerator(): MinimumSeedGenerator { - return theSeedGenerator - } - - init { - theBuilder = ScanBuilder() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SimplexBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/SimplexBuilder.kt deleted file mode 100644 index 0b10155ff..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/SimplexBuilder.kt +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MINUITPlugin -import ru.inr.mass.minuit.* -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * - * @version $Id$ - */ -internal class SimplexBuilder : MinimumBuilder { - /** {@inheritDoc} */ - fun minimum( - mfcn: MnFcn, - gc: GradientCalculator?, - seed: MinimumSeed, - strategy: MnStrategy?, - maxfcn: Int, - minedm: Double - ): FunctionMinimum { - val prec: MnMachinePrecision = seed.precision() - val x: RealVector = seed.parameters().vec().copy() - val step: RealVector = MnUtils.mul(seed.gradient().getStep(), 10.0) - val n: Int = x.getDimension() - val wg = 1.0 / n - val alpha = 1.0 - val beta = 0.5 - val gamma = 2.0 - val rhomin = 4.0 - val rhomax = 8.0 - val rho1 = 1.0 + alpha - val rho2 = 1.0 + alpha * gamma - val simpl: MutableList> = java.util.ArrayList>(n + 1) - simpl.add(Pair(seed.fval(), x.copy())) - var jl = 0 - var jh = 0 - var amin: Double = seed.fval() - var aming: Double = seed.fval() - for (i in 0 until n) { - val dmin: Double = 8.0 * prec.eps2() * (abs(x.getEntry(i)) + prec.eps2()) - if (step.getEntry(i) < dmin) { - step.setEntry(i, dmin) - } - x.setEntry(i, x.getEntry(i) + step.getEntry(i)) - val tmp: Double = mfcn.value(x) - if (tmp < amin) { - amin = tmp - jl = i + 1 - } - if (tmp > aming) { - aming = tmp - jh = i + 1 - } - simpl.add(Pair(tmp, x.copy())) - x.setEntry(i, x.getEntry(i) - step.getEntry(i)) - } - val simplex = SimplexParameters(simpl, jh, jl) - do { - amin = simplex[jl].getFirst() - jl = simplex.jl() - jh = simplex.jh() - var pbar: RealVector = ArrayRealVector(n) - for (i in 0 until n + 1) { - if (i == jh) { - continue - } - pbar = MnUtils.add(pbar, MnUtils.mul(simplex[i].getSecond(), wg)) - } - val pstar: RealVector = - MnUtils.sub(MnUtils.mul(pbar, 1.0 + alpha), MnUtils.mul(simplex[jh].getSecond(), alpha)) - val ystar: Double = mfcn.value(pstar) - if (ystar > amin) { - if (ystar < simplex[jh].getFirst()) { - simplex.update(ystar, pstar) - if (jh != simplex.jh()) { - continue - } - } - val pstst: RealVector = - MnUtils.add(MnUtils.mul(simplex[jh].getSecond(), beta), MnUtils.mul(pbar, 1.0 - beta)) - val ystst: Double = mfcn.value(pstst) - if (ystst > simplex[jh].getFirst()) { - break - } - simplex.update(ystst, pstst) - continue - } - var pstst: RealVector = MnUtils.add(MnUtils.mul(pstar, gamma), MnUtils.mul(pbar, 1.0 - gamma)) - var ystst: Double = mfcn.value(pstst) - val y1: Double = (ystar - simplex[jh].getFirst()) * rho2 - val y2: Double = (ystst - simplex[jh].getFirst()) * rho1 - var rho = 0.5 * (rho2 * y1 - rho1 * y2) / (y1 - y2) - if (rho < rhomin) { - if (ystst < simplex[jl].getFirst()) { - simplex.update(ystst, pstst) - } else { - simplex.update(ystar, pstar) - } - continue - } - if (rho > rhomax) { - rho = rhomax - } - val prho: RealVector = - MnUtils.add(MnUtils.mul(pbar, rho), MnUtils.mul(simplex[jh].getSecond(), 1.0 - rho)) - val yrho: Double = mfcn.value(prho) - if (yrho < simplex[jl].getFirst() && yrho < ystst) { - simplex.update(yrho, prho) - continue - } - if (ystst < simplex[jl].getFirst()) { - simplex.update(ystst, pstst) - continue - } - if (yrho > simplex[jl].getFirst()) { - if (ystst < simplex[jl].getFirst()) { - simplex.update(ystst, pstst) - } else { - simplex.update(ystar, pstar) - } - continue - } - if (ystar > simplex[jh].getFirst()) { - pstst = MnUtils.add(MnUtils.mul(simplex[jh].getSecond(), beta), MnUtils.mul(pbar, 1 - beta)) - ystst = mfcn.value(pstst) - if (ystst > simplex[jh].getFirst()) { - break - } - simplex.update(ystst, pstst) - } - } while (simplex.edm() > minedm && mfcn.numOfCalls() < maxfcn) - amin = simplex[jl].getFirst() - jl = simplex.jl() - jh = simplex.jh() - var pbar: RealVector = ArrayRealVector(n) - for (i in 0 until n + 1) { - if (i == jh) { - continue - } - pbar = MnUtils.add(pbar, MnUtils.mul(simplex[i].getSecond(), wg)) - } - var ybar: Double = mfcn.value(pbar) - if (ybar < amin) { - simplex.update(ybar, pbar) - } else { - pbar = simplex[jl].getSecond() - ybar = simplex[jl].getFirst() - } - var dirin: RealVector = simplex.dirin() - // scale to sigmas on parameters werr^2 = dirin^2 * (up/edm) - dirin = MnUtils.mul(dirin, sqrt(mfcn.errorDef() / simplex.edm())) - val st = MinimumState(MinimumParameters(pbar, dirin, ybar), simplex.edm(), mfcn.numOfCalls()) - val states: MutableList = java.util.ArrayList(1) - states.add(st) - if (mfcn.numOfCalls() > maxfcn) { - MINUITPlugin.logStatic("Simplex did not converge, #fcn calls exhausted.") - return FunctionMinimum(seed, states, mfcn.errorDef(), MnReachedCallLimit()) - } - if (simplex.edm() > minedm) { - MINUITPlugin.logStatic("Simplex did not converge, edm > minedm.") - return FunctionMinimum(seed, states, mfcn.errorDef(), MnAboveMaxEdm()) - } - return FunctionMinimum(seed, states, mfcn.errorDef()) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SimplexMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/SimplexMinimizer.kt deleted file mode 100644 index f4bbcc320..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/SimplexMinimizer.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class SimplexMinimizer : ModularFunctionMinimizer() { - private val theBuilder: SimplexBuilder - private val theSeedGenerator: SimplexSeedGenerator = SimplexSeedGenerator() - - /** {@inheritDoc} */ - override fun builder(): MinimumBuilder { - return theBuilder - } - - /** {@inheritDoc} */ - override fun seedGenerator(): MinimumSeedGenerator { - return theSeedGenerator - } - - /** - * - * Constructor for SimplexMinimizer. - */ - init { - theBuilder = SimplexBuilder() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SimplexParameters.kt b/kmath-optimization/src/commonMain/tmp/minuit/SimplexParameters.kt deleted file mode 100644 index fef6e2010..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/SimplexParameters.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector - -/** - * - * @version $Id$ - */ -internal class SimplexParameters(simpl: MutableList>, jh: Int, jl: Int) { - private var theJHigh: Int - private var theJLow: Int - private val theSimplexParameters: MutableList> - fun dirin(): ArrayRealVector { - val dirin = ArrayRealVector(theSimplexParameters.size - 1) - for (i in 0 until theSimplexParameters.size - 1) { - var pbig: Double = theSimplexParameters[0].getSecond().getEntry(i) - var plit = pbig - for (theSimplexParameter in theSimplexParameters) { - if (theSimplexParameter.getSecond().getEntry(i) < plit) { - plit = theSimplexParameter.getSecond().getEntry(i) - } - if (theSimplexParameter.getSecond().getEntry(i) > pbig) { - pbig = theSimplexParameter.getSecond().getEntry(i) - } - } - dirin.setEntry(i, pbig - plit) - } - return dirin - } - - fun edm(): Double { - return theSimplexParameters[jh()].getFirst() - theSimplexParameters[jl()].getFirst() - } - - operator fun get(i: Int): Pair { - return theSimplexParameters[i] - } - - fun jh(): Int { - return theJHigh - } - - fun jl(): Int { - return theJLow - } - - fun simplex(): List> { - return theSimplexParameters - } - - fun update(y: Double, p: RealVector?) { - theSimplexParameters.set(jh(), Pair(y, p)) - if (y < theSimplexParameters[jl()].getFirst()) { - theJLow = jh() - } - var jh = 0 - for (i in 1 until theSimplexParameters.size) { - if (theSimplexParameters[i].getFirst() > theSimplexParameters[jh].getFirst()) { - jh = i - } - } - theJHigh = jh - } - - init { - theSimplexParameters = simpl - theJHigh = jh - theJLow = jl - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt b/kmath-optimization/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt deleted file mode 100644 index 577545fc3..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/SimplexSeedGenerator.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import org.apache.commons.math3.linear.ArrayRealVector -import ru.inr.mass.minuit.* -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * - * @version $Id$ - */ -internal class SimplexSeedGenerator : MinimumSeedGenerator { - /** {@inheritDoc} */ - fun generate(fcn: MnFcn, gc: GradientCalculator?, st: MnUserParameterState, stra: MnStrategy): MinimumSeed { - val n: Int = st.variableParameters() - val prec: MnMachinePrecision = st.precision() - - // initial starting values - val x: RealVector = ArrayRealVector(n) - for (i in 0 until n) { - x.setEntry(i, st.intParameters()[i]) - } - val fcnmin: Double = fcn.value(x) - val pa = MinimumParameters(x, fcnmin) - val igc = InitialGradientCalculator(fcn, st.getTransformation(), stra) - val dgrad: FunctionGradient = igc.gradient(pa) - val mat = MnAlgebraicSymMatrix(n) - val dcovar = 1.0 - for (i in 0 until n) { - mat[i, i] = if (abs(dgrad.getGradientDerivative() - .getEntry(i)) > prec.eps2() - ) 1.0 / dgrad.getGradientDerivative().getEntry(i) else 1.0 - } - val err = MinimumError(mat, dcovar) - val edm: Double = VariableMetricEDMEstimator().estimate(dgrad, err) - val state = MinimumState(pa, err, dgrad, edm, fcn.numOfCalls()) - return MinimumSeed(state, st.getTransformation()) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SinParameterTransformation.kt b/kmath-optimization/src/commonMain/tmp/minuit/SinParameterTransformation.kt deleted file mode 100644 index 821addef7..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/SinParameterTransformation.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class SinParameterTransformation { - fun dInt2Ext(value: Double, upper: Double, lower: Double): Double { - return 0.5 * abs((upper - lower) * cos(value)) - } - - fun ext2int(value: Double, upper: Double, lower: Double, prec: MnMachinePrecision): Double { - val piby2: Double = 2.0 * atan(1.0) - val distnn: Double = 8.0 * sqrt(prec.eps2()) - val vlimhi = piby2 - distnn - val vlimlo = -piby2 + distnn - val yy = 2.0 * (value - lower) / (upper - lower) - 1.0 - val yy2 = yy * yy - return if (yy2 > 1.0 - prec.eps2()) { - if (yy < 0.0) { - vlimlo - } else { - vlimhi - } - } else { - asin(yy) - } - } - - fun int2ext(value: Double, upper: Double, lower: Double): Double { - return lower + 0.5 * (upper - lower) * (sin(value) + 1.0) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SqrtLowParameterTransformation.kt b/kmath-optimization/src/commonMain/tmp/minuit/SqrtLowParameterTransformation.kt deleted file mode 100644 index 444b63847..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/SqrtLowParameterTransformation.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class SqrtLowParameterTransformation { - // derivative of transformation from internal to external - fun dInt2Ext(value: Double, lower: Double): Double { - return value / sqrt(value * value + 1.0) - } - - // transformation from external to internal - fun ext2int(value: Double, lower: Double, prec: MnMachinePrecision): Double { - val yy = value - lower + 1.0 - val yy2 = yy * yy - return if (yy2 < 1.0 + prec.eps2()) { - 8 * sqrt(prec.eps2()) - } else { - sqrt(yy2 - 1) - } - } - - // transformation from internal to external - fun int2ext(value: Double, lower: Double): Double { - return lower - 1.0 + sqrt(value * value + 1.0) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/SqrtUpParameterTransformation.kt b/kmath-optimization/src/commonMain/tmp/minuit/SqrtUpParameterTransformation.kt deleted file mode 100644 index 5774848bd..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/SqrtUpParameterTransformation.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class SqrtUpParameterTransformation { - // derivative of transformation from internal to external - fun dInt2Ext(value: Double, upper: Double): Double { - return -value / sqrt(value * value + 1.0) - } - - // transformation from external to internal - fun ext2int(value: Double, upper: Double, prec: MnMachinePrecision): Double { - val yy = upper - value + 1.0 - val yy2 = yy * yy - return if (yy2 < 1.0 + prec.eps2()) { - 8 * sqrt(prec.eps2()) - } else { - sqrt(yy2 - 1) - } - } - - // transformation from internal to external - fun int2ext(value: Double, upper: Double): Double { - return upper + 1.0 - sqrt(value * value + 1.0) - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricBuilder.kt b/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricBuilder.kt deleted file mode 100644 index edc6783b6..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricBuilder.kt +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -import space.kscience.kmath.optimization.minuit.MINUITPlugin -import ru.inr.mass.minuit.* -import space.kscience.kmath.optimization.minuit.MinimumSeed - -/** - * - * @version $Id$ - */ -internal class VariableMetricBuilder : MinimumBuilder { - private val theErrorUpdator: DavidonErrorUpdator - private val theEstimator: VariableMetricEDMEstimator = VariableMetricEDMEstimator() - fun errorUpdator(): DavidonErrorUpdator { - return theErrorUpdator - } - - fun estimator(): VariableMetricEDMEstimator { - return theEstimator - } - - /** {@inheritDoc} */ - fun minimum( - fcn: MnFcn, - gc: GradientCalculator, - seed: MinimumSeed, - strategy: MnStrategy, - maxfcn: Int, - edmval: Double - ): FunctionMinimum { - val min: FunctionMinimum = minimum(fcn, gc, seed, maxfcn, edmval) - if (strategy.strategy() === 2 || strategy.strategy() === 1 && min.error().dcovar() > 0.05) { - val st: MinimumState = MnHesse(strategy).calculate(fcn, min.state(), min.seed().trafo(), 0) - min.add(st) - } - if (!min.isValid()) { - MINUITPlugin.logStatic("FunctionMinimum is invalid.") - } - return min - } - - fun minimum(fcn: MnFcn, gc: GradientCalculator, seed: MinimumSeed, maxfcn: Int, edmval: Double): FunctionMinimum { - var edmval = edmval - edmval *= 0.0001 - if (seed.parameters().vec().getDimension() === 0) { - return FunctionMinimum(seed, fcn.errorDef()) - } - val prec: MnMachinePrecision = seed.precision() - val result: MutableList = java.util.ArrayList(8) - var edm: Double = seed.state().edm() - if (edm < 0.0) { - MINUITPlugin.logStatic("VariableMetricBuilder: initial matrix not pos.def.") - if (seed.error().isPosDef()) { - throw RuntimeException("Something is wrong!") - } - return FunctionMinimum(seed, fcn.errorDef()) - } - result.add(seed.state()) - - // iterate until edm is small enough or max # of iterations reached - edm *= 1.0 + 3.0 * seed.error().dcovar() - var step: RealVector // = new ArrayRealVector(seed.gradient().getGradient().getDimension()); - do { - var s0: MinimumState = result[result.size - 1] - step = MnUtils.mul(MnUtils.mul(s0.error().invHessian(), s0.gradient().getGradient()), -1) - var gdel: Double = MnUtils.innerProduct(step, s0.gradient().getGradient()) - if (gdel > 0.0) { - MINUITPlugin.logStatic("VariableMetricBuilder: matrix not pos.def.") - MINUITPlugin.logStatic("gdel > 0: $gdel") - s0 = MnPosDef.test(s0, prec) - step = MnUtils.mul(MnUtils.mul(s0.error().invHessian(), s0.gradient().getGradient()), -1) - gdel = MnUtils.innerProduct(step, s0.gradient().getGradient()) - MINUITPlugin.logStatic("gdel: $gdel") - if (gdel > 0.0) { - result.add(s0) - return FunctionMinimum(seed, result, fcn.errorDef()) - } - } - val pp: MnParabolaPoint = MnLineSearch.search(fcn, s0.parameters(), step, gdel, prec) - if (abs(pp.y() - s0.fval()) < prec.eps()) { - MINUITPlugin.logStatic("VariableMetricBuilder: no improvement") - break //no improvement - } - val p = MinimumParameters(MnUtils.add(s0.vec(), MnUtils.mul(step, pp.x())), pp.y()) - val g: FunctionGradient = gc.gradient(p, s0.gradient()) - edm = estimator().estimate(g, s0.error()) - if (edm < 0.0) { - MINUITPlugin.logStatic("VariableMetricBuilder: matrix not pos.def.") - MINUITPlugin.logStatic("edm < 0") - s0 = MnPosDef.test(s0, prec) - edm = estimator().estimate(g, s0.error()) - if (edm < 0.0) { - result.add(s0) - return FunctionMinimum(seed, result, fcn.errorDef()) - } - } - val e: MinimumError = errorUpdator().update(s0, p, g) - result.add(MinimumState(p, e, g, edm, fcn.numOfCalls())) - // result[0] = MinimumState(p, e, g, edm, fcn.numOfCalls()); - edm *= 1.0 + 3.0 * e.dcovar() - } while (edm > edmval && fcn.numOfCalls() < maxfcn) - if (fcn.numOfCalls() >= maxfcn) { - MINUITPlugin.logStatic("VariableMetricBuilder: call limit exceeded.") - return FunctionMinimum(seed, result, fcn.errorDef(), MnReachedCallLimit()) - } - return if (edm > edmval) { - if (edm < abs(prec.eps2() * result[result.size - 1].fval())) { - MINUITPlugin.logStatic("VariableMetricBuilder: machine accuracy limits further improvement.") - FunctionMinimum(seed, result, fcn.errorDef()) - } else if (edm < 10.0 * edmval) { - FunctionMinimum(seed, result, fcn.errorDef()) - } else { - MINUITPlugin.logStatic("VariableMetricBuilder: finishes without convergence.") - MINUITPlugin.logStatic("VariableMetricBuilder: edm= $edm requested: $edmval") - FunctionMinimum(seed, result, fcn.errorDef(), MnAboveMaxEdm()) - } - } else FunctionMinimum(seed, result, fcn.errorDef()) - } - - init { - theErrorUpdator = DavidonErrorUpdator() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricEDMEstimator.kt b/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricEDMEstimator.kt deleted file mode 100644 index 8fca4e6ee..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricEDMEstimator.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @author tonyj - * @version $Id$ - */ -internal class VariableMetricEDMEstimator { - fun estimate(g: FunctionGradient, e: MinimumError): Double { - if (e.invHessian().size() === 1) { - return 0.5 * g.getGradient().getEntry(0) * g.getGradient().getEntry(0) * e.invHessian()[0, 0] - } - val rho: Double = MnUtils.similarity(g.getGradient(), e.invHessian()) - return 0.5 * rho - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricMinimizer.kt b/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricMinimizer.kt deleted file mode 100644 index 2a13a5fff..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/VariableMetricMinimizer.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - -/** - * - * @version $Id$ - */ -internal class VariableMetricMinimizer : ModularFunctionMinimizer() { - private val theMinBuilder: VariableMetricBuilder - private val theMinSeedGen: MnSeedGenerator = MnSeedGenerator() - - /** {@inheritDoc} */ - override fun builder(): MinimumBuilder { - return theMinBuilder - } - - /** {@inheritDoc} */ - override fun seedGenerator(): MinimumSeedGenerator { - return theMinSeedGen - } - - /** - * - * Constructor for VariableMetricMinimizer. - */ - init { - theMinBuilder = VariableMetricBuilder() - } -} \ No newline at end of file diff --git a/kmath-optimization/src/commonMain/tmp/minuit/package-info.kt b/kmath-optimization/src/commonMain/tmp/minuit/package-info.kt deleted file mode 100644 index 22779da86..000000000 --- a/kmath-optimization/src/commonMain/tmp/minuit/package-info.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2015 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ru.inr.mass.minuit - diff --git a/kmath-stat/README.md b/kmath-stat/README.md deleted file mode 100644 index 762e61237..000000000 --- a/kmath-stat/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-stat - - - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-stat:0.3.0-dev-20`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-stat:0.3.0-dev-20' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-stat:0.3.0-dev-20") -} -``` diff --git a/kmath-stat/build.gradle.kts b/kmath-stat/build.gradle.kts index 41a1666f8..e3e396b6f 100644 --- a/kmath-stat/build.gradle.kts +++ b/kmath-stat/build.gradle.kts @@ -1,5 +1,6 @@ plugins { - id("ru.mipt.npm.gradle.mpp") + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") id("ru.mipt.npm.gradle.native") } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt index 3d3f95f8f..298bbc858 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.distributions diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt index 1218f13c5..067b47796 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.distributions diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt index 66e041f05..24429cf32 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.distributions diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt index 25668446c..5b3cb1859 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.internal diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt index 63db1c56f..18abd669f 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.internal @@ -145,7 +145,7 @@ internal object InternalGamma { } when { - n >= maxIterations -> error("Maximal iterations is exceeded $maxIterations") + n >= maxIterations -> throw error("Maximal iterations is exceeded $maxIterations") sum.isInfinite() -> 1.0 else -> exp(-x + a * ln(x) - logGamma(a)) * sum } diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt index 3997a77b3..77ba02a25 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.internal diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt new file mode 100644 index 000000000..16f616fe2 --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt @@ -0,0 +1,91 @@ +/* + * 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 file. + */ + +package space.kscience.kmath.optimization + +import space.kscience.kmath.expressions.* +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.indices + +/** + * A likelihood function optimization problem with provided derivatives. + */ +public interface FunctionOptimization : Optimization { + /** + * The optimization direction. If true search for function maximum, if false, search for the minimum. + */ + public var maximize: Boolean + + /** + * Defines the initial guess for the optimization problem. + */ + public fun initialGuess(map: Map) + + /** + * Set a differentiable expression as objective function as function and gradient provider. + */ + public fun diffFunction(expression: DifferentiableExpression) + + public companion object { + /** + * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic + * differentiation. + */ + public fun chiSquared( + autoDiff: AutoDiffProcessor>, + x: Buffer, + y: Buffer, + yErr: Buffer, + model: A.(I) -> I, + ): DifferentiableExpression where A : ExtendedField, A : ExpressionAlgebra { + require(x.size == y.size) { "X and y buffers should be of the same size" } + require(y.size == yErr.size) { "Y and yErr buffer should of the same size" } + + return autoDiff.process { + var sum = zero + + x.indices.forEach { + val xValue = const(x[it]) + val yValue = const(y[it]) + val yErrValue = const(yErr[it]) + val modelValue = model(xValue) + sum += ((yValue - modelValue) / yErrValue).pow(2) + } + + sum + } + } + } +} + +/** + * Defines a chi-squared-based objective function. + */ +public fun FunctionOptimization.chiSquared( + autoDiff: AutoDiffProcessor>, + x: Buffer, + y: Buffer, + yErr: Buffer, + model: A.(I) -> I, +) where A : ExtendedField, A : ExpressionAlgebra { + val chiSquared = FunctionOptimization.chiSquared(autoDiff, x, y, yErr, model) + diffFunction(chiSquared) + maximize = false +} + +/** + * Optimizes differentiable expression using specific [OptimizationProblemFactory]. + */ +public fun > DifferentiableExpression.optimizeWith( + factory: OptimizationProblemFactory, + vararg symbols: Symbol, + configuration: F.() -> Unit, +): OptimizationResult { + require(symbols.isNotEmpty()) { "Must provide a list of symbols for optimization" } + val problem = factory(symbols.toList(), configuration) + problem.diffFunction(this) + return problem.optimize() +} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt new file mode 100644 index 000000000..fbc5074ef --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt @@ -0,0 +1,74 @@ +/* + * 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 file. + */ + +package space.kscience.kmath.optimization + +import space.kscience.kmath.expressions.Expression +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.indices +import kotlin.math.pow + +/** + * A likelihood function optimization problem + */ +public interface NoDerivFunctionOptimization : Optimization { + /** + * The optimization direction. If `true` search for function maximum, search for the minimum otherwise. + */ + public var maximize: Boolean + + /** + * Define the initial guess for the optimization problem + */ + public fun initialGuess(map: Map) + + /** + * Set an objective function expression + */ + public fun function(expression: Expression) + + public companion object { + /** + * Generate a chi squared expression from given x-y-sigma model represented by an expression. Does not provide derivatives + */ + public fun chiSquared( + x: Buffer, + y: Buffer, + yErr: Buffer, + model: Expression, + xSymbol: Symbol = Symbol.x, + ): Expression { + require(x.size == y.size) { "X and y buffers should be of the same size" } + require(y.size == yErr.size) { "Y and yErr buffer should of the same size" } + + return Expression { arguments -> + x.indices.sumOf { + val xValue = x[it] + val yValue = y[it] + val yErrValue = yErr[it] + val modifiedArgs = arguments + (xSymbol to xValue) + val modelValue = model(modifiedArgs) + ((yValue - modelValue) / yErrValue).pow(2) + } + } + } + } +} + + +/** + * Optimize expression without derivatives using specific [OptimizationProblemFactory] + */ +public fun > Expression.noDerivOptimizeWith( + factory: OptimizationProblemFactory, + vararg symbols: Symbol, + configuration: F.() -> Unit, +): OptimizationResult { + require(symbols.isNotEmpty()) { "Must provide a list of symbols for optimization" } + val problem = factory(symbols.toList(), configuration) + problem.function(this) + return problem.optimize() +} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt new file mode 100644 index 000000000..d6d15755c --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt @@ -0,0 +1,49 @@ +/* + * 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 file. + */ + +package space.kscience.kmath.optimization + +import space.kscience.kmath.expressions.Symbol + +public interface OptimizationFeature + +public class OptimizationResult( + public val point: Map, + public val value: T, + public val features: Set = emptySet(), +) { + override fun toString(): String { + return "OptimizationResult(point=$point, value=$value)" + } +} + +public operator fun OptimizationResult.plus( + feature: OptimizationFeature, +): OptimizationResult = OptimizationResult(point, value, features + feature) + +/** + * A builder of optimization problems over [T] variables + */ +public interface Optimization { + + /** + * Update the problem from previous optimization run + */ + public fun update(result: OptimizationResult) + + /** + * Make an optimization run + */ + public fun optimize(): OptimizationResult +} + +public fun interface OptimizationProblemFactory> { + public fun build(symbols: List): P +} + +public operator fun > OptimizationProblemFactory.invoke( + symbols: List, + block: P.() -> Unit, +): P = build(symbols).apply(block) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt new file mode 100644 index 000000000..33400040d --- /dev/null +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt @@ -0,0 +1,41 @@ +/* + * 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 file. + */ + +package space.kscience.kmath.optimization + +import space.kscience.kmath.data.ColumnarData +import space.kscience.kmath.expressions.* +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.operations.Field + +@UnstableKMathAPI +public interface XYFit : Optimization { + + public val algebra: Field + + /** + * Set X-Y data for this fit optionally including x and y errors + */ + public fun data( + dataSet: ColumnarData, + xSymbol: Symbol, + ySymbol: Symbol, + xErrSymbol: Symbol? = null, + yErrSymbol: Symbol? = null, + ) + + public fun model(model: (T) -> DifferentiableExpression) + + /** + * Set the differentiable model for this fit + */ + public fun model( + autoDiff: AutoDiffProcessor>, + modelFunction: A.(I) -> I, + ): Unit where A : ExtendedField, A : ExpressionAlgebra = model { arg -> + autoDiff.process { modelFunction(const(arg)) } + } +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt index 77d29981f..5f923fe5f 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt index 993215d41..063e055ce 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt index 5390a2e09..b00db5b30 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt index b3c014553..14aa26275 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt index 9219df43e..e5d1ecb49 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt index 0105731c4..16f91570f 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt index 0a68e5c88..5e636f246 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt index 83f87e832..ceb324e8d 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt index f0f94900e..d3ff05b06 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt index b534fdc14..bda6f9819 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.samplers diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt index 0e06fa162..5e1e577ba 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat 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 aff7d03d9..7daed5798 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 @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat @@ -27,13 +27,8 @@ public class Mean( override suspend fun evaluate(data: Buffer): T = super.evaluate(data) - override suspend fun computeIntermediate(data: Buffer): Pair = group { - var res = zero - for (i in data.indices) { - res += data[i] - } - res to data.size - } + override suspend fun computeIntermediate(data: Buffer): Pair = + evaluateBlocking(data) to data.size override suspend fun composeIntermediate(first: Pair, second: Pair): Pair = group { first.first + second.first } to (first.second + second.second) @@ -43,23 +38,13 @@ public class Mean( } public companion object { - @Deprecated("Use Double.mean instead") + //TODO replace with optimized version which respects overflow public val double: Mean = Mean(DoubleField) { sum, count -> sum / count } - @Deprecated("Use Int.mean instead") public val int: Mean = Mean(IntRing) { sum, count -> sum / count } - @Deprecated("Use Long.mean instead") public val long: Mean = Mean(LongRing) { sum, count -> sum / count } - public fun evaluate(buffer: Buffer): Double = Double.mean.evaluateBlocking(buffer) - public fun evaluate(buffer: Buffer): Int = Int.mean.evaluateBlocking(buffer) - public fun evaluate(buffer: Buffer): Long = Long.mean.evaluateBlocking(buffer) + public fun evaluate(buffer: Buffer): Double = double.evaluateBlocking(buffer) + public fun evaluate(buffer: Buffer): Int = int.evaluateBlocking(buffer) + public fun evaluate(buffer: Buffer): Long = long.evaluateBlocking(buffer) } -} - - -//TODO replace with optimized version which respects overflow -public val Double.Companion.mean: Mean get() = Mean(DoubleField) { sum, count -> sum / count } -public val Int.Companion.mean: Mean get() = Mean(IntRing) { sum, count -> sum / count } -public val Long.Companion.mean: Mean get() = Mean(LongRing) { sum, count -> sum / count } - - +} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt index c587277f9..54b2e42b3 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt @@ -1,12 +1,12 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat -import space.kscience.kmath.operations.asSequence import space.kscience.kmath.structures.Buffer +import space.kscience.kmath.structures.asSequence /** * Non-composable median diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt index d4bc36b5b..61e472334 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt index f280a78aa..98ee6402a 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt index 0dd121f3b..0b3b52cab 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt @@ -1,17 +1,14 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat import kotlinx.coroutines.flow.first import space.kscience.kmath.chains.Chain -import space.kscience.kmath.chains.combine -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferFactory -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.IntBuffer +import space.kscience.kmath.chains.collect +import space.kscience.kmath.structures.* import kotlin.jvm.JvmName /** @@ -39,7 +36,7 @@ public fun Sampler.sampleBuffer( //creating temporary storage once val tmp = ArrayList(size) - return sample(generator).combine { chain -> + return sample(generator).collect { chain -> //clear list from previous run tmp.clear() //Fill list diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt index 1f442c09b..c1bbace86 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat @@ -41,8 +41,8 @@ public class SamplerSpace(public val algebra: S) : Group = ConstantSampler(algebra.zero) - override fun add(left: Sampler, right: Sampler): Sampler = BasicSampler { generator -> - left.sample(generator).zip(right.sample(generator)) { aValue, bValue -> algebra { aValue + bValue } } + override fun add(a: Sampler, b: Sampler): Sampler = BasicSampler { generator -> + a.sample(generator).zip(b.sample(generator)) { aValue, bValue -> algebra { aValue + bValue } } } override fun scale(a: Sampler, value: Double): Sampler = BasicSampler { generator -> diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt index 43cd5b402..ab80fbe1c 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat @@ -8,6 +8,7 @@ package space.kscience.kmath.stat import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.runningReduce @@ -17,23 +18,16 @@ import space.kscience.kmath.structures.Buffer /** * A function, that transforms a buffer of random quantities to some resulting value */ -public fun interface Statistic { +public interface Statistic { public suspend fun evaluate(data: Buffer): R } -public suspend operator fun Statistic.invoke(data: Buffer): R = evaluate(data) - -/** - * A statistic that is computed in a synchronous blocking mode - */ -public fun interface BlockingStatistic : Statistic { +public interface BlockingStatistic : Statistic { public fun evaluateBlocking(data: Buffer): R override suspend fun evaluate(data: Buffer): R = evaluateBlocking(data) } -public operator fun BlockingStatistic.invoke(data: Buffer): R = evaluateBlocking(data) - /** * A statistic tha could be computed separately on different blocks of data and then composed * @@ -54,10 +48,8 @@ public interface ComposableStatistic : Statistic { override suspend fun evaluate(data: Buffer): R = toResult(computeIntermediate(data)) } -/** - * Flow intermediate state of the [ComposableStatistic] - */ -@OptIn(ExperimentalCoroutinesApi::class) +@FlowPreview +@ExperimentalCoroutinesApi private fun ComposableStatistic.flowIntermediate( flow: Flow>, dispatcher: CoroutineDispatcher = Dispatchers.Default, @@ -72,7 +64,7 @@ private fun ComposableStatistic.flowIntermediate( * * The resulting flow contains values that include the whole previous statistics, not only the last chunk. */ -@OptIn(ExperimentalCoroutinesApi::class) +@OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class) public fun ComposableStatistic.flow( flow: Flow>, dispatcher: CoroutineDispatcher = Dispatchers.Default, diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt index 970a3aab5..4c0d08720 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat diff --git a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt index 202a1c8dd..a8e6a3362 100644 --- a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt +++ b/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt index 19c01e099..2b6b1ca60 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt index 075d7f3e5..0c3d9cb0d 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt index 1dbbf591b..4060c0505 100644 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt +++ b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat 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 9eb84899c..c64bcc78c 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 @@ -1,17 +1,15 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.stat +import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.last -import kotlinx.coroutines.flow.take import kotlinx.coroutines.runBlocking import space.kscience.kmath.streaming.chunked import kotlin.test.Test -import kotlin.test.assertEquals internal class StatisticTest { //create a random number generator. @@ -24,27 +22,12 @@ internal class StatisticTest { val chunked = data.chunked(1000) @Test - fun singleBlockingMean() { - val first = runBlocking { chunked.first()} - val res = Double.mean(first) - assertEquals(0.5,res, 1e-1) + fun testParallelMean() = runBlocking { + val average = Mean.double + .flow(chunked) //create a flow with results + .drop(99) // Skip first 99 values and use one with total data + .first() //get 1e5 data samples average + + println(average) } - - @Test - fun singleSuspendMean() = runBlocking { - val first = runBlocking { chunked.first()} - val res = Double.mean(first) - assertEquals(0.5,res, 1e-1) - } - - @Test - fun parallelMean() = runBlocking { - val average = Double.mean - .flow(chunked) //create a flow from evaluated results - .take(100) // Take 100 data chunks from the source and accumulate them - .last() //get 1e5 data samples average - - assertEquals(0.5,average, 1e-2) - } - } diff --git a/kmath-symja/README.md b/kmath-symja/README.md deleted file mode 100644 index e3c717cff..000000000 --- a/kmath-symja/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-symja - -Symja integration module - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-symja:0.3.0-dev-20`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-symja:0.3.0-dev-20' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-symja:0.3.0-dev-20") -} -``` diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt index 3067b5efb..a343256fa 100644 --- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt +++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.symja diff --git a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt index 30c37c799..8def1ae83 100644 --- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt +++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.symja @@ -64,8 +64,8 @@ public fun MST.toIExpr(): IExpr = when (this) { } is MST.Unary -> when (operation) { - GroupOps.PLUS_OPERATION -> value.toIExpr() - GroupOps.MINUS_OPERATION -> F.Negate(value.toIExpr()) + GroupOperations.PLUS_OPERATION -> value.toIExpr() + GroupOperations.MINUS_OPERATION -> F.Negate(value.toIExpr()) TrigonometricOperations.SIN_OPERATION -> F.Sin(value.toIExpr()) TrigonometricOperations.COS_OPERATION -> F.Cos(value.toIExpr()) TrigonometricOperations.TAN_OPERATION -> F.Tan(value.toIExpr()) @@ -85,10 +85,10 @@ public fun MST.toIExpr(): IExpr = when (this) { } is MST.Binary -> when (operation) { - GroupOps.PLUS_OPERATION -> left.toIExpr() + right.toIExpr() - GroupOps.MINUS_OPERATION -> left.toIExpr() - right.toIExpr() - RingOps.TIMES_OPERATION -> left.toIExpr() * right.toIExpr() - FieldOps.DIV_OPERATION -> F.Divide(left.toIExpr(), right.toIExpr()) + GroupOperations.PLUS_OPERATION -> left.toIExpr() + right.toIExpr() + GroupOperations.MINUS_OPERATION -> left.toIExpr() - right.toIExpr() + RingOperations.TIMES_OPERATION -> left.toIExpr() * right.toIExpr() + FieldOperations.DIV_OPERATION -> F.Divide(left.toIExpr(), right.toIExpr()) PowerOperations.POW_OPERATION -> F.Power(left.toIExpr(), F.symjify((right as MST.Numeric).value)) else -> error("Binary operation $operation not defined in $this") } diff --git a/kmath-tensorflow/README.md b/kmath-tensorflow/README.md deleted file mode 100644 index f1dfa0202..000000000 --- a/kmath-tensorflow/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-tensorflow - -Google tensorflow connector - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-tensorflow:0.3.0-dev-20`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-tensorflow:0.3.0-dev-20' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-tensorflow:0.3.0-dev-20") -} -``` diff --git a/kmath-tensorflow/build.gradle.kts b/kmath-tensorflow/build.gradle.kts deleted file mode 100644 index 9380a7308..000000000 --- a/kmath-tensorflow/build.gradle.kts +++ /dev/null @@ -1,15 +0,0 @@ -plugins { - id("ru.mipt.npm.gradle.jvm") -} - -description = "Google tensorflow connector" - -dependencies { - api(project(":kmath-tensors")) - api("org.tensorflow:tensorflow-core-api:0.4.0") - testImplementation("org.tensorflow:tensorflow-core-platform:0.4.0") -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE -} \ No newline at end of file diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt deleted file mode 100644 index ecfd8d098..000000000 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowAlgebra.kt +++ /dev/null @@ -1,94 +0,0 @@ -package space.kscience.kmath.tensorflow - -import org.tensorflow.Graph -import org.tensorflow.Output -import org.tensorflow.ndarray.NdArray -import org.tensorflow.op.core.Constant -import org.tensorflow.types.TFloat64 -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.DefaultStrides -import space.kscience.kmath.nd.Shape -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.PowerOperations - -public class DoubleTensorFlowOutput( - graph: Graph, - output: Output, -) : TensorFlowOutput(graph, output) { - - override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = this as TFloat64 - -} - -public class DoubleTensorFlowAlgebra internal constructor( - graph: Graph, -) : TensorFlowAlgebra(graph), PowerOperations> { - - override val elementAlgebra: DoubleField get() = DoubleField - - override fun structureND( - shape: Shape, - initializer: DoubleField.(IntArray) -> Double, - ): StructureND { - val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array -> - DefaultStrides(shape).forEach { index -> - array.setDouble(elementAlgebra.initializer(index), *index.toLongArray()) - } - } - return DoubleTensorFlowOutput(graph, ops.constant(res).asOutput()) - } - - override fun StructureND.asTensorFlow(): TensorFlowOutput = - if (this is TensorFlowOutput && output.type() == TFloat64::class.java) { - @Suppress("UNCHECKED_CAST") - this as TensorFlowOutput - } else { - val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array -> - @OptIn(PerformancePitfall::class) - elements().forEach { (index, value) -> - array.setDouble(value, *index.toLongArray()) - } - } - DoubleTensorFlowOutput(graph, ops.constant(res).asOutput()) - } - - override fun Output.wrap(): TensorFlowOutput = DoubleTensorFlowOutput(graph, this) - - override fun const(value: Double): Constant = ops.constant(value) - - override fun divide( - left: StructureND, - right: StructureND, - ): TensorFlowOutput = left.operate(right) { l, r -> - ops.math.div(l, r) - } - - override fun power(arg: StructureND, pow: Number): TensorFlowOutput = - arg.operate { ops.math.pow(it, const(pow.toDouble())) } -} - -/** - * Compute a tensor with TensorFlow in a single run. - * - * The resulting tensor is available outside of scope - */ -public fun DoubleField.produceWithTF( - block: DoubleTensorFlowAlgebra.() -> StructureND, -): StructureND = Graph().use { graph -> - val scope = DoubleTensorFlowAlgebra(graph) - scope.export(scope.block()) -} - -/** - * Compute several outputs with TensorFlow in a single run. - * - * The resulting tensors are available outside of scope - */ -public fun DoubleField.produceMapWithTF( - block: DoubleTensorFlowAlgebra.() -> Map>, -): Map> = Graph().use { graph -> - val scope = DoubleTensorFlowAlgebra(graph) - scope.block().mapValues { scope.export(it.value) } -} \ No newline at end of file diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt deleted file mode 100644 index 084a445e0..000000000 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/IntTensorFlowAlgebra.kt +++ /dev/null @@ -1,21 +0,0 @@ -package space.kscience.kmath.tensorflow - -import org.tensorflow.Graph -import org.tensorflow.Output -import org.tensorflow.ndarray.NdArray -import org.tensorflow.types.TInt32 -import org.tensorflow.types.TInt64 - -public class IntTensorFlowOutput( - graph: Graph, - output: Output, -) : TensorFlowOutput(graph, output) { - override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = this as TInt32 -} - -public class LongTensorFlowOutput( - graph: Graph, - output: Output, -) : TensorFlowOutput(graph, output) { - override fun org.tensorflow.Tensor.actualizeTensor(): NdArray = this as TInt64 -} \ No newline at end of file diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt deleted file mode 100644 index b40739ee0..000000000 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/TensorFlowAlgebra.kt +++ /dev/null @@ -1,260 +0,0 @@ -package space.kscience.kmath.tensorflow - - -import org.tensorflow.Graph -import org.tensorflow.Operand -import org.tensorflow.Output -import org.tensorflow.Session -import org.tensorflow.ndarray.NdArray -import org.tensorflow.op.Ops -import org.tensorflow.op.core.Constant -import org.tensorflow.op.core.Max -import org.tensorflow.op.core.Min -import org.tensorflow.op.core.Sum -import org.tensorflow.types.TInt32 -import org.tensorflow.types.family.TNumber -import org.tensorflow.types.family.TType -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.Shape -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.api.TensorAlgebra - -internal fun IntArray.toLongArray() = LongArray(size) { get(it).toLong() } -internal fun LongArray.toIntArray() = IntArray(size) { get(it).toInt() } - -internal val NdArray.scalar: T get() = getObject() - - -public sealed interface TensorFlowTensor : Tensor - -/** - * Static (eager) in-memory TensorFlow tensor - */ -@JvmInline -public value class TensorFlowArray(public val tensor: NdArray) : Tensor { - override val shape: Shape get() = tensor.shape().asArray().toIntArray() - - override fun get(index: IntArray): T = tensor.getObject(*index.toLongArray()) - - //TODO implement native element sequence - - override fun set(index: IntArray, value: T) { - tensor.setObject(value, *index.toLongArray()) - } -} - -/** - * Lazy graph-based TensorFlow tensor. The tensor is actualized on call. - * - * If the tensor is used for intermediate operations, actualizing it could impact performance. - */ -public abstract class TensorFlowOutput( - protected val graph: Graph, - output: Output, -) : TensorFlowTensor { - - public var output: Output = output - internal set - - override val shape: Shape get() = output.shape().asArray().toIntArray() - - protected abstract fun org.tensorflow.Tensor.actualizeTensor(): NdArray - - internal val actualTensor by lazy { - Session(graph).use { session -> - TensorFlowArray(session.runner().fetch(output).run().first().actualizeTensor()) - } - } - - override fun get(index: IntArray): T = actualTensor[index] - - @PerformancePitfall - override fun elements(): Sequence> = actualTensor.elements() - - override fun set(index: IntArray, value: T) { - actualTensor[index] = value - } - -} - - -public abstract class TensorFlowAlgebra> internal constructor( - protected val graph: Graph, -) : TensorAlgebra { - - public val ops: Ops by lazy { Ops.create(graph) } - - protected abstract fun StructureND.asTensorFlow(): TensorFlowOutput - - protected abstract fun Output.wrap(): TensorFlowOutput - - protected abstract fun const(value: T): Constant - - override fun StructureND.valueOrNull(): T? = if (shape contentEquals intArrayOf(1)) - get(Shape(0)) else null - - /** - * Perform binary lazy operation on tensor. Both arguments are implicitly converted - */ - public fun StructureND.operate( - other: StructureND, - operation: (left: Operand, right: Operand) -> Operand, - ): TensorFlowOutput { - val left = asTensorFlow().output - val right = other.asTensorFlow().output - return operation(left, right).asOutput().wrap() - } - - public fun T.operate( - other: StructureND, - operation: (left: Operand, right: Operand) -> Operand, - ): TensorFlowOutput { - val left = const(this) - val right = other.asTensorFlow().output - return operation(left, right).asOutput().wrap() - } - - public fun StructureND.operate( - value: T, - operation: (left: Operand, right: Operand) -> Operand, - ): TensorFlowOutput { - val left = asTensorFlow().output - val right = const(value) - return operation(left, right).asOutput().wrap() - } - - public fun Tensor.operateInPlace( - other: StructureND, - operation: (left: Operand, right: Operand) -> Operand, - ): Unit { - val origin = asTensorFlow() - val left = origin.output - val right = other.asTensorFlow().output - origin.output = operation(left, right).asOutput() - } - - public fun Tensor.operateInPlace( - value: T, - operation: (left: Operand, right: Operand) -> Operand, - ): Unit { - val origin = asTensorFlow() - val left = origin.output - val right = const(value) - origin.output = operation(left, right).asOutput() - } - - public fun StructureND.operate(operation: (Operand) -> Operand): TensorFlowOutput = - operation(asTensorFlow().output).asOutput().wrap() - - override fun T.plus(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::add) - - override fun StructureND.plus(arg: T): TensorFlowOutput = operate(arg, ops.math::add) - - override fun StructureND.plus(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::add) - - override fun Tensor.plusAssign(value: T): Unit = operateInPlace(value, ops.math::add) - - override fun Tensor.plusAssign(arg: StructureND): Unit = operateInPlace(arg, ops.math::add) - - override fun StructureND.minus(arg: T): TensorFlowOutput = operate(arg, ops.math::sub) - - override fun StructureND.minus(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::sub) - - override fun T.minus(arg: StructureND): Tensor = operate(arg, ops.math::sub) - - override fun Tensor.minusAssign(value: T): Unit = operateInPlace(value, ops.math::sub) - - override fun Tensor.minusAssign(arg: StructureND): Unit = operateInPlace(arg, ops.math::sub) - - override fun T.times(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::mul) - - override fun StructureND.times(arg: T): TensorFlowOutput = operate(arg, ops.math::mul) - - override fun StructureND.times(arg: StructureND): TensorFlowOutput = operate(arg, ops.math::mul) - - override fun Tensor.timesAssign(value: T): Unit = operateInPlace(value, ops.math::mul) - - override fun Tensor.timesAssign(arg: StructureND): Unit = operateInPlace(arg, ops.math::mul) - - override fun StructureND.unaryMinus(): TensorFlowOutput = operate(ops.math::neg) - - override fun Tensor.get(i: Int): Tensor = operate { - TODO("Not yet implemented") - } - - override fun Tensor.transpose(i: Int, j: Int): Tensor = operate { - ops.linalg.transpose(it, ops.constant(intArrayOf(i, j))) - } - - override fun Tensor.view(shape: IntArray): Tensor = operate { - ops.reshape(it, ops.constant(shape)) - } - - override fun Tensor.viewAs(other: StructureND): Tensor = operate(other) { l, r -> - ops.reshape(l, ops.shape(r)) - } - - override fun StructureND.dot(other: StructureND): TensorFlowOutput = operate(other) { l, r -> - ops.linalg.matMul( - if (l.shape().numDimensions() == 1) ops.expandDims(l, ops.constant(0)) else l, - if (r.shape().numDimensions() == 1) ops.expandDims(r, ops.constant(-1)) else r - ) - } - - override fun diagonalEmbedding( - diagonalEntries: Tensor, - offset: Int, - dim1: Int, - dim2: Int, - ): TensorFlowOutput = diagonalEntries.operate { - TODO("Not yet implemented") - } - - override fun StructureND.sum(): T = operate { - ops.sum(it, ops.constant(intArrayOf())) - }.value() - - override fun StructureND.sum(dim: Int, keepDim: Boolean): TensorFlowOutput = operate { - ops.sum(it, ops.constant(dim), Sum.keepDims(keepDim)) - } - - override fun StructureND.min(): T = operate { - ops.min(it, ops.constant(intArrayOf())) - }.value() - - override fun StructureND.min(dim: Int, keepDim: Boolean): Tensor = operate { - ops.min(it, ops.constant(dim), Min.keepDims(keepDim)) - } - - override fun StructureND.max(): T = operate { - ops.max(it, ops.constant(intArrayOf())) - }.value() - - override fun StructureND.max(dim: Int, keepDim: Boolean): Tensor = operate { - ops.max(it, ops.constant(dim), Max.keepDims(keepDim)) - } - - override fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor = IntTensorFlowOutput( - graph, - ops.math.argMax(asTensorFlow().output, ops.constant(dim), TInt32::class.java).output() - ).actualTensor - -// private val symbolCache = HashMap>() -// -// override fun bindSymbolOrNull(value: String): TensorFlowOutput? { -// return symbolCache.getOrPut(value){ops.var} -// } -// -// public fun StructureND.grad( -// -// )= operate { ops.gradients() } - - @OptIn(UnstableKMathAPI::class) - override fun export(arg: StructureND): StructureND = - if (arg is TensorFlowOutput) arg.actualTensor else arg -} - -//TODO add TensorFlow expressions \ No newline at end of file diff --git a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt b/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt deleted file mode 100644 index f67c333ce..000000000 --- a/kmath-tensorflow/src/main/kotlin/space/kscience/kmath/tensorflow/tfOperations.kt +++ /dev/null @@ -1,23 +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.tensorflow - -import org.tensorflow.types.family.TNumber -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.TrigonometricOperations - -// - -// TODO add other operations - -public fun TensorFlowAlgebra.sin( - arg: StructureND, -): TensorFlowOutput where A : TrigonometricOperations, A : Ring = arg.operate { ops.math.sin(it) } - -public fun TensorFlowAlgebra.cos( - arg: StructureND, -): TensorFlowOutput where A : TrigonometricOperations, A : Ring = arg.operate { ops.math.cos(it) } \ No newline at end of file diff --git a/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt b/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt deleted file mode 100644 index 308469eed..000000000 --- a/kmath-tensorflow/src/test/kotlin/space/kscience/kmath/tensorflow/DoubleTensorFlowOps.kt +++ /dev/null @@ -1,47 +0,0 @@ -package space.kscience.kmath.tensorflow - -import org.junit.jupiter.api.Test -import space.kscience.kmath.nd.get -import space.kscience.kmath.nd.structureND -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra.Companion.sum -import kotlin.test.assertEquals - -class DoubleTensorFlowOps { - @Test - fun basicOps() { - val res = DoubleField.produceWithTF { - val initial = structureND(2, 2) { 1.0 } - - initial + (initial * 2.0) - } - //println(StructureND.toString(res)) - assertEquals(3.0, res[0, 0]) - } - - @Test - fun dot(){ - val dim = 1000 - - val tensor1 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12224) - val tensor2 = DoubleTensorAlgebra.randomNormal(shape = intArrayOf(dim, dim), 12225) - - DoubleField.produceWithTF { - tensor1 dot tensor2 - }.sum() - } - - @Test - fun extensionOps(){ - val res = DoubleField.produceWithTF { - val i = structureND(2, 2) { 0.5 } - - sin(i).pow(2) + cos(i).pow(2) - } - - assertEquals(1.0, res[0,0],0.01) - } - - -} \ No newline at end of file diff --git a/kmath-tensors/README.md b/kmath-tensors/README.md index 3d7dfd1fb..b19a55381 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -9,17 +9,17 @@ Common linear algebra operations on tensors. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-20`. +The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-14`. -**Gradle Groovy:** -```groovy +**Gradle:** +```gradle repositories { maven { url 'https://repo.kotlin.link' } mavenCentral() } dependencies { - implementation 'space.kscience:kmath-tensors:0.3.0-dev-20' + implementation 'space.kscience:kmath-tensors:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -30,6 +30,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-tensors:0.3.0-dev-20") + implementation("space.kscience:kmath-tensors:0.3.0-dev-14") } ``` diff --git a/kmath-tensors/build.gradle.kts b/kmath-tensors/build.gradle.kts index 66316d21d..d084878ea 100644 --- a/kmath-tensors/build.gradle.kts +++ b/kmath-tensors/build.gradle.kts @@ -6,13 +6,9 @@ plugins { kotlin.sourceSets { all { - languageSettings.optIn("space.kscience.kmath.misc.UnstableKMathAPI") + languageSettings.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") } - filter { it.name.contains("test", true) } - .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) - .forEach { it.optIn("space.kscience.kmath.misc.PerformancePitfall") } - commonMain { dependencies { api(project(":kmath-core")) 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 3ed34ae5e..851810c8d 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 @@ -1,27 +1,22 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.api -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.ExtendedFieldOps -import space.kscience.kmath.operations.Field - /** * Analytic operations on [Tensor]. * * @param T the type of items closed under analytic functions in the tensors. */ -public interface AnalyticTensorAlgebra> : - TensorPartialDivisionAlgebra, ExtendedFieldOps> { +public interface AnalyticTensorAlgebra : TensorPartialDivisionAlgebra { /** * @return the mean of all elements in the input tensor. */ - public fun StructureND.mean(): T + public fun Tensor.mean(): T /** * Returns the mean of each row of the input tensor in the given dimension [dim]. @@ -34,12 +29,12 @@ public interface AnalyticTensorAlgebra> : * @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 StructureND.mean(dim: Int, keepDim: Boolean): Tensor + public fun Tensor.mean(dim: Int, keepDim: Boolean): Tensor /** * @return the standard deviation of all elements in the input tensor. */ - public fun StructureND.std(): T + public fun Tensor.std(): T /** * Returns the standard deviation of each row of the input tensor in the given dimension [dim]. @@ -52,12 +47,12 @@ public interface AnalyticTensorAlgebra> : * @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 StructureND.std(dim: Int, keepDim: Boolean): Tensor + public fun Tensor.std(dim: Int, keepDim: Boolean): Tensor /** * @return the variance of all elements in the input tensor. */ - public fun StructureND.variance(): T + public fun Tensor.variance(): T /** * Returns the variance of each row of the input tensor in the given dimension [dim]. @@ -70,80 +65,57 @@ public interface AnalyticTensorAlgebra> : * @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 StructureND.variance(dim: Int, keepDim: Boolean): Tensor + public fun Tensor.variance(dim: Int, keepDim: Boolean): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.exp.html - public fun StructureND.exp(): Tensor + public fun Tensor.exp(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.log.html - public fun StructureND.ln(): Tensor + public fun Tensor.ln(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.sqrt.html - public fun StructureND.sqrt(): Tensor + public fun Tensor.sqrt(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.acos.html#torch.cos - public fun StructureND.cos(): Tensor + public fun Tensor.cos(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.acos.html#torch.acos - public fun StructureND.acos(): Tensor + public fun Tensor.acos(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.cosh - public fun StructureND.cosh(): Tensor + public fun Tensor.cosh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.acosh - public fun StructureND.acosh(): Tensor + public fun Tensor.acosh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sin - public fun StructureND.sin(): Tensor + public fun Tensor.sin(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asin - public fun StructureND.asin(): Tensor + public fun Tensor.asin(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sinh - public fun StructureND.sinh(): Tensor + public fun Tensor.sinh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asinh - public fun StructureND.asinh(): Tensor + public fun Tensor.asinh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.atan.html#torch.tan - public fun StructureND.tan(): Tensor + public fun Tensor.tan(): Tensor //https://pytorch.org/docs/stable/generated/torch.atan.html#torch.atan - public fun StructureND.atan(): Tensor + public fun Tensor.atan(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.tanh - public fun StructureND.tanh(): Tensor + public fun Tensor.tanh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.atanh - public fun StructureND.atanh(): Tensor + public fun Tensor.atanh(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.ceil.html#torch.ceil - public fun StructureND.ceil(): Tensor + public fun Tensor.ceil(): Tensor //For information: https://pytorch.org/docs/stable/generated/torch.floor.html#torch.floor - public fun StructureND.floor(): Tensor + public fun Tensor.floor(): Tensor - override fun sin(arg: StructureND): StructureND = arg.sin() - - override fun cos(arg: StructureND): StructureND = arg.cos() - - override fun asin(arg: StructureND): StructureND = arg.asin() - - override fun acos(arg: StructureND): StructureND = arg.acos() - - override fun atan(arg: StructureND): StructureND = arg.atan() - - override fun exp(arg: StructureND): StructureND = arg.exp() - - override fun ln(arg: StructureND): StructureND = arg.ln() - - override fun sinh(arg: StructureND): StructureND = arg.sinh() - - override fun cosh(arg: StructureND): StructureND = arg.cosh() - - override fun asinh(arg: StructureND): StructureND = arg.asinh() - - override fun acosh(arg: StructureND): StructureND = arg.acosh() - - override fun atanh(arg: StructureND): StructureND = arg.atanh() } \ 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 0bddc3f9c..78aad2189 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 @@ -1,19 +1,16 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.api -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.Field - /** * Common linear algebra operations. Operates on [Tensor]. * * @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. @@ -21,7 +18,7 @@ public interface LinearOpsTensorAlgebra> : TensorPartialDivision * * @return the determinant. */ - public fun StructureND.det(): Tensor + public fun Tensor.det(): Tensor /** * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input. @@ -31,7 +28,7 @@ public interface LinearOpsTensorAlgebra> : TensorPartialDivision * * @return the multiplicative inverse of a matrix. */ - public fun StructureND.inv(): Tensor + public fun Tensor.inv(): Tensor /** * Cholesky decomposition. @@ -47,7 +44,7 @@ public interface LinearOpsTensorAlgebra> : TensorPartialDivision * @receiver the `input`. * @return the batch of `L` matrices. */ - public fun StructureND.cholesky(): Tensor + public fun Tensor.cholesky(): Tensor /** * QR decomposition. @@ -61,7 +58,7 @@ public interface LinearOpsTensorAlgebra> : TensorPartialDivision * @receiver the `input`. * @return pair of `Q` and `R` tensors. */ - public fun StructureND.qr(): Pair, Tensor> + public fun Tensor.qr(): Pair, Tensor> /** * LUP decomposition @@ -75,7 +72,7 @@ public interface LinearOpsTensorAlgebra> : TensorPartialDivision * @receiver the `input`. * @return triple of P, L and U tensors */ - public fun StructureND.lu(): Triple, Tensor, Tensor> + public fun Tensor.lu(): Triple, Tensor, Tensor> /** * Singular Value Decomposition. @@ -91,7 +88,7 @@ public interface LinearOpsTensorAlgebra> : TensorPartialDivision * @receiver the `input`. * @return triple `Triple(U, S, V)`. */ - public fun StructureND.svd(): Triple, Tensor, Tensor> + public fun Tensor.svd(): Triple, Tensor, Tensor> /** * Returns eigenvalues and eigenvectors of a real symmetric matrix `input` or a batch of real symmetric matrices, @@ -101,6 +98,6 @@ public interface LinearOpsTensorAlgebra> : TensorPartialDivision * @receiver the `input`. * @return a pair `eigenvalues to eigenvectors` */ - public fun StructureND.symEig(): Pair, Tensor> + public fun Tensor.symEig(): Pair, Tensor> } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt index 482bb5244..e0f296057 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.api 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 86d4eaa4e..6076748d9 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 @@ -1,13 +1,11 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.api -import space.kscience.kmath.nd.RingOpsND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.Ring +import space.kscience.kmath.operations.Algebra /** * Algebra over a ring on [Tensor]. @@ -15,47 +13,47 @@ import space.kscience.kmath.operations.Ring * * @param T the type of items in the tensors. */ -public interface TensorAlgebra> : RingOpsND { +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 StructureND.valueOrNull(): T? + 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 StructureND.value(): T = + public fun Tensor.value(): T = valueOrNull() ?: throw IllegalArgumentException("Inconsistent value for tensor of with $shape shape") /** - * Each element of the tensor [arg] is added to this value. + * Each element of the tensor [other] is added to this value. * The resulting tensor is returned. * - * @param arg tensor to be added. - * @return the sum of this value and tensor [arg]. + * @param other tensor to be added. + * @return the sum of this value and tensor [other]. */ - override operator fun T.plus(arg: StructureND): Tensor + public operator fun T.plus(other: Tensor): Tensor /** - * Adds the scalar [arg] to each element of this tensor and returns a new resulting tensor. + * Adds the scalar [value] to each element of this tensor and returns a new resulting tensor. * - * @param arg the number to be added to each element of this tensor. - * @return the sum of this tensor and [arg]. + * @param value the number to be added to each element of this tensor. + * @return the sum of this tensor and [value]. */ - override operator fun StructureND.plus(arg: T): Tensor + public operator fun Tensor.plus(value: T): Tensor /** - * Each element of the tensor [arg] is added to each element of this tensor. + * Each element of the tensor [other] is added to each element of this tensor. * The resulting tensor is returned. * - * @param arg tensor to be added. - * @return the sum of this tensor and [arg]. + * @param other tensor to be added. + * @return the sum of this tensor and [other]. */ - override operator fun StructureND.plus(arg: StructureND): Tensor + public operator fun Tensor.plus(other: Tensor): Tensor /** * Adds the scalar [value] to each element of this tensor. @@ -65,37 +63,37 @@ public interface TensorAlgebra> : RingOpsND { public operator fun Tensor.plusAssign(value: T) /** - * Each element of the tensor [arg] is added to each element of this tensor. + * Each element of the tensor [other] is added to each element of this tensor. * - * @param arg tensor to be added. + * @param other tensor to be added. */ - public operator fun Tensor.plusAssign(arg: StructureND) + public operator fun Tensor.plusAssign(other: Tensor) /** - * Each element of the tensor [arg] is subtracted from this value. + * Each element of the tensor [other] is subtracted from this value. * The resulting tensor is returned. * - * @param arg tensor to be subtracted. - * @return the difference between this value and tensor [arg]. + * @param other tensor to be subtracted. + * @return the difference between this value and tensor [other]. */ - override operator fun T.minus(arg: StructureND): Tensor + public operator fun T.minus(other: Tensor): Tensor /** - * Subtracts the scalar [arg] from each element of this tensor and returns a new resulting tensor. + * Subtracts the scalar [value] from each element of this tensor and returns a new resulting tensor. * - * @param arg the number to be subtracted from each element of this tensor. - * @return the difference between this tensor and [arg]. + * @param value the number to be subtracted from each element of this tensor. + * @return the difference between this tensor and [value]. */ - override operator fun StructureND.minus(arg: T): Tensor + public operator fun Tensor.minus(value: T): Tensor /** - * Each element of the tensor [arg] is subtracted from each element of this tensor. + * Each element of the tensor [other] is subtracted from each element of this tensor. * The resulting tensor is returned. * - * @param arg tensor to be subtracted. - * @return the difference between this tensor and [arg]. + * @param other tensor to be subtracted. + * @return the difference between this tensor and [other]. */ - override operator fun StructureND.minus(arg: StructureND): Tensor + public operator fun Tensor.minus(other: Tensor): Tensor /** * Subtracts the scalar [value] from each element of this tensor. @@ -105,38 +103,38 @@ public interface TensorAlgebra> : RingOpsND { public operator fun Tensor.minusAssign(value: T) /** - * Each element of the tensor [arg] is subtracted from each element of this tensor. + * Each element of the tensor [other] is subtracted from each element of this tensor. * - * @param arg tensor to be subtracted. + * @param other tensor to be subtracted. */ - public operator fun Tensor.minusAssign(arg: StructureND) + public operator fun Tensor.minusAssign(other: Tensor) /** - * Each element of the tensor [arg] is multiplied by this value. + * Each element of the tensor [other] is multiplied by this value. * The resulting tensor is returned. * - * @param arg tensor to be multiplied. - * @return the product of this value and tensor [arg]. + * @param other tensor to be multiplied. + * @return the product of this value and tensor [other]. */ - override operator fun T.times(arg: StructureND): Tensor + public operator fun T.times(other: Tensor): Tensor /** - * Multiplies the scalar [arg] by each element of this tensor and returns a new resulting tensor. + * Multiplies the scalar [value] by each element of this tensor and returns a new resulting tensor. * - * @param arg the number to be multiplied by each element of this tensor. - * @return the product of this tensor and [arg]. + * @param value the number to be multiplied by each element of this tensor. + * @return the product of this tensor and [value]. */ - override operator fun StructureND.times(arg: T): Tensor + public operator fun Tensor.times(value: T): Tensor /** - * Each element of the tensor [arg] is multiplied by each element of this tensor. + * Each element of the tensor [other] is multiplied by each element of this tensor. * The resulting tensor is returned. * - * @param arg tensor to be multiplied. - * @return the product of this tensor and [arg]. + * @param other tensor to be multiplied. + * @return the product of this tensor and [other]. */ - override operator fun StructureND.times(arg: StructureND): Tensor + public operator fun Tensor.times(other: Tensor): Tensor /** * Multiplies the scalar [value] by each element of this tensor. @@ -146,18 +144,18 @@ public interface TensorAlgebra> : RingOpsND { public operator fun Tensor.timesAssign(value: T) /** - * Each element of the tensor [arg] is multiplied by each element of this tensor. + * Each element of the tensor [other] is multiplied by each element of this tensor. * - * @param arg tensor to be multiplied. + * @param other tensor to be multiplied. */ - public operator fun Tensor.timesAssign(arg: StructureND) + public operator fun Tensor.timesAssign(other: Tensor) /** * Numerical negative, element-wise. * * @return tensor negation of the original tensor. */ - override operator fun StructureND.unaryMinus(): Tensor + public operator fun Tensor.unaryMinus(): Tensor /** * Returns the tensor at index i @@ -196,7 +194,7 @@ public interface TensorAlgebra> : RingOpsND { * @param other the result tensor has the same size as other. * @return the result tensor with the same size as other. */ - public fun Tensor.viewAs(other: StructureND): Tensor + public fun Tensor.viewAs(other: Tensor): Tensor /** * Matrix product of two tensors. @@ -208,7 +206,7 @@ public interface TensorAlgebra> : RingOpsND { * * 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, depending on the implementation the prepended dimension might be removed. + * 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. @@ -227,7 +225,7 @@ public interface TensorAlgebra> : RingOpsND { * @param other tensor to be multiplied. * @return a mathematical product of two tensors. */ - public infix fun StructureND.dot(other: StructureND): Tensor + public infix fun Tensor.dot(other: Tensor): Tensor /** * Creates a tensor whose diagonals of certain 2D planes (specified by [dim1] and [dim2]) @@ -262,7 +260,7 @@ public interface TensorAlgebra> : RingOpsND { /** * @return the sum of all elements in the input tensor. */ - public fun StructureND.sum(): T + public fun Tensor.sum(): T /** * Returns the sum of each row of the input tensor in the given dimension [dim]. @@ -275,12 +273,12 @@ public interface TensorAlgebra> : RingOpsND { * @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 StructureND.sum(dim: Int, keepDim: Boolean): Tensor + public fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor /** - * @return the minimum value of all elements in the input tensor or null if there are no values + * @return the minimum value of all elements in the input tensor. */ - public fun StructureND.min(): T? + public fun Tensor.min(): T /** * Returns the minimum value of each row of the input tensor in the given dimension [dim]. @@ -293,12 +291,12 @@ public interface TensorAlgebra> : RingOpsND { * @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 StructureND.min(dim: Int, keepDim: Boolean): Tensor + public fun Tensor.min(dim: Int, keepDim: Boolean): Tensor /** - * Returns the maximum value of all elements in the input tensor or null if there are no values + * Returns the maximum value of all elements in the input tensor. */ - public fun StructureND.max(): T? + public fun Tensor.max(): T /** * Returns the maximum value of each row of the input tensor in the given dimension [dim]. @@ -311,7 +309,7 @@ public interface TensorAlgebra> : RingOpsND { * @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 StructureND.max(dim: Int, keepDim: Boolean): Tensor + 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]. @@ -324,9 +322,5 @@ public interface TensorAlgebra> : RingOpsND { * @param keepDim whether the output tensor has [dim] retained or not. * @return the index of maximum value of each row of the input tensor in the given dimension [dim]. */ - public fun StructureND.argMax(dim: Int, keepDim: Boolean): Tensor - - override fun add(left: StructureND, right: StructureND): Tensor = left + right - - override fun multiply(left: StructureND, right: StructureND): Tensor = left * right + public fun Tensor.argMax(dim: Int, keepDim: Boolean): 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 9c492cda1..ce519288b 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 @@ -1,49 +1,43 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.api -import space.kscience.kmath.nd.FieldOpsND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.Field - /** * 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. */ -public interface TensorPartialDivisionAlgebra> : TensorAlgebra, FieldOpsND { +public interface TensorPartialDivisionAlgebra : TensorAlgebra { /** - * Each element of the tensor [arg] is divided by this value. + * Each element of the tensor [other] is divided by this value. * The resulting tensor is returned. * - * @param arg tensor to divide by. - * @return the division of this value by the tensor [arg]. + * @param other tensor to divide by. + * @return the division of this value by the tensor [other]. */ - override operator fun T.div(arg: StructureND): Tensor + public operator fun T.div(other: Tensor): Tensor /** - * Divide by the scalar [arg] each element of this tensor returns a new resulting tensor. + * Divide by the scalar [value] each element of this tensor returns a new resulting tensor. * - * @param arg the number to divide by each element of this tensor. - * @return the division of this tensor by the [arg]. + * @param value the number to divide by each element of this tensor. + * @return the division of this tensor by the [value]. */ - override operator fun StructureND.div(arg: T): Tensor + public operator fun Tensor.div(value: T): Tensor /** - * Each element of the tensor [arg] is divided by each element of this tensor. + * Each element of the tensor [other] is divided by each element of this tensor. * The resulting tensor is returned. * - * @param arg tensor to be divided by. - * @return the division of this tensor by [arg]. + * @param other tensor to be divided by. + * @return the division of this tensor by [other]. */ - override operator fun StructureND.div(arg: StructureND): Tensor - - override fun divide(left: StructureND, right: StructureND): StructureND = left.div(right) + public operator fun Tensor.div(other: Tensor): Tensor /** * Divides by the scalar [value] each element of this tensor. @@ -53,9 +47,9 @@ public interface TensorPartialDivisionAlgebra> : TensorAlgebra.divAssign(value: T) /** - * Each element of this tensor is divided by each element of the [arg] tensor. + * Each element of this tensor is divided by each element of the [other] tensor. * - * @param arg tensor to be divided by. + * @param other tensor to be divided by. */ - public operator fun Tensor.divAssign(arg: StructureND) + public operator fun Tensor.divAssign(other: Tensor) } 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 e412ab5bb..3eb8e5636 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,13 +1,10 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.core -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.StructureND import space.kscience.kmath.tensors.api.Tensor import space.kscience.kmath.tensors.core.internal.array import space.kscience.kmath.tensors.core.internal.broadcastTensors @@ -18,90 +15,79 @@ import space.kscience.kmath.tensors.core.internal.tensor * Basic linear algebra operations implemented with broadcasting. * For more information: https://pytorch.org/docs/stable/notes/broadcasting.html */ - -@PerformancePitfall public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { - override fun StructureND.plus(arg: StructureND): DoubleTensor { - val broadcast = broadcastTensors(tensor, arg.tensor) + override fun Tensor.plus(other: Tensor): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> + val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> newThis.mutableBuffer.array()[i] + newOther.mutableBuffer.array()[i] } return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.plusAssign(arg: StructureND) { - val newOther = broadcastTo(arg.tensor, tensor.shape) - for (i in 0 until tensor.indices.linearSize) { + 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] += newOther.mutableBuffer.array()[tensor.bufferStart + i] } } - override fun StructureND.minus(arg: StructureND): DoubleTensor { - val broadcast = broadcastTensors(tensor, arg.tensor) + override fun Tensor.minus(other: Tensor): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> + val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> newThis.mutableBuffer.array()[i] - newOther.mutableBuffer.array()[i] } return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.minusAssign(arg: StructureND) { - val newOther = broadcastTo(arg.tensor, tensor.shape) - for (i in 0 until tensor.indices.linearSize) { + 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] -= newOther.mutableBuffer.array()[tensor.bufferStart + i] } } - override fun StructureND.times(arg: StructureND): DoubleTensor { - val broadcast = broadcastTensors(tensor, arg.tensor) + override fun Tensor.times(other: Tensor): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> + val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> newThis.mutableBuffer.array()[newThis.bufferStart + i] * newOther.mutableBuffer.array()[newOther.bufferStart + i] } return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.timesAssign(arg: StructureND) { - val newOther = broadcastTo(arg.tensor, tensor.shape) - for (i in 0 until tensor.indices.linearSize) { + 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] *= newOther.mutableBuffer.array()[tensor.bufferStart + i] } } - override fun StructureND.div(arg: StructureND): DoubleTensor { - val broadcast = broadcastTensors(tensor, arg.tensor) + override fun Tensor.div(other: Tensor): DoubleTensor { + val broadcast = broadcastTensors(tensor, other.tensor) val newThis = broadcast[0] val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.indices.linearSize) { i -> + val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> newThis.mutableBuffer.array()[newOther.bufferStart + i] / newOther.mutableBuffer.array()[newOther.bufferStart + i] } return DoubleTensor(newThis.shape, resBuffer) } - override fun Tensor.divAssign(arg: StructureND) { - val newOther = broadcastTo(arg.tensor, tensor.shape) - for (i in 0 until tensor.indices.linearSize) { + 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] /= newOther.mutableBuffer.array()[tensor.bufferStart + i] } } -} - - -/** - * Compute a value using broadcast double tensor algebra - */ -@UnstableKMathAPI -@PerformancePitfall -public fun DoubleTensorAlgebra.withBroadcast(block: BroadcastDoubleTensorAlgebra.() -> R): R = - BroadcastDoubleTensorAlgebra.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/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 73a89502c..bf9a9f7f7 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,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.core @@ -9,6 +9,7 @@ import space.kscience.kmath.misc.PerformancePitfall import space.kscience.kmath.nd.Strides import space.kscience.kmath.structures.MutableBuffer import space.kscience.kmath.tensors.api.Tensor +import space.kscience.kmath.tensors.core.internal.TensorLinearStructure /** * Represents [Tensor] over a [MutableBuffer] intended to be used through [DoubleTensor] and [IntTensor] @@ -22,22 +23,23 @@ public open class BufferedTensor internal constructor( /** * Buffer strides based on [TensorLinearStructure] implementation */ - override val indices: Strides get() = TensorLinearStructure(shape) + public val linearStructure: Strides + get() = TensorLinearStructure(shape) /** * Number of elements in tensor */ public val numElements: Int - get() = indices.linearSize + get() = linearStructure.linearSize - override fun get(index: IntArray): T = mutableBuffer[bufferStart + indices.offset(index)] + override fun get(index: IntArray): T = mutableBuffer[bufferStart + linearStructure.offset(index)] override fun set(index: IntArray, value: T) { - mutableBuffer[bufferStart + indices.offset(index)] = value + mutableBuffer[bufferStart + linearStructure.offset(index)] = value } @PerformancePitfall - override fun elements(): Sequence> = indices.asSequence().map { + override fun elements(): Sequence> = linearStructure.indices().map { it to get(it) } } 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 8e5116336..ad7831fb9 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 @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.core 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 e9dc34748..4b9d13827 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,18 +1,12 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ - -@file:OptIn(PerformancePitfall::class) - package space.kscience.kmath.tensors.core -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.indices +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.Tensor @@ -24,74 +18,16 @@ import kotlin.math.* * Implementation of basic operations over double tensors and basic algebra operations on them. */ public open class DoubleTensorAlgebra : - TensorPartialDivisionAlgebra, - AnalyticTensorAlgebra, - LinearOpsTensorAlgebra { + TensorPartialDivisionAlgebra, + AnalyticTensorAlgebra, + LinearOpsTensorAlgebra { public companion object : DoubleTensorAlgebra() - override val elementAlgebra: DoubleField - get() = DoubleField - - - /** - * 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. - */ - @PerformancePitfall - @Suppress("OVERRIDE_BY_INLINE") - final override inline fun StructureND.map(transform: DoubleField.(Double) -> Double): DoubleTensor { - val tensor = this.tensor - //TODO remove additional copy - val sourceArray = tensor.copyArray() - val array = DoubleArray(tensor.numElements) { DoubleField.transform(sourceArray[it]) } - return DoubleTensor( - tensor.shape, - array, - tensor.bufferStart - ) - } - - @PerformancePitfall - @Suppress("OVERRIDE_BY_INLINE") - final override inline fun StructureND.mapIndexed(transform: DoubleField.(index: IntArray, Double) -> Double): DoubleTensor { - val tensor = this.tensor - //TODO remove additional copy - val sourceArray = tensor.copyArray() - val array = DoubleArray(tensor.numElements) { DoubleField.transform(tensor.indices.index(it), sourceArray[it]) } - return DoubleTensor( - tensor.shape, - array, - tensor.bufferStart - ) - } - - @PerformancePitfall - override fun zip( - left: StructureND, - right: StructureND, - transform: DoubleField.(Double, Double) -> Double, - ): DoubleTensor { - require(left.shape.contentEquals(right.shape)) { - "The shapes in zip are not equal: left - ${left.shape}, right - ${right.shape}" - } - val leftTensor = left.tensor - val leftArray = leftTensor.copyArray() - val rightTensor = right.tensor - val rightArray = rightTensor.copyArray() - val array = DoubleArray(leftTensor.numElements) { DoubleField.transform(leftArray[it], rightArray[it]) } - return DoubleTensor( - leftTensor.shape, - array - ) - } - - override fun StructureND.valueOrNull(): Double? = if (tensor.shape contentEquals intArrayOf(1)) + override fun Tensor.valueOrNull(): Double? = if (tensor.shape contentEquals intArrayOf(1)) tensor.mutableBuffer.array()[tensor.bufferStart] else null - override fun StructureND.value(): Double = valueOrNull() + override fun Tensor.value(): Double = valueOrNull() ?: throw IllegalArgumentException("The tensor shape is $shape, but value method is allowed only for shape [1]") /** @@ -115,10 +51,11 @@ public open class DoubleTensorAlgebra : * @param initializer mapping tensor indices to values. * @return tensor with the [shape] shape and data generated by the [initializer]. */ - override fun structureND(shape: IntArray, initializer: DoubleField.(IntArray) -> Double): DoubleTensor = fromArray( - shape, - TensorLinearStructure(shape).asSequence().map { DoubleField.initializer(it) }.toMutableList().toDoubleArray() - ) + 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() @@ -165,7 +102,7 @@ public open class DoubleTensorAlgebra : * * @return tensor filled with the scalar value `0.0`, with the same shape as `input` tensor. */ - public fun StructureND.zeroesLike(): DoubleTensor = tensor.fullLike(0.0) + 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]. @@ -203,22 +140,23 @@ public open class DoubleTensorAlgebra : * * @return a copy of the `input` tensor with a copied buffer. */ - public fun StructureND.copy(): DoubleTensor = - DoubleTensor(tensor.shape, tensor.mutableBuffer.array().copyOf(), tensor.bufferStart) - - override fun Double.plus(arg: StructureND): DoubleTensor { - val resBuffer = DoubleArray(arg.tensor.numElements) { i -> - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + this - } - return DoubleTensor(arg.shape, resBuffer) + public fun Tensor.copy(): DoubleTensor { + return DoubleTensor(tensor.shape, tensor.mutableBuffer.array().copyOf(), tensor.bufferStart) } - override fun StructureND.plus(arg: Double): DoubleTensor = arg + tensor + 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 StructureND.plus(arg: StructureND): DoubleTensor { - checkShapesCompatible(tensor, arg.tensor) + override fun Tensor.plus(value: Double): DoubleTensor = value + tensor + + override fun Tensor.plus(other: Tensor): DoubleTensor { + checkShapesCompatible(tensor, other.tensor) val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[i] + arg.tensor.mutableBuffer.array()[i] + tensor.mutableBuffer.array()[i] + other.tensor.mutableBuffer.array()[i] } return DoubleTensor(tensor.shape, resBuffer) } @@ -229,32 +167,32 @@ public open class DoubleTensorAlgebra : } } - override fun Tensor.plusAssign(arg: StructureND) { - checkShapesCompatible(tensor, arg.tensor) + override fun Tensor.plusAssign(other: Tensor) { + checkShapesCompatible(tensor, other.tensor) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] += - arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] + other.tensor.mutableBuffer.array()[tensor.bufferStart + i] } } - override fun Double.minus(arg: StructureND): DoubleTensor { - val resBuffer = DoubleArray(arg.tensor.numElements) { i -> - this - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + 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(arg.shape, resBuffer) + return DoubleTensor(other.shape, resBuffer) } - override fun StructureND.minus(arg: Double): DoubleTensor { + override fun Tensor.minus(value: Double): DoubleTensor { val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[tensor.bufferStart + i] - arg + tensor.mutableBuffer.array()[tensor.bufferStart + i] - value } return DoubleTensor(tensor.shape, resBuffer) } - override fun StructureND.minus(arg: StructureND): DoubleTensor { - checkShapesCompatible(tensor, arg) + override fun Tensor.minus(other: Tensor): DoubleTensor { + checkShapesCompatible(tensor, other) val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[i] - arg.tensor.mutableBuffer.array()[i] + tensor.mutableBuffer.array()[i] - other.tensor.mutableBuffer.array()[i] } return DoubleTensor(tensor.shape, resBuffer) } @@ -265,28 +203,28 @@ public open class DoubleTensorAlgebra : } } - override fun Tensor.minusAssign(arg: StructureND) { - checkShapesCompatible(tensor, arg) + override fun Tensor.minusAssign(other: Tensor) { + checkShapesCompatible(tensor, other) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] -= - arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] + other.tensor.mutableBuffer.array()[tensor.bufferStart + i] } } - override fun Double.times(arg: StructureND): DoubleTensor { - val resBuffer = DoubleArray(arg.tensor.numElements) { i -> - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] * this + 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(arg.shape, resBuffer) + return DoubleTensor(other.shape, resBuffer) } - override fun StructureND.times(arg: Double): DoubleTensor = arg * tensor + override fun Tensor.times(value: Double): DoubleTensor = value * tensor - override fun StructureND.times(arg: StructureND): DoubleTensor { - checkShapesCompatible(tensor, arg) + override fun Tensor.times(other: Tensor): DoubleTensor { + checkShapesCompatible(tensor, other) val resBuffer = DoubleArray(tensor.numElements) { i -> tensor.mutableBuffer.array()[tensor.bufferStart + i] * - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] } return DoubleTensor(tensor.shape, resBuffer) } @@ -297,33 +235,33 @@ public open class DoubleTensorAlgebra : } } - override fun Tensor.timesAssign(arg: StructureND) { - checkShapesCompatible(tensor, arg) + override fun Tensor.timesAssign(other: Tensor) { + checkShapesCompatible(tensor, other) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] *= - arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] + other.tensor.mutableBuffer.array()[tensor.bufferStart + i] } } - override fun Double.div(arg: StructureND): DoubleTensor { - val resBuffer = DoubleArray(arg.tensor.numElements) { i -> - this / arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + 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(arg.shape, resBuffer) + return DoubleTensor(other.shape, resBuffer) } - override fun StructureND.div(arg: Double): DoubleTensor { + override fun Tensor.div(value: Double): DoubleTensor { val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[tensor.bufferStart + i] / arg + tensor.mutableBuffer.array()[tensor.bufferStart + i] / value } return DoubleTensor(shape, resBuffer) } - override fun StructureND.div(arg: StructureND): DoubleTensor { - checkShapesCompatible(tensor, arg) + override fun Tensor.div(other: Tensor): DoubleTensor { + checkShapesCompatible(tensor, other) val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] / - arg.tensor.mutableBuffer.array()[arg.tensor.bufferStart + i] + tensor.mutableBuffer.array()[other.tensor.bufferStart + i] / + other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] } return DoubleTensor(tensor.shape, resBuffer) } @@ -334,15 +272,15 @@ public open class DoubleTensorAlgebra : } } - override fun Tensor.divAssign(arg: StructureND) { - checkShapesCompatible(tensor, arg) + override fun Tensor.divAssign(other: Tensor) { + checkShapesCompatible(tensor, other) for (i in 0 until tensor.numElements) { tensor.mutableBuffer.array()[tensor.bufferStart + i] /= - arg.tensor.mutableBuffer.array()[tensor.bufferStart + i] + other.tensor.mutableBuffer.array()[tensor.bufferStart + i] } } - override fun StructureND.unaryMinus(): DoubleTensor { + override fun Tensor.unaryMinus(): DoubleTensor { val resBuffer = DoubleArray(tensor.numElements) { i -> tensor.mutableBuffer.array()[tensor.bufferStart + i].unaryMinus() } @@ -362,11 +300,11 @@ public open class DoubleTensorAlgebra : val resTensor = DoubleTensor(resShape, resBuffer) for (offset in 0 until n) { - val oldMultiIndex = tensor.indices.index(offset) + val oldMultiIndex = tensor.linearStructure.index(offset) val newMultiIndex = oldMultiIndex.copyOf() newMultiIndex[ii] = newMultiIndex[jj].also { newMultiIndex[jj] = newMultiIndex[ii] } - val linearIndex = resTensor.indices.offset(newMultiIndex) + val linearIndex = resTensor.linearStructure.offset(newMultiIndex) resTensor.mutableBuffer.array()[linearIndex] = tensor.mutableBuffer.array()[tensor.bufferStart + offset] } @@ -378,10 +316,10 @@ public open class DoubleTensorAlgebra : return DoubleTensor(shape, tensor.mutableBuffer.array(), tensor.bufferStart) } - override fun Tensor.viewAs(other: StructureND): DoubleTensor = + override fun Tensor.viewAs(other: Tensor): DoubleTensor = tensor.view(other.shape) - override infix fun StructureND.dot(other: StructureND): 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())) } @@ -418,24 +356,23 @@ public open class DoubleTensorAlgebra : for ((res, ab) in resTensor.matrixSequence().zip(newThis.matrixSequence().zip(newOther.matrixSequence()))) { val (a, b) = ab - dotTo(a, b, res, l, m1, n) + dotHelper(a.as2D(), b.as2D(), res.as2D(), l, m1, n) } - return if (penultimateDim) { - resTensor.view(resTensor.shape.dropLast(2).toIntArray() + intArrayOf(resTensor.shape.last())) - } else if (lastDim) { - resTensor.view(resTensor.shape.dropLast(1).toIntArray()) - } else { - resTensor + if (penultimateDim) { + return resTensor.view( + resTensor.shape.dropLast(2).toIntArray() + + intArrayOf(resTensor.shape.last()) + ) } + if (lastDim) { + return resTensor.view(resTensor.shape.dropLast(1).toIntArray()) + } + return resTensor } - override fun diagonalEmbedding( - diagonalEntries: Tensor, - offset: Int, - dim1: Int, - dim2: Int, - ): DoubleTensor { + override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): + DoubleTensor { val n = diagonalEntries.shape.size val d1 = minusIndexFrom(n + 1, dim1) val d2 = minusIndexFrom(n + 1, dim2) @@ -463,7 +400,7 @@ public open class DoubleTensorAlgebra : val resTensor = zeros(resShape) for (i in 0 until diagonalEntries.tensor.numElements) { - val multiIndex = diagonalEntries.tensor.indices.index(i) + val multiIndex = diagonalEntries.tensor.linearStructure.index(i) var offset1 = 0 var offset2 = abs(realOffset) @@ -482,6 +419,18 @@ public open class DoubleTensorAlgebra : 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 inline fun Tensor.map(transform: (Double) -> Double): DoubleTensor = DoubleTensor( + tensor.shape, + tensor.mutableBuffer.array().map { transform(it) }.toDoubleArray(), + tensor.bufferStart + ) + /** * Compares element-wise two tensors with a specified precision. * @@ -570,14 +519,14 @@ public open class DoubleTensorAlgebra : */ public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { this[it] }) - private inline fun StructureND.fold(foldFunction: (DoubleArray) -> Double): Double = - foldFunction(tensor.copyArray()) + internal inline fun Tensor.fold(foldFunction: (DoubleArray) -> Double): Double = + foldFunction(tensor.toDoubleArray()) - private inline fun StructureND.foldDim( + internal inline fun Tensor.foldDim( + foldFunction: (DoubleArray) -> Double, dim: Int, keepDim: Boolean, - foldFunction: (DoubleArray) -> R, - ): BufferedTensor { + ): 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() @@ -585,75 +534,80 @@ public open class DoubleTensorAlgebra : shape.take(dim).toIntArray() + shape.takeLast(dimension - dim - 1).toIntArray() } val resNumElements = resShape.reduce(Int::times) - val init = foldFunction(DoubleArray(1) { 0.0 }) - val resTensor = BufferedTensor(resShape, - MutableBuffer.auto(resNumElements) { init }, 0) - for (index in resTensor.indices) { + 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 StructureND.sum(): Double = tensor.fold { it.sum() } + override fun Tensor.sum(): Double = tensor.fold { it.sum() } - override fun StructureND.sum(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim(dim, keepDim) { x -> x.sum() }.toDoubleTensor() + override fun Tensor.sum(dim: Int, keepDim: Boolean): DoubleTensor = + foldDim({ x -> x.sum() }, dim, keepDim) - override fun StructureND.min(): Double = this.fold { it.minOrNull()!! } + override fun Tensor.min(): Double = this.fold { it.minOrNull()!! } - override fun StructureND.min(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim(dim, keepDim) { x -> x.minOrNull()!! }.toDoubleTensor() + override fun Tensor.min(dim: Int, keepDim: Boolean): DoubleTensor = + foldDim({ x -> x.minOrNull()!! }, dim, keepDim) - override fun StructureND.max(): Double = this.fold { it.maxOrNull()!! } + override fun Tensor.max(): Double = this.fold { it.maxOrNull()!! } - override fun StructureND.max(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim(dim, keepDim) { x -> x.maxOrNull()!! }.toDoubleTensor() + 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) - override fun StructureND.argMax(dim: Int, keepDim: Boolean): IntTensor = - foldDim(dim, keepDim) { x -> - x.withIndex().maxByOrNull { it.value }?.index!! - }.toIntTensor() + 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 StructureND.mean(): Double = this.fold { it.sum() / tensor.numElements } - - override fun StructureND.mean(dim: Int, keepDim: Boolean): DoubleTensor = foldDim(dim, keepDim) { arr -> - check(dim < dimension) { "Dimension $dim out of range $dimension" } - arr.sum() / shape[dim] - }.toDoubleTensor() - - override fun StructureND.std(): Double = fold { arr -> + 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 StructureND.std(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( + 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 - ) { 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)) - }.toDoubleTensor() + ) - override fun StructureND.variance(): Double = fold { arr -> + 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 StructureND.variance(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( + 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 - ) { 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) - }.toDoubleTensor() + ) private fun cov(x: DoubleTensor, y: DoubleTensor): Double { val n = x.shape[0] @@ -668,7 +622,7 @@ public open class DoubleTensorAlgebra : * @param tensors the [List] of 1-dimensional tensors with same shape * @return `M`. */ - public fun cov(tensors: List>): DoubleTensor { + public 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] @@ -685,43 +639,43 @@ public open class DoubleTensorAlgebra : return resTensor } - override fun StructureND.exp(): DoubleTensor = tensor.map { exp(it) } + override fun Tensor.exp(): DoubleTensor = tensor.map(::exp) - override fun StructureND.ln(): DoubleTensor = tensor.map { ln(it) } + override fun Tensor.ln(): DoubleTensor = tensor.map(::ln) - override fun StructureND.sqrt(): DoubleTensor = tensor.map { sqrt(it) } + override fun Tensor.sqrt(): DoubleTensor = tensor.map(::sqrt) - override fun StructureND.cos(): DoubleTensor = tensor.map { cos(it) } + override fun Tensor.cos(): DoubleTensor = tensor.map(::cos) - override fun StructureND.acos(): DoubleTensor = tensor.map { acos(it) } + override fun Tensor.acos(): DoubleTensor = tensor.map(::acos) - override fun StructureND.cosh(): DoubleTensor = tensor.map { cosh(it) } + override fun Tensor.cosh(): DoubleTensor = tensor.map(::cosh) - override fun StructureND.acosh(): DoubleTensor = tensor.map { acosh(it) } + override fun Tensor.acosh(): DoubleTensor = tensor.map(::acosh) - override fun StructureND.sin(): DoubleTensor = tensor.map { sin(it) } + override fun Tensor.sin(): DoubleTensor = tensor.map(::sin) - override fun StructureND.asin(): DoubleTensor = tensor.map { asin(it) } + override fun Tensor.asin(): DoubleTensor = tensor.map(::asin) - override fun StructureND.sinh(): DoubleTensor = tensor.map { sinh(it) } + override fun Tensor.sinh(): DoubleTensor = tensor.map(::sinh) - override fun StructureND.asinh(): DoubleTensor = tensor.map { asinh(it) } + override fun Tensor.asinh(): DoubleTensor = tensor.map(::asinh) - override fun StructureND.tan(): DoubleTensor = tensor.map { tan(it) } + override fun Tensor.tan(): DoubleTensor = tensor.map(::tan) - override fun StructureND.atan(): DoubleTensor = tensor.map { atan(it) } + override fun Tensor.atan(): DoubleTensor = tensor.map(::atan) - override fun StructureND.tanh(): DoubleTensor = tensor.map { tanh(it) } + override fun Tensor.tanh(): DoubleTensor = tensor.map(::tanh) - override fun StructureND.atanh(): DoubleTensor = tensor.map { atanh(it) } + override fun Tensor.atanh(): DoubleTensor = tensor.map(::atanh) - override fun StructureND.ceil(): DoubleTensor = tensor.map { ceil(it) } + override fun Tensor.ceil(): DoubleTensor = tensor.map(::ceil) - override fun StructureND.floor(): DoubleTensor = tensor.map { floor(it) } + override fun Tensor.floor(): DoubleTensor = tensor.map(::floor) - override fun StructureND.inv(): DoubleTensor = invLU(1e-9) + override fun Tensor.inv(): DoubleTensor = invLU(1e-9) - override fun StructureND.det(): DoubleTensor = detLU(1e-9) + override fun Tensor.det(): DoubleTensor = detLU(1e-9) /** * Computes the LU factorization of a matrix or batches of matrices `input`. @@ -732,7 +686,7 @@ public open class DoubleTensorAlgebra : * 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 StructureND.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") @@ -745,7 +699,7 @@ public open class DoubleTensorAlgebra : * 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 StructureND.luFactor(): Pair = luFactor(1e-9) + public fun Tensor.luFactor(): Pair = luFactor(1e-9) /** * Unpacks the data and pivots from a LU factorization of a tensor. @@ -759,7 +713,7 @@ public open class DoubleTensorAlgebra : * @return triple of `P`, `L` and `U` tensors */ public fun luPivot( - luTensor: StructureND, + luTensor: Tensor, pivotsTensor: Tensor, ): Triple { checkSquareMatrix(luTensor.shape) @@ -802,7 +756,7 @@ public open class DoubleTensorAlgebra : * Used when checking the positive definiteness of the input matrix or matrices. * @return a pair of `Q` and `R` tensors. */ - public fun StructureND.cholesky(epsilon: Double): DoubleTensor { + public fun Tensor.cholesky(epsilon: Double): DoubleTensor { checkSquareMatrix(shape) checkPositiveDefinite(tensor, epsilon) @@ -815,9 +769,9 @@ public open class DoubleTensorAlgebra : return lTensor } - override fun StructureND.cholesky(): DoubleTensor = cholesky(1e-6) + override fun Tensor.cholesky(): DoubleTensor = cholesky(1e-6) - override fun StructureND.qr(): Pair { + override fun Tensor.qr(): Pair { checkSquareMatrix(shape) val qTensor = zeroesLike() val rTensor = zeroesLike() @@ -833,7 +787,7 @@ public open class DoubleTensorAlgebra : return qTensor to rTensor } - override fun StructureND.svd(): Triple = + override fun Tensor.svd(): Triple = svd(epsilon = 1e-10) /** @@ -849,7 +803,7 @@ public open class DoubleTensorAlgebra : * i.e., the precision with which the cosine approaches 1 in an iterative algorithm. * @return a triple `Triple(U, S, V)`. */ - public fun StructureND.svd(epsilon: Double): Triple { + 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) @@ -857,32 +811,28 @@ public open class DoubleTensorAlgebra : val sTensor = zeros(commonShape + intArrayOf(min(n, m))) val vTensor = zeros(commonShape + intArrayOf(min(n, m), m)) - val matrices = tensor.matrices - val uTensors = uTensor.matrices - val sTensorVectors = sTensor.vectors - val vTensors = vTensor.matrices - - for (index in matrices.indices) { - val matrix = matrices[index] - val usv = Triple( - uTensors[index], - sTensorVectors[index], - vTensors[index] - ) - 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) - } + 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 StructureND.symEig(): Pair = symEigJacobi(maxIteration = 50, epsilon = 1e-15) + 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, @@ -892,178 +842,19 @@ public open class DoubleTensorAlgebra : * and when the cosine approaches 1 in the SVD algorithm. * @return a pair `eigenvalues to eigenvectors`. */ - public fun StructureND.symEigSvd(epsilon: Double): Pair { + public fun Tensor.symEig(epsilon: Double): Pair { checkSymmetric(tensor, epsilon) - - fun MutableStructure2D.cleanSym(n: Int) { - for (i in 0 until n) { - for (j in 0 until n) { - if (i == j) { - this[i, j] = sign(this[i, j]) - } else { - this[i, j] = 0.0 - } - } - } - } - 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()) { - matrix.as2D().cleanSym(n) - } + for (matrix in utv.matrixSequence()) + cleanSymHelper(matrix.as2D(), n) val eig = (utv dot s.view(shp)).view(s.shape) return eig to v } - public fun StructureND.symEigJacobi(maxIteration: Int, epsilon: Double): Pair { - checkSymmetric(tensor, epsilon) - - val size = this.dimension - val eigenvectors = zeros(this.shape) - val eigenvalues = zeros(this.shape.sliceArray(0 until size - 1)) - - var eigenvalueStart = 0 - var eigenvectorStart = 0 - for (matrix in tensor.matrixSequence()) { - val matrix2D = matrix.as2D() - val (d, v) = matrix2D.jacobiHelper(maxIteration, epsilon) - - for (i in 0 until matrix2D.rowNum) { - for (j in 0 until matrix2D.colNum) { - eigenvectors.mutableBuffer.array()[eigenvectorStart + i * matrix2D.rowNum + j] = v[i, j] - } - } - - for (i in 0 until matrix2D.rowNum) { - eigenvalues.mutableBuffer.array()[eigenvalueStart + i] = d[i] - } - - eigenvalueStart += this.shape.last() - eigenvectorStart += this.shape.last() * this.shape.last() - } - - return eigenvalues to eigenvectors - } - - private fun MutableStructure2D.jacobiHelper( - maxIteration: Int, - epsilon: Double - ): Pair, Structure2D> { - val n = this.shape[0] - val A_ = this.copy() - val V = eye(n) - val D = DoubleTensor(intArrayOf(n), (0 until this.rowNum).map { this[it, it] }.toDoubleArray()).as1D() - val B = DoubleTensor(intArrayOf(n), (0 until this.rowNum).map { this[it, it] }.toDoubleArray()).as1D() - val Z = zeros(intArrayOf(n)).as1D() - - // assume that buffered tensor is square matrix - operator fun BufferedTensor.get(i: Int, j: Int): Double { - return this.mutableBuffer.array()[bufferStart + i * this.shape[0] + j] - } - - operator fun BufferedTensor.set(i: Int, j: Int, value: Double) { - this.mutableBuffer.array()[bufferStart + i * this.shape[0] + j] = value - } - - fun maxOffDiagonal(matrix: BufferedTensor): Double { - var maxOffDiagonalElement = 0.0 - for (i in 0 until n - 1) { - for (j in i + 1 until n) { - maxOffDiagonalElement = max(maxOffDiagonalElement, abs(matrix[i, j])) - } - } - return maxOffDiagonalElement - } - - fun rotate(a: BufferedTensor, s: Double, tau: Double, i: Int, j: Int, k: Int, l: Int) { - val g = a[i, j] - val h = a[k, l] - a[i, j] = g - s * (h + g * tau) - a[k, l] = h + s * (g - h * tau) - } - - fun jacobiIteration( - a: BufferedTensor, - v: BufferedTensor, - d: MutableStructure1D, - z: MutableStructure1D, - ) { - for (ip in 0 until n - 1) { - for (iq in ip + 1 until n) { - val g = 100.0 * abs(a[ip, iq]) - - if (g <= epsilon * abs(d[ip]) && g <= epsilon * abs(d[iq])) { - a[ip, iq] = 0.0 - continue - } - - var h = d[iq] - d[ip] - val t = when { - g <= epsilon * abs(h) -> (a[ip, iq]) / h - else -> { - val theta = 0.5 * h / (a[ip, iq]) - val denominator = abs(theta) + sqrt(1.0 + theta * theta) - if (theta < 0.0) -1.0 / denominator else 1.0 / denominator - } - } - - val c = 1.0 / sqrt(1 + t * t) - val s = t * c - val tau = s / (1.0 + c) - h = t * a[ip, iq] - z[ip] -= h - z[iq] += h - d[ip] -= h - d[iq] += h - a[ip, iq] = 0.0 - - for (j in 0 until ip) { - rotate(a, s, tau, j, ip, j, iq) - } - for (j in (ip + 1) until iq) { - rotate(a, s, tau, ip, j, j, iq) - } - for (j in (iq + 1) until n) { - rotate(a, s, tau, ip, j, iq, j) - } - for (j in 0 until n) { - rotate(v, s, tau, j, ip, j, iq) - } - } - } - } - - fun updateDiagonal( - d: MutableStructure1D, - z: MutableStructure1D, - b: MutableStructure1D, - ) { - for (ip in 0 until d.size) { - b[ip] += z[ip] - d[ip] = b[ip] - z[ip] = 0.0 - } - } - - var sm = maxOffDiagonal(A_) - for (iteration in 0 until maxIteration) { - if (sm < epsilon) { - break - } - - jacobiIteration(A_, V, D, Z) - updateDiagonal(D, Z, B) - sm = maxOffDiagonal(A_) - } - - // TODO sort eigenvalues - return D to V.as2D() - } - /** * Computes the determinant of a square matrix input, or of each square matrix in a batched input * using LU factorization algorithm. @@ -1072,7 +863,7 @@ public open class DoubleTensorAlgebra : * with zero. * @return the determinant. */ - public fun StructureND.detLU(epsilon: Double = 1e-9): DoubleTensor { + public fun Tensor.detLU(epsilon: Double = 1e-9): DoubleTensor { checkSquareMatrix(tensor.shape) val luTensor = tensor.copy() val pivotsTensor = tensor.setUpPivots() @@ -1105,7 +896,7 @@ public open class DoubleTensorAlgebra : * @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 StructureND.invLU(epsilon: Double = 1e-9): DoubleTensor { + public fun Tensor.invLU(epsilon: Double = 1e-9): DoubleTensor { val (luTensor, pivotsTensor) = luFactor(epsilon) val invTensor = luTensor.zeroesLike() @@ -1130,15 +921,12 @@ public open class DoubleTensorAlgebra : * @param epsilon permissible error when comparing the determinant of a matrix with zero. * @return triple of `P`, `L` and `U` tensors. */ - public fun StructureND.lu(epsilon: Double = 1e-9): Triple { + public fun Tensor.lu(epsilon: Double = 1e-9): Triple { val (lu, pivots) = tensor.luFactor(epsilon) return luPivot(lu, pivots) } - override fun StructureND.lu(): Triple = lu(1e-9) + override fun Tensor.lu(): Triple = lu(1e-9) } -public val Double.Companion.tensorAlgebra: DoubleTensorAlgebra.Companion get() = DoubleTensorAlgebra -public val DoubleField.tensorAlgebra: DoubleTensorAlgebra.Companion get() = DoubleTensorAlgebra - 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 index e3d7c3d35..dd9f9c0c1 100644 --- 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 @@ -1,12 +1,11 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.core import space.kscience.kmath.structures.IntBuffer -import space.kscience.kmath.tensors.core.internal.array /** * Default [BufferedTensor] implementation for [Int] values @@ -15,7 +14,4 @@ public class IntTensor internal constructor( shape: IntArray, buffer: IntArray, offset: Int = 0 -) : BufferedTensor(shape, IntBuffer(buffer), offset){ - public fun asDouble() : DoubleTensor = - DoubleTensor(shape, mutableBuffer.array().map{ it.toDouble()}.toDoubleArray(), bufferStart) -} +) : BufferedTensor(shape, IntBuffer(buffer), offset) 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 deleted file mode 100644 index 19eefc2f8..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/TensorLinearStructure.kt +++ /dev/null @@ -1,74 +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 - -import space.kscience.kmath.nd.Strides -import kotlin.math.max - -/** - * 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() { - override val strides: IntArray - get() = stridesFromShape(shape) - - override fun index(offset: Int): IntArray = - indexFromOffset(offset, strides, shape.size) - - override val linearSize: Int - get() = shape.reduce(Int::times) - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other == null || this::class != other::class) return false - - other as TensorLinearStructure - - if (!shape.contentEquals(other.shape)) return false - - return true - } - - override fun hashCode(): Int { - return shape.contentHashCode() - } - - public companion object { - - public fun stridesFromShape(shape: IntArray): IntArray { - val nDim = shape.size - val res = IntArray(nDim) - if (nDim == 0) - return res - - var current = nDim - 1 - res[current] = 1 - - while (current > 0) { - res[current - 1] = max(1, shape[current]) * res[current] - current-- - } - return res - } - - public fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): IntArray { - val res = IntArray(nDim) - var current = offset - var strideIndex = 0 - - while (strideIndex < nDim) { - res[strideIndex] = (current / strides[strideIndex]) - current %= strides[strideIndex] - strideIndex++ - } - return res - } - } - -} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt new file mode 100644 index 000000000..817ed60d8 --- /dev/null +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt @@ -0,0 +1,57 @@ +/* + * 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 file. + */ + +package space.kscience.kmath.tensors.core.internal + +import space.kscience.kmath.nd.Strides +import kotlin.math.max + + +internal fun stridesFromShape(shape: IntArray): IntArray { + val nDim = shape.size + val res = IntArray(nDim) + if (nDim == 0) + return res + + var current = nDim - 1 + res[current] = 1 + + while (current > 0) { + res[current - 1] = max(1, shape[current]) * res[current] + current-- + } + return res +} + +internal fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): IntArray { + val res = IntArray(nDim) + var current = offset + var strideIndex = 0 + + while (strideIndex < nDim) { + res[strideIndex] = (current / strides[strideIndex]) + current %= strides[strideIndex] + strideIndex++ + } + 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. + */ +internal 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) + + override val linearSize: Int + get() = shape.reduce(Int::times) + +} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt index 9d37423e5..4b9c0c382 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.core.internal @@ -10,7 +10,7 @@ import kotlin.math.max internal fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTensor, linearSize: Int) { for (linearIndex in 0 until linearSize) { - val totalMultiIndex = resTensor.indices.index(linearIndex) + val totalMultiIndex = resTensor.linearStructure.index(linearIndex) val curMultiIndex = tensor.shape.copyOf() val offset = totalMultiIndex.size - curMultiIndex.size @@ -23,7 +23,7 @@ internal fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTenso } } - val curLinearIndex = tensor.indices.offset(curMultiIndex) + val curLinearIndex = tensor.linearStructure.offset(curMultiIndex) resTensor.mutableBuffer.array()[linearIndex] = tensor.mutableBuffer.array()[tensor.bufferStart + curLinearIndex] } @@ -112,7 +112,7 @@ internal fun broadcastOuterTensors(vararg tensors: DoubleTensor): List checkShapesCompatible(a: StructureND, b: StructureND) = +internal fun checkShapesCompatible(a: Tensor, b: Tensor) = check(a.shape contentEquals b.shape) { "Incompatible shapes ${a.shape.toList()} and ${b.shape.toList()} " } 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 aba6167ce..f3ac92872 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 @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.core.internal @@ -9,71 +9,50 @@ 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.asSequence import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.VirtualBuffer import space.kscience.kmath.tensors.core.BufferedTensor import space.kscience.kmath.tensors.core.DoubleTensor import space.kscience.kmath.tensors.core.DoubleTensorAlgebra import space.kscience.kmath.tensors.core.IntTensor import kotlin.math.abs import kotlin.math.min +import kotlin.math.sign import kotlin.math.sqrt -internal val BufferedTensor.vectors: VirtualBuffer> - get() { - val n = shape.size - val vectorOffset = shape[n - 1] - val vectorShape = intArrayOf(shape.last()) - - return VirtualBuffer(numElements / vectorOffset) { index -> - val offset = index * vectorOffset - BufferedTensor(vectorShape, mutableBuffer, bufferStart + offset) - } +internal fun BufferedTensor.vectorSequence(): Sequence> = sequence { + val n = shape.size + val vectorOffset = shape[n - 1] + val vectorShape = intArrayOf(shape.last()) + for (offset in 0 until numElements step vectorOffset) { + val vector = BufferedTensor(vectorShape, mutableBuffer, bufferStart + offset) + yield(vector) } +} - -internal fun BufferedTensor.vectorSequence(): Sequence> = vectors.asSequence() - -/** - * A random access alternative to [matrixSequence] - */ -internal val BufferedTensor.matrices: VirtualBuffer> - get() { - 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]) - - return VirtualBuffer(numElements / matrixOffset) { index -> - val offset = index * matrixOffset - BufferedTensor(matrixShape, mutableBuffer, bufferStart + offset) - } +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) { + val matrix = BufferedTensor(matrixShape, mutableBuffer, bufferStart + offset) + yield(matrix) } +} -internal fun BufferedTensor.matrixSequence(): Sequence> = matrices.asSequence() - -internal fun dotTo( - a: BufferedTensor, - b: BufferedTensor, - res: BufferedTensor, - l: Int, m: Int, n: Int, +internal fun dotHelper( + a: MutableStructure2D, + b: MutableStructure2D, + res: MutableStructure2D, + l: Int, m: Int, n: Int ) { - val aStart = a.bufferStart - val bStart = b.bufferStart - val resStart = res.bufferStart - - val aBuffer = a.mutableBuffer - val bBuffer = b.mutableBuffer - val resBuffer = res.mutableBuffer - for (i in 0 until l) { for (j in 0 until n) { var curr = 0.0 for (k in 0 until m) { - curr += aBuffer[aStart + i * m + k] * bBuffer[bStart + k * n + j] + curr += a[i, k] * b[k, j] } - resBuffer[resStart + i * n + j] = curr + res[i, j] = curr } } } @@ -81,7 +60,7 @@ internal fun dotTo( internal fun luHelper( lu: MutableStructure2D, pivots: MutableStructure1D, - epsilon: Double, + epsilon: Double ): Boolean { val m = lu.rowNum @@ -143,7 +122,7 @@ internal fun BufferedTensor.setUpPivots(): IntTensor { internal fun DoubleTensorAlgebra.computeLU( tensor: DoubleTensor, - epsilon: Double, + epsilon: Double ): Pair? { checkSquareMatrix(tensor.shape) @@ -160,7 +139,7 @@ internal fun DoubleTensorAlgebra.computeLU( internal fun pivInit( p: MutableStructure2D, pivot: MutableStructure1D, - n: Int, + n: Int ) { for (i in 0 until n) { p[i, pivot[i]] = 1.0 @@ -171,7 +150,7 @@ internal fun luPivotHelper( l: MutableStructure2D, u: MutableStructure2D, lu: MutableStructure2D, - n: Int, + n: Int ) { for (i in 0 until n) { for (j in 0 until n) { @@ -191,7 +170,7 @@ internal fun luPivotHelper( internal fun choleskyHelper( a: MutableStructure2D, l: MutableStructure2D, - n: Int, + n: Int ) { for (i in 0 until n) { for (j in 0 until i) { @@ -221,7 +200,7 @@ internal fun luMatrixDet(lu: MutableStructure2D, pivots: MutableStructur internal fun luMatrixInv( lu: MutableStructure2D, pivots: MutableStructure1D, - invMatrix: MutableStructure2D, + invMatrix: MutableStructure2D ) { val m = lu.shape[0] @@ -248,7 +227,7 @@ internal fun luMatrixInv( internal fun DoubleTensorAlgebra.qrHelper( matrix: DoubleTensor, q: DoubleTensor, - r: MutableStructure2D, + r: MutableStructure2D ) { checkSquareMatrix(matrix.shape) val n = matrix.shape[0] @@ -301,11 +280,12 @@ internal fun DoubleTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10) internal fun DoubleTensorAlgebra.svdHelper( matrix: DoubleTensor, - USV: Triple, BufferedTensor, BufferedTensor>, - m: Int, n: Int, epsilon: Double, + USV: Pair, Pair, BufferedTensor>>, + m: Int, n: Int, epsilon: Double ) { val res = ArrayList>(0) - val (matrixU, matrixS, matrixV) = USV + val (matrixU, SV) = USV + val (matrixS, matrixV) = SV for (k in 0 until min(n, m)) { var a = matrix.copy() @@ -349,3 +329,14 @@ internal fun DoubleTensorAlgebra.svdHelper( matrixV.mutableBuffer.array()[matrixV.bufferStart + i] = vBuffer[i] } } + +internal fun cleanSymHelper(matrix: MutableStructure2D, n: Int) { + 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 + } + } +} 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 a5cdb2f47..29aa02931 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 @@ -1,18 +1,16 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.core.internal import space.kscience.kmath.nd.MutableBufferND -import space.kscience.kmath.nd.StructureND 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.TensorLinearStructure internal fun BufferedTensor.asTensor(): IntTensor = IntTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) @@ -20,24 +18,21 @@ internal fun BufferedTensor.asTensor(): IntTensor = internal fun BufferedTensor.asTensor(): DoubleTensor = DoubleTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) -internal fun StructureND.copyToBufferedTensor(): BufferedTensor = +internal fun Tensor.copyToBufferedTensor(): BufferedTensor = BufferedTensor( this.shape, - TensorLinearStructure(this.shape).asSequence().map(this::get).toMutableList().asMutableBuffer(), 0 + TensorLinearStructure(this.shape).indices().map(this::get).toMutableList().asMutableBuffer(), 0 ) -internal fun StructureND.toBufferedTensor(): BufferedTensor = when (this) { +internal fun Tensor.toBufferedTensor(): BufferedTensor = when (this) { is BufferedTensor -> this - is MutableBufferND -> if (this.indices == TensorLinearStructure(this.shape)) { - BufferedTensor(this.shape, this.buffer, 0) - } else { - this.copyToBufferedTensor() - } + is MutableBufferND -> if (this.strides.strides contentEquals TensorLinearStructure(this.shape).strides) + BufferedTensor(this.shape, this.mutableBuffer, 0) else this.copyToBufferedTensor() else -> this.copyToBufferedTensor() } @PublishedApi -internal val StructureND.tensor: DoubleTensor +internal val Tensor.tensor: DoubleTensor get() = when (this) { is DoubleTensor -> this else -> this.toBufferedTensor().asTensor() diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt index 85cc91b1d..6088c32e4 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt @@ -1,12 +1,11 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.core.internal import space.kscience.kmath.nd.as1D -import space.kscience.kmath.operations.toMutableList import space.kscience.kmath.samplers.GaussianSampler import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.structures.* @@ -85,7 +84,7 @@ internal fun format(value: Double, digits: Int = 4): String = buildString { internal fun DoubleTensor.toPrettyString(): String = buildString { var offset = 0 val shape = this@toPrettyString.shape - val linearStructure = this@toPrettyString.indices + val linearStructure = this@toPrettyString.linearStructure val vectorSize = shape.last() append("DoubleTensor(\n") var charOffset = 3 diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt deleted file mode 100644 index d8e8df31e..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorAlgebraExtensions.kt +++ /dev/null @@ -1,19 +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. - */ - -@file:OptIn(PerformancePitfall::class) - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.Shape -import kotlin.jvm.JvmName - -@JvmName("varArgOne") -public fun DoubleTensorAlgebra.one(vararg shape: Int): DoubleTensor = ones(intArrayOf(*shape)) -public fun DoubleTensorAlgebra.one(shape: Shape): DoubleTensor = ones(shape) -@JvmName("varArgZero") -public fun DoubleTensorAlgebra.zero(vararg shape: Int): DoubleTensor = zeros(intArrayOf(*shape)) -public fun DoubleTensorAlgebra.zero(shape: Shape): DoubleTensor = zeros(shape) \ 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 5dc8114dd..021ca539c 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 @@ -1,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.core @@ -19,19 +19,18 @@ public fun Tensor.toDoubleTensor(): DoubleTensor = this.tensor public fun Tensor.toIntTensor(): IntTensor = this.tensor /** - * Returns a copy-protected [DoubleArray] of tensor elements + * Returns [DoubleArray] of tensor elements */ -public fun DoubleTensor.copyArray(): DoubleArray { - //TODO use ArrayCopy +public fun DoubleTensor.toDoubleArray(): DoubleArray { return DoubleArray(numElements) { i -> mutableBuffer[bufferStart + i] } } /** - * Returns a copy-protected [IntArray] of tensor elements + * Returns [IntArray] of tensor elements */ -public fun IntTensor.copyArray(): IntArray { +public fun IntTensor.toIntArray(): IntArray { return IntArray(numElements) { i -> mutableBuffer[bufferStart + i] } 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 6788ae792..1171b5217 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,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.core 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 1e21379b4..ba8182da2 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,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.core 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 e025d4b71..c50c99b54 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,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.core 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 d808637c7..2686df19e 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,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.core 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 205ae2fee..2aee03b82 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,6 +1,6 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.tensors.core @@ -107,8 +107,6 @@ internal class TestDoubleTensorAlgebra { val tensor11 = fromArray(intArrayOf(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) val tensor2 = fromArray(intArrayOf(3), doubleArrayOf(10.0, 20.0, 30.0)) val tensor3 = fromArray(intArrayOf(1, 1, 3), doubleArrayOf(-1.0, -2.0, -3.0)) - val tensor4 = fromArray(intArrayOf(2, 3, 3), (1..18).map { it.toDouble() }.toDoubleArray()) - val tensor5 = fromArray(intArrayOf(2, 3, 3), (1..18).map { 1 + it.toDouble() }.toDoubleArray()) val res12 = tensor1.dot(tensor2) assertTrue(res12.mutableBuffer.array() contentEquals doubleArrayOf(140.0, 320.0)) @@ -125,13 +123,6 @@ 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)) - - val res45 = tensor4.dot(tensor5) - assertTrue(res45.mutableBuffer.array() contentEquals doubleArrayOf( - 36.0, 42.0, 48.0, 81.0, 96.0, 111.0, 126.0, 150.0, 174.0, - 468.0, 501.0, 534.0, 594.0, 636.0, 678.0, 720.0, 771.0, 822.0 - )) - assertTrue(res45.shape contentEquals intArrayOf(2, 3, 3)) } @Test diff --git a/kmath-units/build.gradle.kts b/kmath-units/build.gradle.kts new file mode 100644 index 000000000..11b0d0300 --- /dev/null +++ b/kmath-units/build.gradle.kts @@ -0,0 +1,15 @@ +import ru.mipt.npm.gradle.Maturity + +plugins { + id("ru.mipt.npm.gradle.mpp") +} + +kotlin.sourceSets.commonMain { + dependencies { + api(project(":kmath-core")) + } +} + +readme { + maturity = Maturity.PROTOTYPE +} diff --git a/kmath-units/src/commonMain/kotlin/space/kscience/kmath/units/units.kt b/kmath-units/src/commonMain/kotlin/space/kscience/kmath/units/units.kt new file mode 100644 index 000000000..a414a9fe2 --- /dev/null +++ b/kmath-units/src/commonMain/kotlin/space/kscience/kmath/units/units.kt @@ -0,0 +1,276 @@ +package space.kscience.kmath.units + +import space.kscience.kmath.operations.* +import kotlin.jvm.JvmName +import kotlin.math.PI +import kotlin.math.pow + +/** + * Represents base units of International System of Units. + */ +public enum class BaseUnits { + /** + * The base unit of time. + */ + SECOND, + + /** + * The base unit of length. + */ + METER, + + /** + * The base unit of mass. + */ + KILOGRAM, + + /** + * The base unit of electric current. + */ + AMPERE, + + /** + * The base unit of thermodynamic temperature. + */ + KELVIN, + + /** + * The base unit of amount of substance. + */ + MOLE, + + /** + * The base unit of luminous intensity. + */ + CANDELA; +} + +/** + * Represents a unit. + * + * @property chain chain of multipliers consisting of [BaseUnits] unit and its power. + * @property multiplier a scalar to multiply an element applied to this unit. + */ +public data class Measure internal constructor( + val chain: Map = emptyMap(), + val multiplier: Double = 1.0, +) + +internal fun Measure(vararg chain: Pair, multiplier: Double = 1.0): Measure = + Measure(mapOf(*chain), multiplier) + +public data class Measurement(val measure: Measure, val value: T) + +public object MeasureAlgebra : Algebra { + public const val MULTIPLY_OPERATION: String = "*" + public const val DIVIDE_OPERATION: String = "/" + + public fun multiply(a: Measure, b: Measure): Measure { + val newChain = mutableMapOf() + + a.chain.forEach { (k, v) -> + val cur = newChain[k] + if (cur != null) newChain[k] = cur + v + else newChain[k] = v + } + + b.chain.forEach { (k, v) -> + val cur = newChain[k] + if (cur != null) newChain[k] = cur + v + else newChain[k] = v + } + + return Measure(newChain, a.multiplier * b.multiplier) + } + + public fun divide(a: Measure, b: Measure): Measure = + multiply(a, b.copy(chain = b.chain.mapValues { (_, v) -> -v })) + + public operator fun Measure.times(b: Measure): Measure = multiply(this, b) + public operator fun Measure.div(b: Measure): Measure = divide(this, b) + + override fun binaryOperationFunction(operation: String): (left: Measure, right: Measure) -> Measure = + when (operation) { + MULTIPLY_OPERATION -> ::multiply + DIVIDE_OPERATION -> ::divide + else -> super.binaryOperationFunction(operation) + } +} + +/** + * A measure for dimensionless quantities with multiplier `1.0`. + */ +public val pure: Measure = Measure() + +/** + * A measure for [BaseUnits.METER] of power `1.0` with multiplier `1.0`. + */ +public val m: Measure = Measure(BaseUnits.METER to 1) + +/** + * A measure for [BaseUnits.KILOGRAM] of power `1.0` with multiplier `1.0`. + */ +public val kg: Measure = Measure(BaseUnits.KILOGRAM to 1) + +/** + * A measure for [BaseUnits.SECOND] of power `1.0` with multiplier `1.0`. + */ +@get:JvmName("s-seconds") +public val s: Measure = Measure(BaseUnits.SECOND to 1) + +/** + * A measure for [BaseUnits.AMPERE] of power `1.0` with multiplier `1.0`. + */ +public val A: Measure = Measure(BaseUnits.AMPERE to 1) + +/** + * A measure for [BaseUnits.KELVIN] of power `1.0` with multiplier `1.0`. + */ +public val K: Measure = Measure(BaseUnits.KELVIN to 1) + +/** + * A measure for [BaseUnits.MOLE] of power `1.0` with multiplier `1.0`. + */ +public val mol: Measure = Measure(BaseUnits.MOLE to 1) + +/** + * A measure for [BaseUnits.CANDELA] of power `1.0` with multiplier `1.0`. + */ +public val cd: Measure = Measure(BaseUnits.CANDELA to 1) + +public val rad: Measure = pure +public val sr: Measure = pure +public val degC: Measure = K +public val Hz: Measure = MeasureAlgebra { pure / s } +public val N: Measure = MeasureAlgebra { kg * m * (pure / (s * s)) } +public val J: Measure = MeasureAlgebra { N * m } +public val W: Measure = MeasureAlgebra { J / s } +public val Pa: Measure = MeasureAlgebra { N / (m * m) } +public val lm: Measure = MeasureAlgebra { cd * sr } +public val lx: Measure = MeasureAlgebra { lm / (m * m) } +public val C: Measure = MeasureAlgebra { A * s } +public val V: Measure = MeasureAlgebra { J / C } +public val Ohm: Measure = MeasureAlgebra { V / A } +public val F: Measure = MeasureAlgebra { C / V } +public val Wb: Measure = MeasureAlgebra { kg * m * m * (pure / (s * s)) * (pure / A) } + +@get:JvmName("T-tesla") +public val T: Measure = MeasureAlgebra { Wb / (m * m) } + +@get:JvmName("H-henry") +public val H: Measure = MeasureAlgebra { kg * m * m * (pure / (s * s)) * (pure / (A * A)) } + +public val S: Measure = MeasureAlgebra { pure / Ohm } +public val Bq: Measure = MeasureAlgebra { pure / s } +public val Gy: Measure = MeasureAlgebra { J / kg } +public val Sv: Measure = MeasureAlgebra { J / kg } +public val kat: Measure = MeasureAlgebra { mol / s } + +public val g: Measure = Measure(BaseUnits.KILOGRAM to 1, multiplier = 0.001) +public val min: Measure = Measure(BaseUnits.SECOND to 1, multiplier = 60.0) +public val h: Measure = Measure(BaseUnits.SECOND to 1, multiplier = 3600.0) +public val d: Measure = Measure(BaseUnits.SECOND to 1, multiplier = 86_400.0) +public val au: Measure = Measure(BaseUnits.METER to 1, multiplier = 149_597_870_700.0) +public val deg: Measure = Measure(multiplier = PI / 180.0) +public val arcMin: Measure = Measure(multiplier = PI / 10_800.0) +public val arcS: Measure = Measure(multiplier = PI / 648_000.0) +public val ha: Measure = Measure(BaseUnits.METER to 2, multiplier = 10000.0) +public val l: Measure = Measure(BaseUnits.METER to 3, multiplier = 0.001) +public val t: Measure = Measure(BaseUnits.KILOGRAM to 1, multiplier = 1000.0) +public val Da: Measure = Measure(BaseUnits.KILOGRAM to 1, multiplier = 1.660_539_040_202_020 * 10e-27) +public val eV: Measure = J.copy(multiplier = 1.602_176_634 * 10e-19) + +public fun Y(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e24) +public fun Z(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e21) +public fun E(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e18) +public fun P(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e15) +public fun T(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e12) +public fun G(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e9) +public fun M(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e6) +public fun k(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e3) +public fun h(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e2) +public fun da(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e1) + +public fun y(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-24) +public fun z(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-21) +public fun a(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-18) +public fun f(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-15) +public fun p(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-12) +public fun n(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-9) +public fun u(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-6) +public fun m(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-3) +public fun c(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-2) +public fun d(measure: Measure): Measure = measure.copy(multiplier = measure.multiplier * 1e-1) + +public infix fun Measure.pow(power: Int): Measure = + copy(chain = chain.mapValues { (_, v) -> IntRing.power(v, power.toUInt()) }, multiplier = multiplier.pow(power)) + +public open class MeasurementAlgebra(public open val algebra: Algebra) : Algebra> { + public operator fun T.times(m: Measure): Measurement = Measurement(m, this) + public operator fun Measurement.times(m: Measure): Measurement = + copy(measure = MeasureAlgebra { measure * m }) + + public override fun bindSymbol(value: String): Measurement = algebra.bindSymbol(value) * pure +} + +public fun Algebra.measurement(): MeasurementAlgebra = MeasurementAlgebra(this) + +public open class MeasurementSpace(public override val algebra: A) : MeasurementAlgebra(algebra), + Group>, ScaleOperations> where A : Group, A : ScaleOperations { + public override val zero: Measurement + get() = Measurement(pure, algebra.zero) + + public override fun add(a: Measurement, b: Measurement): Measurement { + require(a.measure.chain == b.measure.chain) { + "The units are incompatible. The chains are ${a.measure.chain} and ${b.measure.chain}" + } + + return a.copy(value = algebra { a.value * a.measure.multiplier + b.value * b.measure.multiplier }) + } + + public override fun scale(a: Measurement, value: Double): Measurement = + Measurement(a.measure, algebra { a.value * value }) + + override fun Measurement.unaryMinus(): Measurement = copy(value = algebra { -value }) +} + +public fun A.measurement(): MeasurementSpace where A : Group, A : ScaleOperations = MeasurementSpace(this) + +public open class MeasurementRing(override val algebra: A) : MeasurementSpace(algebra), + Ring> where A : ScaleOperations, A : Ring { + public override val one: Measurement + get() = Measurement(pure, algebra.one) + + public override fun multiply(a: Measurement, b: Measurement): Measurement = + Measurement(MeasureAlgebra { a.measure * b.measure }, algebra { a.value * b.value }) +} + +public fun A.measurement(): MeasurementRing where A : Ring, A : ScaleOperations = MeasurementRing(this) + +public open class MeasurementField(public override val algebra: Field) : MeasurementRing>(algebra), + Field> { + public override fun divide(a: Measurement, b: Measurement): Measurement = + Measurement(MeasureAlgebra { a.measure / b.measure }, algebra { a.value / b.value }) +} + +public fun Field.measurement(): MeasurementField = MeasurementField(this) + +public open class MeasurementExtendedField(public override val algebra: ExtendedField) : + MeasurementField(algebra), + ExtendedField> { + public override fun number(value: Number): Measurement = Measurement(pure, algebra.number(value)) + public override fun sin(arg: Measurement): Measurement = Measurement(arg.measure, algebra.sin(arg.value)) + public override fun cos(arg: Measurement): Measurement = Measurement(arg.measure, algebra.cos(arg.value)) + public override fun tan(arg: Measurement): Measurement = Measurement(arg.measure, algebra.tan(arg.value)) + public override fun asin(arg: Measurement): Measurement = Measurement(arg.measure, algebra.asin(arg.value)) + public override fun acos(arg: Measurement): Measurement = Measurement(arg.measure, algebra.acos(arg.value)) + public override fun atan(arg: Measurement): Measurement = Measurement(arg.measure, algebra.atan(arg.value)) + + public override fun power(arg: Measurement, pow: Number): Measurement = + (this as Field>).power(arg, pow.toInt()) + + public override fun exp(arg: Measurement): Measurement = Measurement(arg.measure, algebra.exp(arg.value)) + public override fun ln(arg: Measurement): Measurement = Measurement(arg.measure, algebra.ln(arg.value)) +} + +public fun ExtendedField.measurement(): MeasurementExtendedField = MeasurementExtendedField(this) diff --git a/kmath-viktor/README.md b/kmath-viktor/README.md deleted file mode 100644 index 229d4dcd4..000000000 --- a/kmath-viktor/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Module kmath-viktor - -Binding for https://github.com/JetBrains-Research/viktor - -## Usage - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-viktor:0.3.0-dev-20`. - -**Gradle Groovy:** -```groovy -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-viktor:0.3.0-dev-20' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-viktor:0.3.0-dev-20") -} -``` diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt index 4eedcb5ee..caebd9783 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt @@ -1,17 +1,15 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.viktor import org.jetbrains.bio.viktor.F64FlatArray -import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.MutableBuffer @Suppress("NOTHING_TO_INLINE", "OVERRIDE_BY_INLINE") -@JvmInline -public value class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuffer { +public class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuffer { override val size: Int get() = flatArray.size @@ -23,6 +21,4 @@ public value class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuf override fun copy(): MutableBuffer = ViktorBuffer(flatArray.copy().flatten()) override operator fun iterator(): Iterator = flatArray.data.iterator() - - override fun toString(): String = Buffer.toString(this) } diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt deleted file mode 100644 index 1d4d6cebd..000000000 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorFieldOpsND.kt +++ /dev/null @@ -1,132 +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. - */ - -@file:OptIn(PerformancePitfall::class) - -package space.kscience.kmath.viktor - -import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.ExtendedFieldOps -import space.kscience.kmath.operations.NumbersAddOps -import space.kscience.kmath.operations.PowerOperations - -@OptIn(UnstableKMathAPI::class, PerformancePitfall::class) -@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public open class ViktorFieldOpsND : - FieldOpsND, - ExtendedFieldOps>, - PowerOperations> { - - public val StructureND.f64Buffer: F64Array - get() = when (this) { - is ViktorStructureND -> this.f64Buffer - else -> structureND(shape) { this@f64Buffer[it] }.f64Buffer - } - - override val elementAlgebra: DoubleField get() = DoubleField - - override fun structureND(shape: IntArray, initializer: DoubleField.(IntArray) -> Double): ViktorStructureND = - F64Array(*shape).apply { - DefaultStrides(shape).asSequence().forEach { index -> - set(value = DoubleField.initializer(index), indices = index) - } - }.asStructure() - - override fun StructureND.unaryMinus(): StructureND = -1 * this - - @PerformancePitfall - override fun StructureND.map(transform: DoubleField.(Double) -> Double): ViktorStructureND = - F64Array(*shape).apply { - DefaultStrides(shape).asSequence().forEach { index -> - set(value = DoubleField.transform(this@map[index]), indices = index) - } - }.asStructure() - - @PerformancePitfall - override fun StructureND.mapIndexed( - transform: DoubleField.(index: IntArray, Double) -> Double, - ): ViktorStructureND = F64Array(*shape).apply { - DefaultStrides(shape).asSequence().forEach { index -> - set(value = DoubleField.transform(index, this@mapIndexed[index]), indices = index) - } - }.asStructure() - - @PerformancePitfall - override fun zip( - left: StructureND, - right: StructureND, - transform: DoubleField.(Double, Double) -> Double, - ): ViktorStructureND { - require(left.shape.contentEquals(right.shape)) - return F64Array(*left.shape).apply { - DefaultStrides(left.shape).asSequence().forEach { index -> - set(value = DoubleField.transform(left[index], right[index]), indices = index) - } - }.asStructure() - } - - override fun add(left: StructureND, right: StructureND): ViktorStructureND = - (left.f64Buffer + right.f64Buffer).asStructure() - - override fun scale(a: StructureND, value: Double): ViktorStructureND = - (a.f64Buffer * value).asStructure() - - override fun StructureND.plus(arg: StructureND): ViktorStructureND = - (f64Buffer + arg.f64Buffer).asStructure() - - override fun StructureND.minus(arg: StructureND): ViktorStructureND = - (f64Buffer - arg.f64Buffer).asStructure() - - override fun StructureND.times(k: Number): ViktorStructureND = - (f64Buffer * k.toDouble()).asStructure() - - override fun StructureND.plus(arg: Double): ViktorStructureND = - (f64Buffer.plus(arg)).asStructure() - - override fun sin(arg: StructureND): ViktorStructureND = arg.map { sin(it) } - override fun cos(arg: StructureND): ViktorStructureND = arg.map { cos(it) } - override fun tan(arg: StructureND): ViktorStructureND = arg.map { tan(it) } - override fun asin(arg: StructureND): ViktorStructureND = arg.map { asin(it) } - override fun acos(arg: StructureND): ViktorStructureND = arg.map { acos(it) } - override fun atan(arg: StructureND): ViktorStructureND = arg.map { atan(it) } - - override fun power(arg: StructureND, pow: Number): ViktorStructureND = arg.map { it.pow(pow) } - - override fun exp(arg: StructureND): ViktorStructureND = arg.f64Buffer.exp().asStructure() - - override fun ln(arg: StructureND): ViktorStructureND = arg.f64Buffer.log().asStructure() - - override fun sinh(arg: StructureND): ViktorStructureND = arg.map { sinh(it) } - - override fun cosh(arg: StructureND): ViktorStructureND = arg.map { cosh(it) } - - override fun asinh(arg: StructureND): ViktorStructureND = arg.map { asinh(it) } - - override fun acosh(arg: StructureND): ViktorStructureND = arg.map { acosh(it) } - - override fun atanh(arg: StructureND): ViktorStructureND = arg.map { atanh(it) } - - public companion object : ViktorFieldOpsND() -} - -public val DoubleField.viktorAlgebra: ViktorFieldOpsND get() = ViktorFieldOpsND - -public open class ViktorFieldND( - override val shape: Shape, -) : ViktorFieldOpsND(), FieldND, NumbersAddOps> { - override val zero: ViktorStructureND by lazy { F64Array.full(init = 0.0, shape = shape).asStructure() } - override val one: ViktorStructureND by lazy { F64Array.full(init = 1.0, shape = shape).asStructure() } - - override fun number(value: Number): ViktorStructureND = - F64Array.full(init = value.toDouble(), shape = shape).asStructure() -} - -public fun DoubleField.viktorAlgebra(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape) - -public fun ViktorFieldND(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape) \ No newline at end of file diff --git a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt index 25ca3a10e..682123ddd 100644 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt +++ b/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt @@ -1,14 +1,18 @@ /* * 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. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. */ package space.kscience.kmath.viktor import org.jetbrains.bio.viktor.F64Array import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.DefaultStrides -import space.kscience.kmath.nd.MutableStructureND +import space.kscience.kmath.misc.UnstableKMathAPI +import space.kscience.kmath.nd.* +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.operations.NumbersAddOperations +import space.kscience.kmath.operations.ScaleOperations @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public class ViktorStructureND(public val f64Buffer: F64Array) : MutableStructureND { @@ -22,9 +26,101 @@ public class ViktorStructureND(public val f64Buffer: F64Array) : MutableStructur @PerformancePitfall override fun elements(): Sequence> = - DefaultStrides(shape).asSequence().map { it to get(it) } + DefaultStrides(shape).indices().map { it to get(it) } } public fun F64Array.asStructure(): ViktorStructureND = ViktorStructureND(this) +@OptIn(UnstableKMathAPI::class) +@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +public class ViktorFieldND(override val shape: IntArray) : FieldND, + NumbersAddOperations>, ExtendedField>, + ScaleOperations> { + public val StructureND.f64Buffer: F64Array + get() = when { + !shape.contentEquals(this@ViktorFieldND.shape) -> throw ShapeMismatchException( + this@ViktorFieldND.shape, + shape + ) + this is ViktorStructureND && this.f64Buffer.shape.contentEquals(this@ViktorFieldND.shape) -> this.f64Buffer + else -> produce { this@f64Buffer[it] }.f64Buffer + } + + override val zero: ViktorStructureND by lazy { F64Array.full(init = 0.0, shape = shape).asStructure() } + override val one: ViktorStructureND by lazy { F64Array.full(init = 1.0, shape = shape).asStructure() } + + private val strides: Strides = DefaultStrides(shape) + + override val elementContext: DoubleField get() = DoubleField + + override fun produce(initializer: DoubleField.(IntArray) -> Double): ViktorStructureND = + F64Array(*shape).apply { + this@ViktorFieldND.strides.indices().forEach { index -> + set(value = DoubleField.initializer(index), indices = index) + } + }.asStructure() + + override fun StructureND.unaryMinus(): StructureND = -1 * this + + override fun StructureND.map(transform: DoubleField.(Double) -> Double): ViktorStructureND = + F64Array(*this@ViktorFieldND.shape).apply { + this@ViktorFieldND.strides.indices().forEach { index -> + set(value = DoubleField.transform(this@map[index]), indices = index) + } + }.asStructure() + + override fun StructureND.mapIndexed( + transform: DoubleField.(index: IntArray, Double) -> Double, + ): ViktorStructureND = F64Array(*this@ViktorFieldND.shape).apply { + this@ViktorFieldND.strides.indices().forEach { index -> + set(value = DoubleField.transform(index, this@mapIndexed[index]), indices = index) + } + }.asStructure() + + override fun combine( + a: StructureND, + b: StructureND, + transform: DoubleField.(Double, Double) -> Double, + ): ViktorStructureND = F64Array(*shape).apply { + this@ViktorFieldND.strides.indices().forEach { index -> + set(value = DoubleField.transform(a[index], b[index]), indices = index) + } + }.asStructure() + + override fun add(a: StructureND, b: StructureND): ViktorStructureND = + (a.f64Buffer + b.f64Buffer).asStructure() + + override fun scale(a: StructureND, value: Double): ViktorStructureND = + (a.f64Buffer * value).asStructure() + + override inline fun StructureND.plus(b: StructureND): ViktorStructureND = + (f64Buffer + b.f64Buffer).asStructure() + + override inline fun StructureND.minus(b: StructureND): ViktorStructureND = + (f64Buffer - b.f64Buffer).asStructure() + + override inline fun StructureND.times(k: Number): ViktorStructureND = + (f64Buffer * k.toDouble()).asStructure() + + override inline fun StructureND.plus(arg: Double): ViktorStructureND = + (f64Buffer.plus(arg)).asStructure() + + override fun number(value: Number): ViktorStructureND = + F64Array.full(init = value.toDouble(), shape = shape).asStructure() + + override fun sin(arg: StructureND): ViktorStructureND = arg.map { sin(it) } + override fun cos(arg: StructureND): ViktorStructureND = arg.map { cos(it) } + override fun tan(arg: StructureND): ViktorStructureND = arg.map { tan(it) } + override fun asin(arg: StructureND): ViktorStructureND = arg.map { asin(it) } + override fun acos(arg: StructureND): ViktorStructureND = arg.map { acos(it) } + override fun atan(arg: StructureND): ViktorStructureND = arg.map { atan(it) } + + override fun power(arg: StructureND, pow: Number): ViktorStructureND = arg.map { it.pow(pow) } + + override fun exp(arg: StructureND): ViktorStructureND = arg.f64Buffer.exp().asStructure() + + override fun ln(arg: StructureND): ViktorStructureND = arg.f64Buffer.log().asStructure() +} + +public fun ViktorNDField(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape) diff --git a/license/COPYRIGHT.txt b/license/COPYRIGHT.txt deleted file mode 100644 index 7bf2faffd..000000000 --- a/license/COPYRIGHT.txt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ \ No newline at end of file diff --git a/license/COPYRIGHT_HEADER.txt b/license/COPYRIGHT_HEADER.txt deleted file mode 100644 index 3e7d28489..000000000 --- a/license/COPYRIGHT_HEADER.txt +++ /dev/null @@ -1,4 +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. - */ \ No newline at end of file diff --git a/license/LICENSE.txt b/license/LICENSE.txt deleted file mode 100644 index d64569567..000000000 --- a/license/LICENSE.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/license/README.md b/license/README.md deleted file mode 100644 index 376321684..000000000 --- a/license/README.md +++ /dev/null @@ -1,53 +0,0 @@ -The Apache 2 license (given in full in LICENSE.txt) applies to all code in this repository, which is copyright by the -contributors of KMath. The following sections of the repository contain third-party code, to which different licenses -may apply: - -## KMath Libraries - -The following modules contain third-party code and are incorporated into the KMath Libraries: - -- Path: kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt - - License: Apache 2 ([cm](third_party/cm_license.txt)) - - Origin: Derived from Apache Commons Math, (c) 2001-2020 The Apache Software Foundation -- Path: kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt - - License: Apache 2 ([cm](third_party/cm_license.txt)) - - Origin: Derived from Apache Commons Math, (c) 2001-2020 The Apache Software Foundation -- Path: kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LoessInterpolator.kt - - License: Apache 2 ([cm](third_party/cm_license.txt)) - - Origin: Derived from Apache Commons Math, (c) 2001-2020 The Apache Software Foundation -- Path: kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt - - License: Apache 2 ([cm](third_party/cm_license.txt)) - - Origin: Derived from Apache Commons Math, (c) 2001-2020 The Apache Software Foundation -- Path: kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt - - License: Apache 2 ([numky](third_party/numky_license.txt)) - - Origin: Initial implementation was taken from Numky -- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt - - License: Apache 2 ([cm](third_party/crng_license.txt)) - - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation -- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt - - License: Apache 2 ([cm](third_party/crng_license.txt)) - - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation -- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt - - License: Apache 2 ([cm](third_party/crng_license.txt)) - - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation -- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt - - License: Apache 2 ([cm](third_party/crng_license.txt)) - - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation -- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt - - License: Apache 2 ([cm](third_party/crng_license.txt)) - - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation -- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt - - License: Apache 2 ([cm](third_party/crng_license.txt)) - - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation -- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt - - License: Apache 2 ([cm](third_party/crng_license.txt)) - - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation -- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt - - License: Apache 2 ([cm](third_party/crng_license.txt)) - - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation -- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt - - License: Apache 2 ([cm](third_party/crng_license.txt)) - - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation -- Path: kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt - - License: Apache 2 ([cm](third_party/crng_license.txt)) - - Origin: Derived from Apache Commons RNG, (c) 2001-2020 The Apache Software Foundation diff --git a/license/third_party/cm_license.txt b/license/third_party/cm_license.txt deleted file mode 100644 index 6172c3fb2..000000000 --- a/license/third_party/cm_license.txt +++ /dev/null @@ -1,457 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - -Apache Commons Math includes the following code provided to the ASF under the -Apache License 2.0: - - - The inverse error function implementation in the Erf class is based on CUDA - code developed by Mike Giles, Oxford-Man Institute of Quantitative Finance, - and published in GPU Computing Gems, volume 2, 2010 (grant received on - March 23th 2013) - - The LinearConstraint, LinearObjectiveFunction, LinearOptimizer, - RelationShip, SimplexSolver and SimplexTableau classes in package - org.apache.commons.math3.optimization.linear include software developed by - Benjamin McCann (http://www.benmccann.com) and distributed with - the following copyright: Copyright 2009 Google Inc. (grant received on - March 16th 2009) - - The class "org.apache.commons.math3.exception.util.LocalizedFormatsTest" which - is an adapted version of "OrekitMessagesTest" test class for the Orekit library - - The "org.apache.commons.math3.analysis.interpolation.HermiteInterpolator" - has been imported from the Orekit space flight dynamics library. - -=============================================================================== - - - -APACHE COMMONS MATH DERIVATIVE WORKS: - -The Apache commons-math library includes a number of subcomponents -whose implementation is derived from original sources written -in C or Fortran. License terms of the original sources -are reproduced below. - -=============================================================================== -For the lmder, lmpar and qrsolv Fortran routine from minpack and translated in -the LevenbergMarquardtOptimizer class in package -org.apache.commons.math3.optimization.general -Original source copyright and license statement: - -Minpack Copyright Notice (1999) University of Chicago. All rights reserved - -Redistribution and use in source and binary forms, with or -without modification, are permitted provided that the -following conditions are met: - -1. Redistributions of source code must retain the above -copyright notice, this list of conditions and the following -disclaimer. - -2. Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following -disclaimer in the documentation and/or other materials -provided with the distribution. - -3. The end-user documentation included with the -redistribution, if any, must include the following -acknowledgment: - - "This product includes software developed by the - University of Chicago, as Operator of Argonne National - Laboratory. - -Alternately, this acknowledgment may appear in the software -itself, if and wherever such third-party acknowledgments -normally appear. - -4. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" -WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE -UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND -THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE -OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY -OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR -USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF -THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) -DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION -UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL -BE CORRECTED. - -5. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT -HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF -ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, -INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF -ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF -PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER -SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT -(INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE, -EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE -POSSIBILITY OF SUCH LOSS OR DAMAGES. -=============================================================================== - -Copyright and license statement for the odex Fortran routine developed by -E. Hairer and G. Wanner and translated in GraggBulirschStoerIntegrator class -in package org.apache.commons.math3.ode.nonstiff: - - -Copyright (c) 2004, Ernst Hairer - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -- Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -=============================================================================== - -Copyright and license statement for the original Mersenne twister C -routines translated in MersenneTwister class in package -org.apache.commons.math3.random: - - Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. The names of its contributors may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=============================================================================== - -The initial code for shuffling an array (originally in class -"org.apache.commons.math3.random.RandomDataGenerator", now replaced by -a method in class "org.apache.commons.math3.util.MathArrays") was -inspired from the algorithm description provided in -"Algorithms", by Ian Craw and John Pulham (University of Aberdeen 1999). -The textbook (containing a proof that the shuffle is uniformly random) is -available here: - http://citeseerx.ist.psu.edu/viewdoc/download;?doi=10.1.1.173.1898&rep=rep1&type=pdf - -=============================================================================== -License statement for the direction numbers in the resource files for Sobol sequences. - ------------------------------------------------------------------------------ -Licence pertaining to sobol.cc and the accompanying sets of direction numbers - ------------------------------------------------------------------------------ -Copyright (c) 2008, Frances Y. Kuo and Stephen Joe -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the names of the copyright holders nor the names of the - University of New South Wales and the University of Waikato - and its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -=============================================================================== - -The initial commit of package "org.apache.commons.math3.ml.neuralnet" is -an adapted version of code developed in the context of the Data Processing -and Analysis Consortium (DPAC) of the "Gaia" project of the European Space -Agency (ESA). -=============================================================================== - -The initial commit of the class "org.apache.commons.math3.special.BesselJ" is -an adapted version of code translated from the netlib Fortran program, rjbesl -http://www.netlib.org/specfun/rjbesl by R.J. Cody at Argonne National -Laboratory (USA). There is no license or copyright statement included with the -original Fortran sources. -=============================================================================== - - -The BracketFinder (package org.apache.commons.math3.optimization.univariate) -and PowellOptimizer (package org.apache.commons.math3.optimization.general) -classes are based on the Python code in module "optimize.py" (version 0.5) -developed by Travis E. Oliphant for the SciPy library (http://www.scipy.org/) -Copyright © 2003-2009 SciPy Developers. - -SciPy license -Copyright © 2001, 2002 Enthought, Inc. -All rights reserved. - -Copyright © 2003-2013 SciPy Developers. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of Enthought nor the names of the SciPy Developers may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -=============================================================================== diff --git a/license/third_party/crng_license.txt b/license/third_party/crng_license.txt deleted file mode 100644 index dec0e2a5c..000000000 --- a/license/third_party/crng_license.txt +++ /dev/null @@ -1,275 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -================================================================================ - -Class "org.apache.commons.rng.core.source64.MersenneTwister64" contains -Java code partly ported from the reference implementation in C. -That source file contained the following notice: - - Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura, - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. The names of its contributors may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -================================================================================ - -Class "org.apache.commons.rng.core.source32.MersenneTwister" contains -Java code partly ported from the reference implementation in C. -That source file contained the following notice: - - Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. The names of its contributors may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -================================================================================ \ No newline at end of file diff --git a/license/third_party/numky_license.txt b/license/third_party/numky_license.txt deleted file mode 100644 index f49a4e16e..000000000 --- a/license/third_party/numky_license.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index b3c275810..b2f40300c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,6 +1,22 @@ +pluginManagement { + repositories { + maven("https://repo.kotlin.link") + mavenCentral() + gradlePluginPortal() + } + + val kotlinVersion = "1.5.21" + + plugins { + id("org.jetbrains.kotlinx.benchmark") version "0.3.1" + id("ru.mipt.npm.gradle.project") version "0.10.2" + kotlin("multiplatform") version kotlinVersion + kotlin("plugin.allopen") version kotlinVersion + } +} + rootProject.name = "kmath" -enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") include( ":kmath-memory", ":kmath-complex", @@ -10,9 +26,6 @@ include( ":kmath-histograms", ":kmath-commons", ":kmath-viktor", - ":kmath-multik", - ":kmath-tensorflow", - ":kmath-optimization", ":kmath-stat", ":kmath-nd4j", ":kmath-dimensions", @@ -23,6 +36,7 @@ include( ":kmath-kotlingrad", ":kmath-tensors", ":kmath-jupyter", + ":kmath-units", ":kmath-symja", ":kmath-jafama", ":examples",