diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9a9f04621..cde58b6d6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,9 @@ name: Gradle build -on: [ push ] +on: + push: + branches: [ dev, master ] + pull_request: jobs: build: @@ -8,23 +11,22 @@ jobs: matrix: os: [ macOS-latest, windows-latest ] runs-on: ${{matrix.os}} - timeout-minutes: 30 + timeout-minutes: 40 steps: - name: Checkout the repo uses: actions/checkout@v2 - name: Set up JDK 11 uses: DeLaGuardo/setup-graalvm@4.0 with: - graalvm: 21.1.0 + graalvm: 21.2.0 java: java11 arch: amd64 - - name: Add msys to path - if: matrix.os == 'windows-latest' - run: SETX PATH "%PATH%;C:\msys64\mingw64\bin" - name: Cache gradle uses: actions/cache@v2 with: - path: ~/.gradle/caches + path: | + ~/.gradle/caches + ~/.gradle/wrapper key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} restore-keys: | ${{ runner.os }}-gradle- @@ -36,4 +38,4 @@ jobs: restore-keys: | ${{ runner.os }}-gradle- - name: Build - run: ./gradlew build --no-daemon --stacktrace + run: ./gradlew build --build-cache --no-daemon --stacktrace diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 86fdac6a6..23ed54357 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -2,23 +2,27 @@ name: Dokka publication on: push: - branches: - - master + branches: [ master ] jobs: build: runs-on: ubuntu-20.04 + timeout-minutes: 40 steps: - - name: Checkout the repo - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v1 + - uses: actions/checkout@v2 + - uses: DeLaGuardo/setup-graalvm@4.0 with: - java-version: 11 - - name: Build - run: ./gradlew dokkaHtmlMultiModule --no-daemon --no-parallel --stacktrace - - name: Deploy to GitHub Pages - uses: JamesIves/github-pages-deploy-action@4.1.0 + graalvm: 21.2.0 + java: java11 + arch: amd64 + - uses: actions/cache@v2 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} + restore-keys: | + ${{ runner.os }}-gradle- + - 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 c5c110e89..c5075cb0f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,8 +3,7 @@ name: Gradle publish on: workflow_dispatch: release: - types: - - created + types: [ created ] jobs: publish: @@ -20,16 +19,15 @@ jobs: - name: Set up JDK 11 uses: DeLaGuardo/setup-graalvm@4.0 with: - graalvm: 21.1.0 + graalvm: 21.2.0 java: java11 arch: amd64 - - name: Add msys to path - if: matrix.os == 'windows-latest' - run: SETX PATH "%PATH%;C:\msys64\mingw64\bin" - name: Cache gradle uses: actions/cache@v2 with: - path: ~/.gradle/caches + path: | + ~/.gradle/caches + ~/.gradle/wrapper key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} restore-keys: | ${{ runner.os }}-gradle- @@ -42,20 +40,14 @@ jobs: ${{ runner.os }}-gradle- - name: Publish Windows Artifacts if: matrix.os == 'windows-latest' + shell: cmd run: > - ./gradlew release --no-daemon - -Ppublishing.enabled=true - -Ppublishing.github.user=${{ secrets.PUBLISHING_GITHUB_USER }} - -Ppublishing.github.token=${{ secrets.PUBLISHING_GITHUB_TOKEN }} - -Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }} - -Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }} + ./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' run: > - ./gradlew release --no-daemon - -Ppublishing.enabled=true - -Ppublishing.platform=macosX64 - -Ppublishing.github.user=${{ secrets.PUBLISHING_GITHUB_USER }} - -Ppublishing.github.token=${{ secrets.PUBLISHING_GITHUB_TOKEN }} - -Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }} - -Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }} + ./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/CHANGELOG.md b/CHANGELOG.md index 8c4f5b547..eadf5877d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,11 @@ ## [Unreleased] ### Added -- ScaleOperations interface -- Field extends ScaleOperations +- `ScaleOperations` interface +- `Field` extends `ScaleOperations` - Basic integration API - Basic MPP distributions and samplers -- bindSymbolOrNull +- `bindSymbolOrNull` - Blocking chains and Statistics - Multiplatform integration - Integration for any Field element @@ -15,6 +15,8 @@ - `@PerformancePitfall` annotation to mark possibly slow API - BigInt operation performance improvement and fixes by @zhelenskiy (#328) - Unified architecture for Integration and Optimization using features. +- `BigInt` operation performance improvement and fixes by @zhelenskiy (#328) +- Integration between `MST` and Symja `IExpr` ### Changed - Exponential operations merged with hyperbolic functions @@ -53,6 +55,7 @@ ### Fixed - Ring inherits RingOperations, not GroupOperations +- Univariate histogram filling ### Security diff --git a/README.md b/README.md index 9117582ac..db069d4e0 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,14 @@ [![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382) ![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg) [![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22) -[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fkscience%2Fkmath%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) +[![Space](https://img.shields.io/badge/dynamic/xml?color=orange&label=Space&query=//metadata/versioning/latest&url=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) # KMath -Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based analog to -Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture -designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could -be achieved with [kmath-for-real](/kmath-for-real) extension module. +Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based +analog to Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior +architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like +experience could be achieved with [kmath-for-real](/kmath-for-real) extension module. [Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/) @@ -21,26 +21,33 @@ be achieved with [kmath-for-real](/kmath-for-real) extension module. # Goal -* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native). +* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native) + . * Provide basic multiplatform implementations for those abstractions (without significant performance optimization). * Provide bindings and wrappers with those abstractions for popular optimized platform libraries. ## Non-goals -* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in terms of API. +* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in API. * Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them. * Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually. -* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like -for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better -experience for those, who want to work with specific types. +* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like + for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better + experience for those, who want to work with specific types. ## Features and stability -KMath is a modular library. Different modules provide different features with different API stability guarantees. All core modules are released with the same version, but with different API change policy. The features are described in module definitions below. The module stability could have following levels: +KMath is a modular library. Different modules provide different features with different API stability guarantees. All +core modules are released with the same version, but with different API change policy. The features are described in +module definitions below. The module stability could have the following levels: -* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could break any moment. You can still use it, but be sure to fix the specific version. -* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked with `@UnstableKmathAPI` or other stability warning annotations. -* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor versions, but not in patch versions. API is protected with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. +* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could + break any moment. You can still use it, but be sure to fix the specific version. +* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked + with `@UnstableKmathAPI` or other stability warning annotations. +* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor + versions, but not in patch versions. API is protected + with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. * **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. @@ -132,7 +139,7 @@ KMath is a modular library. Different modules provide different features with di objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high performance calculations to code generation. > - [domains](kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains) : Domains -> - [autodif](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation +> - [autodiff](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
@@ -161,7 +168,7 @@ performance calculations to code generation.
* ### [kmath-for-real](kmath-for-real) -> Extension module that should be used to achieve numpy-like behavior. +> 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. > @@ -175,7 +182,7 @@ One can still use generic algebras though.
* ### [kmath-functions](kmath-functions) -> Functions, integration and interpolation +> > > **Maturity**: EXPERIMENTAL > @@ -200,6 +207,16 @@ One can still use generic algebras though. > **Maturity**: PROTOTYPE
+* ### [kmath-jafama](kmath-jafama) +> +> +> **Maturity**: PROTOTYPE +> +> **Features:** +> - [jafama-double](kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/) : Double ExtendedField implementations based on Jafama + +
+ * ### [kmath-jupyter](kmath-jupyter) > > @@ -207,24 +224,24 @@ One can still use generic algebras though.
* ### [kmath-kotlingrad](kmath-kotlingrad) -> Functions, integration and interpolation +> > > **Maturity**: EXPERIMENTAL > > **Features:** -> - [differentiable-mst-expression](kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt) : MST based DifferentiableExpression. -> - [differentiable-mst-expression](kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt) : Conversions between Kotlin∇'s SFun and MST +> - [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) -> An API and basic implementation for arranging objects in a continous memory block. +> An API and basic implementation for arranging objects in a continuous memory block. > > **Maturity**: DEVELOPMENT
* ### [kmath-nd4j](kmath-nd4j) -> ND4J NDStructure implementation and according NDAlgebra classes +> > > **Maturity**: EXPERIMENTAL > @@ -241,6 +258,12 @@ One can still use generic algebras though. > **Maturity**: EXPERIMENTAL
+* ### [kmath-symja](kmath-symja) +> +> +> **Maturity**: PROTOTYPE +
+ * ### [kmath-tensors](kmath-tensors) > > @@ -248,7 +271,7 @@ One can still use generic algebras though. > > **Features:** > - [tensor algebra](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt) : Basic linear algebra operations on tensors (plus, dot, etc.) -> - [tensor algebra with broadcasting](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt) : Basic linear algebra operations implemented with broadcasting. +> - [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.
@@ -262,30 +285,33 @@ One can still use generic algebras though. ## Multi-platform support -KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the -[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features -are delegated to platform-specific implementations even if they could be provided in the common module for performance -reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and +KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the +[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features +are delegated to platform-specific implementations even if they could be provided in the common module for performance +reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and feedback are also welcome. ## Performance -Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve -both performance and flexibility. +Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve both +performance and flexibility. -We expect to focus on creating convenient universal API first and then work on increasing performance for specific -cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized -native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be +We expect to focus on creating convenient universal API first and then work on increasing performance for specific +cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized +native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be better than SciPy. ## Requirements -KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance. +KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for +execution to get better performance. ### Repositories -Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of -[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy: +Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) +repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of +[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could +be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy: ```kotlin repositories { @@ -293,8 +319,8 @@ repositories { } dependencies { - api("space.kscience:kmath-core:0.3.0-dev-11") - // api("space.kscience:kmath-core-jvm:0.3.0-dev-11") 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 } ``` @@ -302,7 +328,7 @@ Gradle `6.0+` is required for multiplatform artifacts. ## Contributing -The project requires a lot of additional work. The most important thing we need is a feedback about what features are -required the most. Feel free to create feature requests. We are also welcome to code contributions, -especially in issues marked with +The project requires a lot of additional work. The most important thing we need is a feedback about what features are +required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues +marked with [waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index 98ffc5a96..d96c5a8b6 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -1,3 +1,7 @@ +@file:Suppress("UNUSED_VARIABLE") + +import space.kscience.kmath.benchmarks.addBenchmarkProperties + plugins { kotlin("multiplatform") kotlin("plugin.allopen") @@ -12,6 +16,7 @@ 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 } @@ -30,7 +35,8 @@ kotlin { implementation(project(":kmath-stat")) implementation(project(":kmath-dimensions")) implementation(project(":kmath-for-real")) - implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.0") + implementation(project(":kmath-jafama")) + implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.1") } } @@ -41,8 +47,7 @@ kotlin { implementation(project(":kmath-nd4j")) implementation(project(":kmath-kotlingrad")) implementation(project(":kmath-viktor")) - implementation("org.nd4j:nd4j-native:1.0.0-beta7") - + implementation("org.nd4j:nd4j-native:1.0.0-M1") // uncomment if your system supports AVX2 // val os = System.getProperty("os.name") // @@ -95,6 +100,11 @@ benchmark { commonConfiguration() include("BigIntBenchmark") } + + configurations.register("jafamaDouble") { + commonConfiguration() + include("JafamaBenchmark") + } } // Fix kotlinx-benchmarks bug @@ -124,3 +134,5 @@ tasks.withType { readme { maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL } + +addBenchmarkProperties() 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 15cd14399..0294f924b 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt @@ -14,22 +14,51 @@ 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 @State(Scope.Benchmark) internal 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 asmExpression(blackhole: Blackhole) = invokeAndSum(asm, 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 @@ -42,23 +71,24 @@ internal class ExpressionsInterpretersBenchmark { } private companion object { - private val x: Symbol by symbol - private val algebra: DoubleField = DoubleField + private val x by symbol + private val algebra = DoubleField private const val times = 1_000_000 - private val functional: Expression = DoubleField.expressionInExtendedField { + 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 { - bindSymbol(x) * 2.0 + number(2.0) / bindSymbol(x) - number(16.0) / sin(bindSymbol(x)) + x * 2.0 + number(2.0) / x - number(16.0) / sin(x) } - private val mst: Expression = node.toExpression(DoubleField) - private val asm: Expression = node.compileToExpression(DoubleField) + private val mst = node.toExpression(DoubleField) + private val asm = node.compileToExpression(DoubleField) - private val raw: Expression = Expression { args -> - args.getValue(x) * 2.0 + 2.0 / args.getValue(x) - 16.0 / kotlin.math.sin(args.getValue(x)) + 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/JafamaBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt new file mode 100644 index 000000000..5d4eee7c0 --- /dev/null +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.benchmarks + +import kotlinx.benchmark.Blackhole +import org.openjdk.jmh.annotations.Benchmark +import org.openjdk.jmh.annotations.Scope +import org.openjdk.jmh.annotations.State +import space.kscience.kmath.jafama.JafamaDoubleField +import space.kscience.kmath.jafama.StrictJafamaDoubleField +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.operations.invoke +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlin.random.Random + +@State(Scope.Benchmark) +internal class JafamaBenchmark { + @Benchmark + fun jafama(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> + JafamaDoubleField { x * power(x, 4) * exp(x) / cos(x) + sin(x) } + } + + @Benchmark + fun core(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> + DoubleField { x * power(x, 4) * exp(x) / cos(x) + sin(x) } + } + + @Benchmark + fun strictJafama(blackhole: Blackhole) = invokeBenchmarks(blackhole) { x -> + StrictJafamaDoubleField { x * power(x, 4) * exp(x) / cos(x) + sin(x) } + } +} + +private inline fun invokeBenchmarks(blackhole: Blackhole, expr: (Double) -> Double) { + contract { callsInPlace(expr, InvocationKind.AT_LEAST_ONCE) } + val rng = Random(0) + repeat(1000000) { blackhole.consume(expr(rng.nextDouble())) } +} 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 ff67ccc84..8da23bee1 100644 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt +++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt @@ -14,8 +14,8 @@ 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.lupSolver import space.kscience.kmath.nd.getFeature import kotlin.random.Random @@ -35,19 +35,19 @@ internal class MatrixInverseBenchmark { @Benchmark fun kmathLupInversion(blackhole: Blackhole) { - blackhole.consume(LinearSpace.double.inverseWithLup(matrix)) + blackhole.consume(LinearSpace.double.lupSolver().inverse(matrix)) } @Benchmark fun cmLUPInversion(blackhole: Blackhole) { - with(CMLinearSpace) { + CMLinearSpace { blackhole.consume(inverse(matrix)) } } @Benchmark fun ejmlInverse(blackhole: Blackhole) { - with(EjmlLinearSpaceDDRM) { + EjmlLinearSpaceDDRM { blackhole.consume(matrix.getFeature>()?.inverse) } } diff --git a/build.gradle.kts b/build.gradle.kts index 4de6d8bad..6bb19cd35 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import java.net.URL + plugins { id("ru.mipt.npm.gradle.project") kotlin("jupyter.api") apply false @@ -7,15 +9,17 @@ allprojects { repositories { 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-13" + version = "0.3.0-dev-14" } subprojects { @@ -23,30 +27,46 @@ subprojects { afterEvaluate { tasks.withType { - dependsOn(tasks.getByName("assemble")) + dependsOn(tasks["assemble"]) dokkaSourceSets.all { - val readmeFile = File(this@subprojects.projectDir, "README.md") - if (readmeFile.exists()) includes.setFrom(includes + readmeFile.absolutePath) - externalDocumentationLink("http://ejml.org/javadoc/") + val readmeFile = this@subprojects.projectDir.resolve("README.md") + if (readmeFile.exists()) includes.from(readmeFile) + val kotlinDirPath = "src/$name/kotlin" + val kotlinDir = file(kotlinDirPath) + + if (kotlinDir.exists()) sourceLink { + localDirectory.set(kotlinDir) + + remoteUrl.set( + URL("https://github.com/mipt-npm/${rootProject.name}/tree/master/${this@subprojects.name}/$kotlinDirPath") + ) + } + externalDocumentationLink("https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/") externalDocumentationLink("https://deeplearning4j.org/api/latest/") - externalDocumentationLink("https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/") + externalDocumentationLink("https://axelclk.bitbucket.io/symja/javadoc/") + + externalDocumentationLink( + "https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/", + "https://kotlin.github.io/kotlinx.coroutines/package-list", + ) + + externalDocumentationLink( + "https://breandan.net/kotlingrad/kotlingrad/", + "https://breandan.net/kotlingrad/kotlingrad/kotlingrad/package-list", + ) } } } } -readme { - readmeTemplate = file("docs/templates/README-TEMPLATE.md") -} +readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") ksciencePublish { - github("kmath") - space() - sonatype() + vcs("https://github.com/mipt-npm/kmath") + space(publish = true) + sonatype(publish = true) } -apiValidation { - nonPublicMarkers.add("space.kscience.kmath.misc.UnstableKMathAPI") -} +apiValidation.nonPublicMarkers.add("space.kscience.kmath.misc.UnstableKMathAPI") diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 7ca4df19d..36a1ffd9e 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,5 +1,20 @@ plugins { `kotlin-dsl` + kotlin("plugin.serialization") version "1.4.31" } -repositories.mavenCentral() +repositories { + maven("https://repo.kotlin.link") + mavenCentral() + gradlePluginPortal() +} + +dependencies { + 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.useExperimentalAnnotation("kotlin.ExperimentalStdlibApi") +} diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt new file mode 100644 index 000000000..eaa0f59d8 --- /dev/null +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt @@ -0,0 +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. + */ + +package space.kscience.kmath.benchmarks + +import kotlinx.serialization.Serializable + +@Serializable +data class JmhReport( + val jmhVersion: String, + val benchmark: String, + val mode: String, + val threads: Int, + val forks: Int, + val jvm: String, + val jvmArgs: List, + val jdkVersion: String, + val vmName: String, + val vmVersion: String, + val warmupIterations: Int, + val warmupTime: String, + val warmupBatchSize: Int, + val measurementIterations: Int, + val measurementTime: String, + val measurementBatchSize: Int, + val params: Map = emptyMap(), + val primaryMetric: PrimaryMetric, + val secondaryMetrics: Map, +) { + interface Metric { + val score: Double + val scoreError: Double + val scoreConfidence: List + val scorePercentiles: Map + val scoreUnit: String + } + + @Serializable + data class PrimaryMetric( + override val score: Double, + override val scoreError: Double, + override val scoreConfidence: List, + override val scorePercentiles: Map, + override val scoreUnit: String, + val rawDataHistogram: List>>>? = null, + val rawData: List>? = null, + ) : Metric + + @Serializable + data class SecondaryMetric( + override val score: Double, + override val scoreError: Double, + override val scoreConfidence: List, + override val scorePercentiles: Map, + override val scoreUnit: String, + val rawData: List>, + ) : Metric +} diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt new file mode 100644 index 000000000..b55e1320e --- /dev/null +++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt @@ -0,0 +1,100 @@ +/* + * Copyright 2018-2021 KMath 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.gradle.BenchmarksExtension +import kotlinx.serialization.* +import kotlinx.serialization.json.* +import org.gradle.api.Project +import ru.mipt.npm.gradle.KScienceReadmeExtension +import java.time.* +import java.time.format.* +import java.time.temporal.ChronoField.* + +private val ISO_DATE_TIME: DateTimeFormatter = DateTimeFormatterBuilder().run { + parseCaseInsensitive() + appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) + appendLiteral('-') + appendValue(MONTH_OF_YEAR, 2) + appendLiteral('-') + appendValue(DAY_OF_MONTH, 2) + appendLiteral('T') + appendValue(HOUR_OF_DAY, 2) + appendLiteral('.') + appendValue(MINUTE_OF_HOUR, 2) + optionalStart() + appendLiteral('.') + appendValue(SECOND_OF_MINUTE, 2) + optionalStart() + appendFraction(NANO_OF_SECOND, 0, 9, true) + optionalStart() + appendOffsetId() + optionalStart() + appendLiteral('[') + parseCaseSensitive() + appendZoneRegionId() + appendLiteral(']') + toFormatter() +} + +private fun noun(number: Number, singular: String, plural: String) = if (number.toLong() == 1L) singular else plural + +fun Project.addBenchmarkProperties() { + val benchmarksProject = this + rootProject.subprojects.forEach { p -> + p.extensions.findByType(KScienceReadmeExtension::class.java)?.run { + benchmarksProject.extensions.findByType(BenchmarksExtension::class.java)?.configurations?.forEach { cfg -> + 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) { + "> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**." + } else { + val reports = + Json.decodeFromString>(resDirectory.resolve("jvm.json").readText()) + + buildString { + appendLine("
") + appendLine("") + appendLine("Report for benchmark configuration ${cfg.name}") + appendLine("") + appendLine() + val first = reports.first() + + appendLine("* Run on ${first.vmName} (build ${first.vmVersion}) with Java process:") + appendLine() + appendLine("```") + appendLine("${first.jvm} ${ + first.jvmArgs.joinToString(" ") + }") + appendLine("```") + + appendLine("* JMH ${first.jmhVersion} was used in `${first.mode}` mode with ${first.warmupIterations} warmup ${ + noun(first.warmupIterations, "iteration", "iterations") + } by ${first.warmupTime} and ${first.measurementIterations} measurement ${ + noun(first.measurementIterations, "iteration", "iterations") + } by ${first.measurementTime}.") + + appendLine() + appendLine("| Benchmark | Score |") + appendLine("|:---------:|:-----:|") + + reports.forEach { report -> + appendLine("|`${report.benchmark}`|${report.primaryMetric.score} ± ${report.primaryMetric.scoreError} ${report.primaryMetric.scoreUnit}|") + } + + appendLine("
") + } + } + } + } + } + } +} 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 da1f45c1f..c68a7ae1c 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 @@ -14,12 +14,12 @@ private fun Appendable.appendEjmlVector(type: String, ejmlMatrixType: String) { @Language("kotlin") val text = """/** * [EjmlVector] specialization for [$type]. */ -public class Ejml${type}Vector(public override val origin: M) : EjmlVector<$type, M>(origin) { +public class Ejml${type}Vector(override val origin: M) : EjmlVector<$type, M>(origin) { init { require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } } - public override operator fun get(index: Int): $type = origin[0, index] + override operator fun get(index: Int): $type = origin[0, index] }""" appendLine(text) appendLine() @@ -29,8 +29,8 @@ private fun Appendable.appendEjmlMatrix(type: String, ejmlMatrixType: String) { val text = """/** * [EjmlMatrix] specialization for [$type]. */ -public class Ejml${type}Matrix(public override val origin: M) : EjmlMatrix<$type, M>(origin) { - public override operator fun get(i: Int, j: Int): $type = origin[i, j] +public class Ejml${type}Matrix(override val origin: M) : EjmlMatrix<$type, M>(origin) { + override operator fun get(i: Int, j: Int): $type = origin[i, j] }""" appendLine(text) appendLine() @@ -54,23 +54,23 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, /** * The [${kmathAlgebra}] reference. */ - public override val elementAlgebra: $kmathAlgebra get() = $kmathAlgebra + override val elementAlgebra: $kmathAlgebra get() = $kmathAlgebra @Suppress("UNCHECKED_CAST") - public override fun Matrix<${type}>.toEjml(): Ejml${type}Matrix<${ejmlMatrixType}> = when { + override fun Matrix<${type}>.toEjml(): Ejml${type}Matrix<${ejmlMatrixType}> = when { this is Ejml${type}Matrix<*> && origin is $ejmlMatrixType -> this as Ejml${type}Matrix<${ejmlMatrixType}> else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } } @Suppress("UNCHECKED_CAST") - public override fun Point<${type}>.toEjml(): Ejml${type}Vector<${ejmlMatrixType}> = when { + override fun Point<${type}>.toEjml(): Ejml${type}Vector<${ejmlMatrixType}> = when { this is Ejml${type}Vector<*> && origin is $ejmlMatrixType -> this as Ejml${type}Vector<${ejmlMatrixType}> else -> Ejml${type}Vector(${ejmlMatrixType}(size, 1).also { (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } }) } - public override fun buildMatrix( + override fun buildMatrix( rows: Int, columns: Int, initializer: ${kmathAlgebra}.(i: Int, j: Int) -> ${type}, @@ -80,7 +80,7 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, } }.wrapMatrix() - public override fun buildVector( + override fun buildVector( size: Int, initializer: ${kmathAlgebra}.(Int) -> ${type}, ): Ejml${type}Vector<${ejmlMatrixType}> = Ejml${type}Vector(${ejmlMatrixType}(size, 1).also { @@ -90,21 +90,21 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, private fun T.wrapMatrix() = Ejml${type}Matrix(this) private fun T.wrapVector() = Ejml${type}Vector(this) - public override fun Matrix<${type}>.unaryMinus(): Matrix<${type}> = this * elementAlgebra { -one } + override fun Matrix<${type}>.unaryMinus(): Matrix<${type}> = this * elementAlgebra { -one } - public override fun Matrix<${type}>.dot(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { + override fun Matrix<${type}>.dot(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { val out = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.mult(toEjml().origin, other.toEjml().origin, out) return out.wrapMatrix() } - public override fun Matrix<${type}>.dot(vector: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { + override fun Matrix<${type}>.dot(vector: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { val out = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.mult(toEjml().origin, vector.toEjml().origin, out) return out.wrapVector() } - public override operator fun Matrix<${type}>.minus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { + override operator fun Matrix<${type}>.minus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { val out = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.add( @@ -123,19 +123,19 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, return out.wrapMatrix() } - public override operator fun Matrix<${type}>.times(value: ${type}): Ejml${type}Matrix<${ejmlMatrixType}> { + override operator fun Matrix<${type}>.times(value: ${type}): Ejml${type}Matrix<${ejmlMatrixType}> { val res = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.scale(value, toEjml().origin, res) return res.wrapMatrix() } - public override fun Point<${type}>.unaryMinus(): Ejml${type}Vector<${ejmlMatrixType}> { + override fun Point<${type}>.unaryMinus(): Ejml${type}Vector<${ejmlMatrixType}> { val res = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.changeSign(toEjml().origin, res) return res.wrapVector() } - public override fun Matrix<${type}>.plus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { + override fun Matrix<${type}>.plus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { val out = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.add( @@ -154,7 +154,7 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, return out.wrapMatrix() } - public override fun Point<${type}>.plus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { + override fun Point<${type}>.plus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { val out = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.add( @@ -173,7 +173,7 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, return out.wrapVector() } - public override fun Point<${type}>.minus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { + override fun Point<${type}>.minus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { val out = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.add( @@ -192,18 +192,18 @@ public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, return out.wrapVector() } - public override fun ${type}.times(m: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> = m * this + override fun ${type}.times(m: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> = m * this - public override fun Point<${type}>.times(value: ${type}): Ejml${type}Vector<${ejmlMatrixType}> { + override fun Point<${type}>.times(value: ${type}): Ejml${type}Vector<${ejmlMatrixType}> { val res = ${ejmlMatrixType}(1, 1) CommonOps_${ops}.scale(value, toEjml().origin, res) return res.wrapVector() } - public override fun ${type}.times(v: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> = v * this + override fun ${type}.times(v: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> = v * this @UnstableKMathAPI - public override fun computeFeature(structure: Matrix<${type}>, type: KClass): F? { + override fun computeFeature(structure: Matrix<${type}>, type: KClass): F? { structure.getFeature(type)?.let { return it } val origin = structure.toEjml().origin diff --git a/docs/algebra.md b/docs/algebra.md index 84693bb81..20158a125 100644 --- a/docs/algebra.md +++ b/docs/algebra.md @@ -1,85 +1,45 @@ # Algebraic Structures and Algebraic Elements -The mathematical operations in KMath are generally separated from mathematical objects. This means that to perform an -operation, say `+`, one needs two objects of a type `T` and an algebra context, which draws appropriate operation up, -say `Space`. Next one needs to run the actual operation in the context: +The mathematical operations in KMath are generally separated from mathematical objects. This means that to perform an +operation, say `+`, one needs two objects of a type `T` and an algebra context, which draws appropriate operation up, +say `Group`. Next one needs to run the actual operation in the context: ```kotlin import space.kscience.kmath.operations.* val a: T = ... val b: T = ... -val space: Space = ... +val group: Group = ... -val c = space { a + b } +val c = group { a + b } ``` -At first glance, this distinction seems to be a needless complication, but in fact one needs to remember that in -mathematics, one could draw up different operations on same objects. For example, one could use different types of +At first glance, this distinction seems to be a needless complication, but in fact one needs to remember that in +mathematics, one could draw up different operations on same objects. For example, one could use different types of geometry for vectors. ## Algebraic Structures -Mathematical contexts have the following hierarchy: +Primary mathematical contexts have the following hierarchy: -**Algebra** ← **Space** ← **Ring** ← **Field** +`Field <: Ring <: Group <: Algebra` These interfaces follow real algebraic structures: -- [Space](https://mathworld.wolfram.com/VectorSpace.html) defines addition, its neutral element (i.e. 0) and scalar -multiplication; -- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its neutral element (i.e. 1); +- [Group](https://mathworld.wolfram.com/Group.html) defines addition, its identity element (i.e., 0) and additive + inverse (-x); +- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its identity element (i.e., 1); - [Field](http://mathworld.wolfram.com/Field.html) adds division operation. A typical implementation of `Field` is the `DoubleField` which works on doubles, and `VectorSpace` for `Space`. In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate -interface. Also, contexts may have operations, which produce elements outside of the context. For example, `Matrix.dot` -operation produces a matrix with new dimensions, which can be incompatible with initial matrix in terms of linear -operations. - -## Algebraic Element - -To achieve more familiar behavior (where you apply operations directly to mathematical objects), without involving -contexts KMath submits special type objects called `MathElement`. A `MathElement` is basically some object coupled to -a mathematical context. For example `Complex` is the pair of real numbers representing real and imaginary parts, -but it also holds reference to the `ComplexField` singleton, which allows performing direct operations on `Complex` -numbers without explicit involving the context like: - -```kotlin -import space.kscience.kmath.operations.* - -// Using elements -val c1 = Complex(1.0, 1.0) -val c2 = Complex(1.0, -1.0) -val c3 = c1 + c2 + 3.0.toComplex() - -// Using context -val c4 = ComplexField { c1 + i - 2.0 } -``` - -Both notations have their pros and cons. - -The hierarchy for algebraic elements follows the hierarchy for the corresponding algebraic structures. - -**MathElement** ← **SpaceElement** ← **RingElement** ← **FieldElement** - -`MathElement` is the generic common ancestor of the class with context. - -One major distinction between algebraic elements and algebraic contexts is that elements have three type -parameters: - -1. The type of elements, the field operates on. -2. The self-type of the element returned from operation (which has to be an algebraic element). -3. The type of the algebra over first type-parameter. - -The middle type is needed for of algebra members do not store context. For example, it is impossible to add a context -to regular `Double`. The element performs automatic conversions from context types and back. One should use context -operations in all performance-critical places. The performance of element operations is not guaranteed. +interface. Also, contexts may have operations, which produce elements outside the context. For example, `Matrix.dot` +operation produces a matrix with new dimensions, which can be incompatible with initial matrix in linear operations. ## Spaces and Fields -KMath submits both contexts and elements for builtin algebraic structures: +KMath introduces contexts for builtin algebraic structures: ```kotlin import space.kscience.kmath.operations.* @@ -102,13 +62,13 @@ val c2 = ComplexField { c1 - 1.0 } // Returns: Complex(re=0.0, im=2.0) val c3 = ComplexField { c1 - i * 2.0 } ``` -**Note**: In theory it is possible to add behaviors directly to the context, but as for now Kotlin does not support -that. Watch [KT-10468](https://youtrack.jetbrains.com/issue/KT-10468) and +**Note**: In theory it is possible to add behaviors directly to the context, but as for now Kotlin does not support +that. Watch [KT-10468](https://youtrack.jetbrains.com/issue/KT-10468) and [KEEP-176](https://github.com/Kotlin/KEEP/pull/176) for updates. ## Nested fields -Contexts allow one to build more complex structures. For example, it is possible to create a `Matrix` from complex +Contexts allow one to build more complex structures. For example, it is possible to create a `Matrix` from complex elements like so: ```kotlin @@ -118,8 +78,9 @@ val element = NDElement.complex(shape = intArrayOf(2, 2)) { index: IntArray -> ``` The `element` in this example is a member of the `Field` of 2D structures, each element of which is a member of its own -`ComplexField`. It is important one does not need to create a special n-d class to hold complex -numbers and implement operations on it, one just needs to provide a field for its elements. +`ComplexField`. It is important one does not need to create a special n-d class to hold complex numbers and implement +operations on it, one just needs to provide a field for its elements. -**Note**: Fields themselves do not solve the problem of JVM boxing, but it is possible to solve with special contexts like +**Note**: Fields themselves do not solve the problem of JVM boxing, but it is possible to solve with special contexts +like `MemorySpec`. diff --git a/docs/buffers.md b/docs/buffers.md index 679bd4e78..e7573497e 100644 --- a/docs/buffers.md +++ b/docs/buffers.md @@ -1,17 +1,20 @@ # Buffers -Buffer is one of main building blocks of kmath. It is a basic interface allowing random-access read and write (with `MutableBuffer`). -There are different types of buffers: +Buffer is one of main building blocks of kmath. It is a basic interface allowing random-access read and write ( +with `MutableBuffer`). There are different types of buffers: -* Primitive buffers wrapping like `RealBuffer` which are wrapping primitive arrays. +* Primitive buffers wrapping like `DoubleBuffer` which are wrapping primitive arrays. * Boxing `ListBuffer` wrapping a list * Functionally defined `VirtualBuffer` which does not hold a state itself, but provides a function to calculate value * `MemoryBuffer` allows direct allocation of objects in continuous memory block. -Some kmath features require a `BufferFactory` class to operate properly. A general convention is to use functions defined in -`Buffer` and `MutableBuffer` companion classes. For example factory `Buffer.Companion::auto` in most cases creates the most suitable -buffer for given reified type (for types with custom memory buffer it still better to use their own `MemoryBuffer.create()` factory). +Some kmath features require a `BufferFactory` class to operate properly. A general convention is to use functions +defined in +`Buffer` and `MutableBuffer` companion classes. For example factory `Buffer.Companion::auto` in most cases creates the +most suitable buffer for given reified type (for types with custom memory buffer it still better to use their +own `MemoryBuffer.create()` factory). ## Buffer performance -One should avoid using default boxing buffer wherever it is possible. Try to use primitive buffers or memory buffers instead +One should avoid using default boxing buffer wherever it is possible. Try to use primitive buffers or memory buffers +instead . diff --git a/docs/codestyle.md b/docs/codestyle.md index 541dc4973..73ba5f754 100644 --- a/docs/codestyle.md +++ b/docs/codestyle.md @@ -1,26 +1,20 @@ # Coding Conventions -KMath code follows general [Kotlin conventions](https://kotlinlang.org/docs/reference/coding-conventions.html), but -with a number of small changes and clarifications. +Generally, KMath code follows general [Kotlin coding conventions](https://kotlinlang.org/docs/reference/coding-conventions.html), but with a number of small changes and clarifications. ## Utility Class Naming -Filename should coincide with a name of one of the classes contained in the file or start with small letter and -describe its contents. +Filename should coincide with a name of one of the classes contained in the file or start with small letter and describe its contents. -The code convention [here](https://kotlinlang.org/docs/reference/coding-conventions.html#source-file-names) says that -file names should start with a capital letter even if file does not contain classes. Yet starting utility classes and -aggregators with a small letter seems to be a good way to visually separate those files. +The code convention [here](https://kotlinlang.org/docs/reference/coding-conventions.html#source-file-names) says that file names should start with a capital letter even if file does not contain classes. Yet starting utility classes and aggregators with a small letter seems to be a good way to visually separate those files. This convention could be changed in future in a non-breaking way. ## Private Variable Naming -Private variables' names may start with underscore `_` for of the private mutable variable is shadowed by the public -read-only value with the same meaning. +Private variables' names may start with underscore `_` for of the private mutable variable is shadowed by the public read-only value with the same meaning. -This rule does not permit underscores in names, but it is sometimes useful to "underscore" the fact that public and -private versions draw up the same entity. It is allowed only for private variables. +This rule does not permit underscores in names, but it is sometimes useful to "underscore" the fact that public and private versions draw up the same entity. It is allowed only for private variables. This convention could be changed in future in a non-breaking way. @@ -30,5 +24,4 @@ Use one-liners when they occupy single code window line both for functions and p `val b: String get() = "fff"`. The same should be performed with multiline expressions when they could be cleanly separated. -There is no universal consensus whenever use `fun a() = ...` or `fun a() { return ... }`. Yet from reader outlook -one-lines seem to better show that the property or function is easily calculated. +There is no universal consensus whenever use `fun a() = ...` or `fun a() { return ... }`. Yet from reader outlook one-lines seem to better show that the property or function is easily calculated. diff --git a/docs/contexts.md b/docs/contexts.md index 58b198046..c26333860 100644 --- a/docs/contexts.md +++ b/docs/contexts.md @@ -2,18 +2,17 @@ ## The problem -A known problem for implementing mathematics in statically-typed languages (but not only in them) is that different -sets of mathematical operators can be defined on the same mathematical objects. Sometimes there is no single way to -treat some operations, including basic arithmetic operations, on a Java/Kotlin `Number`. Sometimes there are different ways to -define the same structure, such as Euclidean and elliptic geometry vector spaces over real vectors. Another problem arises when -one wants to add some kind of behavior to an existing entity. In dynamic languages those problems are usually solved -by adding dynamic context-specific behaviors at runtime, but this solution has a lot of drawbacks. +A known problem for implementing mathematics in statically-typed languages (but not only in them) is that different sets +of mathematical operators can be defined on the same mathematical objects. Sometimes there is no single way to treat +some operations, including basic arithmetic operations, on a Java/Kotlin `Number`. Sometimes there are different ways to +define the same structure, such as Euclidean and elliptic geometry vector spaces over real vectors. Another problem +arises when one wants to add some kind of behavior to an existing entity. In dynamic languages those problems are +usually solved by adding dynamic context-specific behaviors at runtime, but this solution has a lot of drawbacks. ## Context-oriented approach -One possible solution to these problems is to divorce numerical representations from behaviors. -For example in Kotlin one can define a separate class which represents some entity without any operations, -ex. a complex number: +One possible solution to these problems is to divorce numerical representations from behaviors. For example in Kotlin +one can define a separate class representing some entity without any operations, ex. a complex number: ```kotlin data class Complex(val re: Double, val im: Double) @@ -28,9 +27,10 @@ object ComplexOperations { } ``` -In Java, applying such external operations could be very cumbersome, but Kotlin has a unique feature which allows us -implement this naturally: [extensions with receivers](https://kotlinlang.org/docs/reference/extensions.html#extension-functions). -In Kotlin, an operation on complex number could be implemented as: +In Java, applying such external operations could be cumbersome, but Kotlin has a unique feature that allows us +implement this +naturally: [extensions with receivers](https://kotlinlang.org/docs/reference/extensions.html#extension-functions). In +Kotlin, an operation on complex number could be implemented as: ```kotlin with(ComplexOperations) { c1 + c2 - c3 } @@ -52,20 +52,20 @@ In KMath, contexts are not only responsible for operations, but also for raw obj ### Type classes -An obvious candidate to get more or less the same functionality is the type class, which allows one to bind a behavior to -a specific type without modifying the type itself. On the plus side, type classes do not require explicit context +An obvious candidate to get more or less the same functionality is the type class, which allows one to bind a behavior +to a specific type without modifying the type itself. On the plus side, type classes do not require explicit context declaration, so the code looks cleaner. On the minus side, if there are different sets of behaviors for the same types, -it is impossible to combine them into one module. Also, unlike type classes, context can have parameters or even -state. For example in KMath, sizes and strides for `NDElement` or `Matrix` could be moved to context to optimize -performance in case of a large amount of structures. +it is impossible to combine them into one module. Also, unlike type classes, context can have parameters or even state. +For example in KMath, sizes and strides for `NDElement` or `Matrix` could be moved to context to optimize performance in +case of a large amount of structures. ### Wildcard imports and importing-on-demand -Sometimes, one may wish to use a single context throughout a file. In this case, is possible to import all members -from a package or file, via `import context.complex.*`. Effectively, this is the same as enclosing an entire file -with a single context. However when using multiple contexts, this technique can introduce operator ambiguity, due to -namespace pollution. If there are multiple scoped contexts which define the same operation, it is still possible to -to import specific operations as needed, without using an explicit context with extension functions, for example: +Sometimes, one may wish to use a single context throughout a file. In this case, is possible to import all members from +a package or file, via `import context.complex.*`. Effectively, this is the same as enclosing an entire file with a +single context. However, when using multiple contexts, this technique can introduce operator ambiguity, due to namespace +pollution. If there are multiple scoped contexts that define the same operation, it is still possible to import +specific operations as needed, without using an explicit context with extension functions, for example: ``` import context.complex.op1 diff --git a/docs/expressions.md b/docs/expressions.md index 1e05e5340..e6250110c 100644 --- a/docs/expressions.md +++ b/docs/expressions.md @@ -1,26 +1,21 @@ # Expressions -**Experimental: this API is in early stage and could change any time** - -Expressions is an experimental feature which allows to construct lazily or immediately calculated parametric mathematical -expressions. +Expressions is a feature, which allows constructing lazily or immediately calculated parametric mathematical expressions. The potential use-cases for it (so far) are following: -* Lazy evaluation (in general simple lambda is better, but there are some border cases) +* lazy evaluation (in general simple lambda is better, but there are some border cases); +* automatic differentiation in single-dimension and in multiple dimensions; +* generation of mathematical syntax trees with subsequent code generation for other languages; +* symbolic computations, especially differentiation (and some other actions with `kmath-symja` integration with Symja's `IExpr`—integration, simplification, and more); +* visualization with `kmath-jupyter`. -* Automatic differentiation in single-dimension and in multiple dimensions - -* Generation of mathematical syntax trees with subsequent code generation for other languages - -* Maybe symbolic computations (needs additional research) - -The workhorse of this API is `Expression` interface which exposes single `operator fun invoke(arguments: Map): T` -method. `ExpressionContext` is used to generate expressions and introduce variables. +The workhorse of this API is `Expression` interface, which exposes single `operator fun invoke(arguments: Map): T` +method. `ExpressionAlgebra` is used to generate expressions and introduce variables. Currently there are two implementations: * Generic `ExpressionField` in `kmath-core` which allows construction of custom lazy expressions -* Auto-differentiation expression in `kmath-commons` module allows to use full power of `DerivativeStructure` +* Auto-differentiation expression in `kmath-commons` module allows using full power of `DerivativeStructure` from commons-math. **TODO: add example** diff --git a/docs/features.md b/docs/features.md deleted file mode 100644 index 1068a4417..000000000 --- a/docs/features.md +++ /dev/null @@ -1,14 +0,0 @@ -# Features - -* [Algebra](algebra.md) - [Context-based](contexts.md) operations on different primitives and structures. - -* [NDStructures](nd-structure.md) - -* [Linear algebra](linear.md) - Matrices, operations and linear equations solving. To be moved to separate module. Currently supports basic -api and multiple library back-ends. - -* [Histograms](histograms.md) - Multidimensional histogram calculation and operations. - -* [Expressions](expressions.md) - -* Commons math integration diff --git a/docs/linear.md b/docs/linear.md index 6ccc6caac..2a05499ef 100644 --- a/docs/linear.md +++ b/docs/linear.md @@ -1,19 +1,31 @@ ## Basic linear algebra layout -KMath support for linear algebra organized in a context-oriented way. Meaning that operations are in most cases declared -in context classes, and are not the members of classes that store data. This allows more flexible approach to maintain multiple -back-ends. The new operations added as extensions to contexts instead of being member functions of data structures. +KMath support for linear algebra organized in a context-oriented way, which means that operations are in most cases declared in context classes, and are not the members of classes that store data. This allows more flexible approach to maintain multiple back-ends. The new operations added as extensions to contexts instead of being member functions of data structures. -Two major contexts used for linear algebra and hyper-geometry: +The main context for linear algebra over matrices and vectors is `LinearSpace`, which defines addition and dot products of matrices and vectors: -* `VectorSpace` forms a mathematical space on top of array-like structure (`Buffer` and its type alias `Point` used for geometry). +```kotlin +import space.kscience.kmath.linear.* -* `MatrixContext` forms a space-like context for 2d-structures. It does not store matrix size and therefore does not implement -`Space` interface (it is impossible to create zero element without knowing the matrix size). +LinearSpace.Companion.real { + val vec = buildVector(10) { i -> i.toDouble() } + val mat = buildMatrix(10, 10) { i, j -> i.toDouble() + j } -## Vector spaces + // Addition + vec + vec + mat + mat + // Multiplication by scalar + vec * 2.0 + mat * 2.0 -## Matrix operations + // Dot product + mat dot vec + mat dot mat +} +``` -## Back-end overview \ No newline at end of file +## Backends overview + +### EJML +### Commons Math diff --git a/docs/nd-structure.md b/docs/nd-structure.md index ec9b4d521..3e9203ec0 100644 --- a/docs/nd-structure.md +++ b/docs/nd-structure.md @@ -11,16 +11,16 @@ Let us consider following contexts: ```kotlin // automatically build context most suited for given type. val autoField = NDField.auto(DoubleField, dim, dim) - // specialized nd-field for Double. It works as generic Double field as well + // specialized nd-field for Double. It works as generic Double field as well. val specializedField = NDField.real(dim, dim) //A generic boxing field. It should be used for objects, not primitives. val genericField = NDField.buffered(DoubleField, dim, dim) ``` -Now let us perform several tests and see which implementation is best suited for each case: +Now let us perform several tests and see, which implementation is best suited for each case: ## Test case -In order to test performance we will take 2d-structures with `dim = 1000` and add a structure filled with `1.0` +To test performance we will take 2d-structures with `dim = 1000` and add a structure filled with `1.0` to it `n = 1000` times. ## Specialized @@ -35,8 +35,8 @@ The code to run this looks like: ``` The performance of this code is the best of all tests since it inlines all operations and is specialized for operation with doubles. We will measure everything else relative to this one, so time for this test will be `1x` (real time -on my computer is about 4.5 seconds). The only problem with this approach is that it requires to specify type -from the beginning. Everyone do so anyway, so it is the recommended approach. +on my computer is about 4.5 seconds). The only problem with this approach is that it requires specifying type +from the beginning. Everyone does so anyway, so it is the recommended approach. ## Automatic Let's do the same with automatic field inference: @@ -49,7 +49,7 @@ Let's do the same with automatic field inference: } ``` Ths speed of this operation is approximately the same as for specialized case since `NDField.auto` just -returns the same `RealNDField` in this case. Of course it is usually better to use specialized method to be sure. +returns the same `RealNDField` in this case. Of course, it is usually better to use specialized method to be sure. ## Lazy Lazy field does not produce a structure when asked, instead it generates an empty structure and fills it on-demand @@ -63,7 +63,7 @@ When one calls } } ``` -The result will be calculated almost immediately but the result will be empty. In order to get the full result +The result will be calculated almost immediately but the result will be empty. To get the full result structure one needs to call all its elements. In this case computation overhead will be huge. So this field never should be used if one expects to use the full result structure. Though if one wants only small fraction, it could save a lot of time. @@ -94,7 +94,7 @@ The boxing field produced by } } ``` -obviously is the slowest one, because it requires to box and unbox the `double` on each operation. It takes about +is the slowest one, because it requires boxing and unboxing the `double` on each operation. It takes about `15x` time (**TODO: there seems to be a problem here, it should be slow, but not that slow**). This field should never be used for primitives. @@ -115,12 +115,14 @@ via extension function. Usually it is bad idea to compare the direct numerical operation performance in different languages, but it hard to work completely without frame of reference. In this case, simple numpy code: ```python +import numpy as np + res = np.ones((1000,1000)) for i in range(1000): res = res + 1.0 ``` gives the completion time of about `1.1x`, which means that specialized kotlin code in fact is working faster (I think it is because better memory management). Of course if one writes `res += 1.0`, the performance will be different, -but it would be differenc case, because numpy overrides `+=` with in-place operations. In-place operations are +but it would be different case, because numpy overrides `+=` with in-place operations. In-place operations are available in `kmath` with `MutableNDStructure` but there is no field for it (one can still work with mapping functions). \ No newline at end of file diff --git a/docs/readme.md b/docs/readme.md new file mode 100644 index 000000000..2953b7113 --- /dev/null +++ b/docs/readme.md @@ -0,0 +1,14 @@ +# Documentation + +* [Algebra](algebra.md): [context-based](contexts.md) operations on different primitives and structures. + +* [NDStructures](nd-structure.md) + +* [Linear algebra](linear.md): matrices, operations and linear equations solving. To be moved to separate module. + Currently, supports basic API and multiple library back-ends. + +* [Histograms](histograms.md): multidimensional histogram calculation and operations. + +* [Expressions](expressions.md) + +* Commons math integration diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md index 6bb1e9085..e75d4c5ed 100644 --- a/docs/templates/README-TEMPLATE.md +++ b/docs/templates/README-TEMPLATE.md @@ -2,14 +2,14 @@ [![DOI](https://zenodo.org/badge/129486382.svg)](https://zenodo.org/badge/latestdoi/129486382) ![Gradle build](https://github.com/mipt-npm/kmath/workflows/Gradle%20build/badge.svg) [![Maven Central](https://img.shields.io/maven-central/v/space.kscience/kmath-core.svg?label=Maven%20Central)](https://search.maven.org/search?q=g:%22space.kscience%22) -[![Space](https://img.shields.io/maven-metadata/v?label=Space&metadataUrl=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fkscience%2Fkmath%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) +[![Space](https://img.shields.io/badge/dynamic/xml?color=orange&label=Space&query=//metadata/versioning/latest&url=https%3A%2F%2Fmaven.pkg.jetbrains.space%2Fmipt-npm%2Fp%2Fsci%2Fmaven%2Fspace%2Fkscience%2Fkmath-core%2Fmaven-metadata.xml)](https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven/space/kscience/) # KMath -Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based analog to -Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior architecture -designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like experience could -be achieved with [kmath-for-real](/kmath-for-real) extension module. +Could be pronounced as `key-math`. The **K**otlin **Math**ematics library was initially intended as a Kotlin-based +analog to Python's NumPy library. Later we found that kotlin is much more flexible language and allows superior +architecture designs. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. The `numpy`-like +experience could be achieved with [kmath-for-real](/kmath-for-real) extension module. [Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/) @@ -21,26 +21,33 @@ be achieved with [kmath-for-real](/kmath-for-real) extension module. # Goal -* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native). +* Provide a flexible and powerful API to work with mathematics abstractions in Kotlin-multiplatform (JVM, JS and Native) + . * Provide basic multiplatform implementations for those abstractions (without significant performance optimization). * Provide bindings and wrappers with those abstractions for popular optimized platform libraries. ## Non-goals -* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in terms of API. +* Be like NumPy. It was the idea at the beginning, but we decided that we can do better in API. * Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them. * Cover all cases as immediately and in one bundle. We will modularize everything and add new features gradually. -* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like -for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better -experience for those, who want to work with specific types. +* Provide specialized behavior in the core. API is made generic on purpose, so one needs to specialize for types, like + for `Double` in the core. For that we will have specialization modules like `kmath-for-real`, which will give better + experience for those, who want to work with specific types. ## Features and stability -KMath is a modular library. Different modules provide different features with different API stability guarantees. All core modules are released with the same version, but with different API change policy. The features are described in module definitions below. The module stability could have following levels: +KMath is a modular library. Different modules provide different features with different API stability guarantees. All +core modules are released with the same version, but with different API change policy. The features are described in +module definitions below. The module stability could have the following levels: -* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could break any moment. You can still use it, but be sure to fix the specific version. -* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked with `@UnstableKmathAPI` or other stability warning annotations. -* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor versions, but not in patch versions. API is protected with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. +* **PROTOTYPE**. On this level there are no compatibility guarantees. All methods and classes form those modules could + break any moment. You can still use it, but be sure to fix the specific version. +* **EXPERIMENTAL**. The general API is decided, but some changes could be made. Volatile API is marked + with `@UnstableKmathAPI` or other stability warning annotations. +* **DEVELOPMENT**. API breaking generally follows semantic versioning ideology. There could be changes in minor + versions, but not in patch versions. API is protected + with [binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) tool. * **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. @@ -78,30 +85,33 @@ $modules ## Multi-platform support -KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the -[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features -are delegated to platform-specific implementations even if they could be provided in the common module for performance -reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and +KMath is developed as a multi-platform library, which means that most of the interfaces are declared in the +[common source sets](/kmath-core/src/commonMain) and implemented there wherever it is possible. In some cases, features +are delegated to platform-specific implementations even if they could be provided in the common module for performance +reasons. Currently, the Kotlin/JVM is the primary platform, however Kotlin/Native and Kotlin/JS contributions and feedback are also welcome. ## Performance -Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve -both performance and flexibility. +Calculation performance is one of major goals of KMath in the future, but in some cases it is impossible to achieve both +performance and flexibility. -We expect to focus on creating convenient universal API first and then work on increasing performance for specific -cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized -native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be +We expect to focus on creating convenient universal API first and then work on increasing performance for specific +cases. We expect the worst KMath benchmarks will perform better than native Python, but worse than optimized +native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be better than SciPy. ## Requirements -KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance. +KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for +execution to get better performance. ### Repositories -Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of -[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy: +Release and development artifacts are accessible from mipt-npm [Space](https://www.jetbrains.com/space/) +repository `https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven` (see documentation of +[Kotlin Multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) for more details). The repository could +be reached through [repo.kotlin.link](https://repo.kotlin.link) proxy: ```kotlin repositories { @@ -118,7 +128,7 @@ Gradle `6.0+` is required for multiplatform artifacts. ## Contributing -The project requires a lot of additional work. The most important thing we need is a feedback about what features are -required the most. Feel free to create feature requests. We are also welcome to code contributions, -especially in issues marked with +The project requires a lot of additional work. The most important thing we need is a feedback about what features are +required the most. Feel free to create feature requests. We are also welcome to code contributions, especially in issues +marked with [waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index d095db1ba..4cc6fecc0 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -26,7 +26,7 @@ dependencies { implementation(project(":kmath-ejml")) implementation(project(":kmath-nd4j")) implementation(project(":kmath-tensors")) - + implementation(project(":kmath-symja")) implementation(project(":kmath-for-real")) implementation("org.nd4j:nd4j-native:1.0.0-beta7") @@ -41,9 +41,11 @@ dependencies { // } else implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") - implementation("org.slf4j:slf4j-simple:1.7.30") + implementation("org.slf4j:slf4j-simple:1.7.31") // plotting - implementation("space.kscience:plotlykt-server:0.4.0") + implementation("space.kscience:plotlykt-server:0.4.2") + //jafama + implementation(project(":kmath-jafama")) } kotlin.sourceSets.all { 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 e16769464..c4f263f97 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt @@ -10,7 +10,7 @@ import space.kscience.kmath.ast.rendering.LatexSyntaxRenderer import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer import space.kscience.kmath.ast.rendering.renderWithStringBuilder -public fun main() { +fun main() { val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath() val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst) println("MathSyntax:") 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 d5a82590f..96c9856cf 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt @@ -9,12 +9,10 @@ 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.bindSymbol import space.kscience.kmath.operations.invoke fun main() { val expr = MstField { - val x = bindSymbol(x) x * 2.0 + number(2.0) / x - 16.0 } 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 88fd312c7..dec3bfb81 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt @@ -5,25 +5,23 @@ package space.kscience.kmath.ast -import space.kscience.kmath.asm.compileToExpression import space.kscience.kmath.expressions.derivative import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.expressions.symbol +import space.kscience.kmath.expressions.Symbol.Companion.x +import space.kscience.kmath.expressions.toExpression import space.kscience.kmath.kotlingrad.toKotlingradExpression import space.kscience.kmath.operations.DoubleField /** - * In this example, x^2-4*x-44 function is differentiated with Kotlin∇, and the autodiff result is compared with - * valid derivative. + * In this example, *x2 − 4 x − 44* function is differentiated with Kotlin∇, and the + * derivation result is compared with valid derivative in a certain point. */ fun main() { - val x by symbol - - val actualDerivative = "x^2-4*x-44".parseMath() + val actualDerivative = "x^2-4*x-44" + .parseMath() .toKotlingradExpression(DoubleField) .derivative(x) - - val expectedDerivative = "2*x-4".parseMath().compileToExpression(DoubleField) - assert(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0)) + val expectedDerivative = "2*x-4".parseMath().toExpression(DoubleField) + check(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0)) } diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt new file mode 100644 index 000000000..7e09faeff --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2018-2021 KMath 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.Symbol.Companion.x +import space.kscience.kmath.expressions.derivative +import space.kscience.kmath.expressions.invoke +import space.kscience.kmath.expressions.toExpression +import space.kscience.kmath.operations.DoubleField +import space.kscience.kmath.symja.toSymjaExpression + +/** + * In this example, *x2 − 4 x − 44* function is differentiated with Symja, and the + * derivation result is compared with valid derivative in a certain point. + */ +fun main() { + val actualDerivative = "x^2-4*x-44" + .parseMath() + .toSymjaExpression(DoubleField) + .derivative(x) + + val expectedDerivative = "2*x-4".parseMath().toExpression(DoubleField) + check(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0)) +} diff --git a/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt index 5660c76e8..8d95ebb4a 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt @@ -7,11 +7,15 @@ package space.kscience.kmath.commons.fit import kotlinx.html.br import kotlinx.html.h3 -import space.kscience.kmath.commons.optimization.chiSquared +import space.kscience.kmath.commons.expressions.DSProcessor +import space.kscience.kmath.commons.optimization.CMOptimizer import space.kscience.kmath.distributions.NormalDistribution +import space.kscience.kmath.expressions.chiSquaredExpression import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.optimization.FunctionOptimization -import space.kscience.kmath.optimization.OptimizationResult +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.real.DoubleVector import space.kscience.kmath.real.map import space.kscience.kmath.real.step @@ -24,8 +28,7 @@ import space.kscience.plotly.models.TraceValues import kotlin.math.pow import kotlin.math.sqrt -//Forward declaration of symbols that will be used in expressions. -// This declaration is required for +// 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 @@ -64,17 +67,21 @@ 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 = FunctionOptimization.chiSquared(x, y, yErr) { x1 -> + val chi2 = DSProcessor.chiSquaredExpression(x, y, yErr) { arg -> //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 * x1.pow(2) + b * x1 + c + a * arg.pow(2) + b * arg + c } //minimize the chi^2 in given starting point. Derivatives are not required, they are already included. - val result: OptimizationResult = chi2.minimize(a to 1.5, b to 0.9, c to 1.0) + val result = chi2.optimizeWith( + CMOptimizer, + mapOf(a to 1.5, b to 0.9, c to 1.0), + FunctionOptimizationTarget.MINIMIZE + ) //display a page with plot and numerical results val page = Plotly.page { @@ -91,7 +98,7 @@ suspend fun main() { scatter { mode = ScatterMode.lines x(x) - y(x.map { result.point[a]!! * it.pow(2) + result.point[b]!! * it + 1 }) + y(x.map { result.resultPoint[a]!! * it.pow(2) + result.resultPoint[b]!! * it + 1 }) name = "fit" } } @@ -100,7 +107,7 @@ suspend fun main() { +"Fit result: $result" } h3 { - +"Chi2/dof = ${result.value / (x.size - 3)}" + +"Chi2/dof = ${result.resultValue / (x.size - 3)}" } } diff --git a/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt new file mode 100644 index 000000000..9c3d0fdbe --- /dev/null +++ b/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt @@ -0,0 +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. + */ + +package space.kscience.kmath.jafama + +import space.kscience.kmath.operations.invoke + +fun main() { + val a = 2.0 + val b = StrictJafamaDoubleField { exp(a) } + println(JafamaDoubleField { b + a }) + println(StrictJafamaDoubleField { ln(b) }) +} 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 b319766e3..bde83cea9 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt @@ -10,9 +10,6 @@ import space.kscience.kmath.chains.Chain import space.kscience.kmath.chains.collectWithState import space.kscience.kmath.distributions.NormalDistribution -/** - * The state of distribution averager. - */ private data class AveragingChainState(var num: Int = 0, var value: Double = 0.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 501bf98db..e1621d477 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt @@ -32,7 +32,7 @@ fun main() { // automatically build context most suited for given type. val autoField = AlgebraND.auto(DoubleField, dim, dim) - // specialized nd-field for Double. It works as generic Double field as well + // specialized nd-field for Double. It works as generic Double field as well. val realField = AlgebraND.real(dim, dim) //A generic boxing field. It should be used for objects, not primitives. val boxingField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim) 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 955f86fa9..c28b566b9 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt @@ -19,7 +19,7 @@ private fun DMatrixContext.simple() { } private object D5 : Dimension { - override val dim: UInt = 5u + override val dim: Int = 5 } private fun DMatrixContext.custom() { diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt index 74795cc68..ad6890b15 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt @@ -17,7 +17,7 @@ fun main() = BroadcastDoubleTensorAlgebra { // work in context with broadcast m dataset += fromArray( intArrayOf(5), - doubleArrayOf(0.0, 1.0, 1.5, 3.0, 5.0) // rows means + doubleArrayOf(0.0, 1.0, 1.5, 3.0, 5.0) // row means ) @@ -28,7 +28,7 @@ fun main() = BroadcastDoubleTensorAlgebra { // work in context with broadcast m println("Mean:\n$mean") println("Standard deviation:\n$std") - // also we can calculate other statistic as minimum and maximum of rows + // also, we can calculate other statistic as minimum and maximum of rows println("Minimum:\n${dataset.min(0, false)}") println("Maximum:\n${dataset.max(0, false)}") diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt index 6453ca44e..3e6a60c31 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt @@ -42,7 +42,7 @@ fun main() = BroadcastDoubleTensorAlgebra {// work in context with linear operat // get P, L, U such that PA = LU val (p, l, u) = a.lu() - // check that P is permutation matrix + // check P is permutation matrix println("P:\n$p") // L is lower triangular matrix and U is upper triangular matrix println("L:\n$l") diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt index b262bee02..55a9aa67a 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt @@ -186,7 +186,7 @@ fun main() = BroadcastDoubleTensorAlgebra { x += fromArray( intArrayOf(5), - doubleArrayOf(0.0, -1.0, -2.5, -3.0, 5.5) // rows means + doubleArrayOf(0.0, -1.0, -2.5, -3.0, 5.5) // row means ) 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 411e048d7..b973abdef 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt +++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt @@ -65,8 +65,8 @@ fun main(): Unit = BroadcastDoubleTensorAlgebra { // work in context with broad val datasetReduced = v dot stack(listOf(xScaled, yScaled)) println("Reduced data:\n$datasetReduced") - // we can restore original data from reduced data. - // for example, find 7th element of dataset + // we can restore original data from reduced data; + // for example, find 7th element of dataset. val n = 7 val restored = (datasetReduced[n] dot v.view(intArrayOf(1, 2))) * std + mean println("Original value:\n${dataset[n]}") diff --git a/gradle.properties b/gradle.properties index 7e9516660..b97db1c54 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,7 +7,6 @@ kotlin.code.style=official kotlin.mpp.enableGranularSourceSetsMetadata=true kotlin.mpp.stability.nowarn=true kotlin.native.enableDependencyPropagation=false -kotlin.parallel.tasks.in.project=true 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 e708b1c02..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 f371643ee..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.0-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 4f906e0c8..744e882ed 100755 --- a/gradlew +++ b/gradlew @@ -72,7 +72,7 @@ case "`uname`" in Darwin* ) darwin=true ;; - MINGW* ) + MSYS* | MINGW* ) msys=true ;; NONSTOP* ) diff --git a/kmath-ast/README.md b/kmath-ast/README.md index b0f2d59e5..686506f6f 100644 --- a/kmath-ast/README.md +++ b/kmath-ast/README.md @@ -10,7 +10,7 @@ Performance and visualization extensions to MST API. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-14`. **Gradle:** ```gradle @@ -20,7 +20,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ast:0.3.0-dev-11' + implementation 'space.kscience:kmath-ast:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation("space.kscience:kmath-ast:0.3.0-dev-11") + implementation("space.kscience:kmath-ast:0.3.0-dev-14") } ``` @@ -45,11 +45,12 @@ special implementation of `Expression` with implemented `invoke` function. For example, the following builder: ```kotlin +import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.* import space.kscience.kmath.asm.* -MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField) +MstField { x + 2 }.compileToExpression(DoubleField) ``` ... leads to generation of bytecode, which can be decompiled to the following Java class: @@ -89,11 +90,12 @@ public final class AsmCompiledExpression_45045_0 implements Expression { A similar feature is also available on JS. ```kotlin +import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.* import space.kscience.kmath.estree.* -MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField) +MstField { x + 2 }.compileToExpression(DoubleField) ``` The code above returns expression implemented with such a JS function: @@ -104,15 +106,16 @@ var executable = function (constants, arguments) { }; ``` -JS also supports very experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation. +JS also supports experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation. Currently, only expressions inside `DoubleField` and `IntRing` are supported. ```kotlin +import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.* import space.kscience.kmath.wasm.* -MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField) +MstField { x + 2 }.compileToExpression(DoubleField) ``` An example of emitted Wasm IR in the form of WAT: @@ -158,7 +161,10 @@ public fun main() { Result LaTeX: +
+ ![](https://latex.codecogs.com/gif.latex?%5Coperatorname{exp}%5C,%5Cleft(%5Csqrt{x}%5Cright)-%5Cfrac{%5Cfrac{%5Coperatorname{arcsin}%5C,%5Cleft(2%5C,x%5Cright)}{2%5Ctimes10^{10}%2Bx^{3}}}{12}+x^{2/3}) +
Result MathML (can be used with MathJax or other renderers): diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts index 508374d82..9de7e9980 100644 --- a/kmath-ast/build.gradle.kts +++ b/kmath-ast/build.gradle.kts @@ -37,17 +37,15 @@ kotlin.sourceSets { jsMain { dependencies { - implementation(npm("astring", "1.7.4")) - implementation(npm("binaryen", "100.0")) - implementation(npm("js-base64", "3.6.0")) - implementation(npm("webassembly", "0.11.0")) + implementation(npm("astring", "1.7.5")) + implementation(npm("binaryen", "101.0.0")) + implementation(npm("js-base64", "3.6.1")) } } jvmMain { dependencies { - implementation("org.ow2.asm:asm:9.1") - implementation("org.ow2.asm:asm-commons:9.1") + implementation("org.ow2.asm:asm-commons:9.2") } } } @@ -63,25 +61,21 @@ readme { feature( id = "expression-language", - description = "Expression language and its parser", ref = "src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt" - ) + ) { "Expression language and its parser" } feature( id = "mst-jvm-codegen", - description = "Dynamic MST to JVM bytecode compiler", ref = "src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt" - ) + ) { "Dynamic MST to JVM bytecode compiler" } feature( id = "mst-js-codegen", - description = "Dynamic MST to JS compiler", ref = "src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt" - ) + ) { "Dynamic MST to JS compiler" } feature( id = "rendering", - description = "Extendable MST rendering", ref = "src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt" - ) + ) { "Extendable MST rendering" } } diff --git a/kmath-ast/docs/README-TEMPLATE.md b/kmath-ast/docs/README-TEMPLATE.md index 80ea31642..9494af63a 100644 --- a/kmath-ast/docs/README-TEMPLATE.md +++ b/kmath-ast/docs/README-TEMPLATE.md @@ -16,11 +16,12 @@ special implementation of `Expression` with implemented `invoke` function. For example, the following builder: ```kotlin +import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.* import space.kscience.kmath.asm.* -MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField) +MstField { x + 2 }.compileToExpression(DoubleField) ``` ... leads to generation of bytecode, which can be decompiled to the following Java class: @@ -60,11 +61,12 @@ public final class AsmCompiledExpression_45045_0 implements Expression { A similar feature is also available on JS. ```kotlin +import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.* import space.kscience.kmath.estree.* -MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField) +MstField { x + 2 }.compileToExpression(DoubleField) ``` The code above returns expression implemented with such a JS function: @@ -75,15 +77,16 @@ var executable = function (constants, arguments) { }; ``` -JS also supports very experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation. +JS also supports experimental expression optimization with [WebAssembly](https://webassembly.org/) IR generation. Currently, only expressions inside `DoubleField` and `IntRing` are supported. ```kotlin +import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.* import space.kscience.kmath.wasm.* -MstField { bindSymbol("x") + 2 }.compileToExpression(DoubleField) +MstField { x + 2 }.compileToExpression(DoubleField) ``` An example of emitted Wasm IR in the form of WAT: @@ -129,7 +132,10 @@ public fun main() { Result LaTeX: +
+ ![](https://latex.codecogs.com/gif.latex?%5Coperatorname{exp}%5C,%5Cleft(%5Csqrt{x}%5Cright)-%5Cfrac{%5Cfrac{%5Coperatorname{arcsin}%5C,%5Cleft(2%5C,x%5Cright)}{2%5Ctimes10^{10}%2Bx^{3}}}{12}+x^{2/3}) +
Result MathML (can be used with MathJax or other renderers): 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 01717b0f9..2df3d3cc7 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 @@ -27,7 +27,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI */ @UnstableKMathAPI public object LatexSyntaxRenderer : SyntaxRenderer { - public override fun render(node: MathSyntax, output: Appendable): Unit = output.run { + override fun render(node: MathSyntax, output: Appendable): Unit = output.run { fun render(syntax: MathSyntax) = render(syntax, output) when (node) { 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 cda8e2322..8b5819b84 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 @@ -16,7 +16,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI */ @UnstableKMathAPI public object MathMLSyntaxRenderer : SyntaxRenderer { - public override fun render(node: MathSyntax, output: Appendable) { + override fun render(node: MathSyntax, output: Appendable) { output.append("") renderPart(node, output) output.append("") 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 c33f95483..fdef35ebd 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 @@ -29,7 +29,7 @@ public fun interface MathRenderer { */ @UnstableKMathAPI public open class FeaturedMathRenderer(public val features: List) : MathRenderer { - public override fun render(mst: MST): MathSyntax { + override fun render(mst: MST): MathSyntax { for (feature in features) feature.render(this, mst)?.let { return it } throw UnsupportedOperationException("Renderer $this has no appropriate feature to render node $mst.") } @@ -54,9 +54,9 @@ public open class FeaturedMathRenderer(public val features: List) @UnstableKMathAPI public open class FeaturedMathRendererWithPostProcess( features: List, - public val stages: List, + public val stages: List, ) : FeaturedMathRenderer(features) { - public override fun render(mst: MST): MathSyntax { + override fun render(mst: MST): MathSyntax { val res = super.render(mst) for (stage in stages) stage.perform(res) return res @@ -65,7 +65,7 @@ public open class FeaturedMathRendererWithPostProcess( /** * Logical unit of [MathSyntax] post-processing. */ - public fun interface PostProcessStage { + public fun interface PostProcessPhase { /** * Performs the specified action over [MathSyntax]. */ @@ -102,7 +102,7 @@ public open class FeaturedMathRendererWithPostProcess( // Printing terminal nodes as string PrintNumeric, - PrintSymbolic, + PrintSymbol, ), listOf( BetterExponent, 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 a71985fbc..ee23ab408 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 @@ -8,7 +8,7 @@ package space.kscience.kmath.ast.rendering import space.kscience.kmath.misc.UnstableKMathAPI /** - * Mathematical typography syntax node. + * Syntax node for mathematical typography. * * @author Iaroslav Postovalov */ @@ -150,9 +150,9 @@ public data class OperandSyntax( */ @UnstableKMathAPI public data class UnaryOperatorSyntax( - public override val operation: String, + override val operation: String, public var prefix: MathSyntax, - public override val operand: OperandSyntax, + override val operand: OperandSyntax, ) : UnarySyntax() { init { operand.parent = this @@ -166,8 +166,8 @@ public data class UnaryOperatorSyntax( */ @UnstableKMathAPI public data class UnaryPlusSyntax( - public override val operation: String, - public override val operand: OperandSyntax, + override val operation: String, + override val operand: OperandSyntax, ) : UnarySyntax() { init { operand.parent = this @@ -181,8 +181,8 @@ public data class UnaryPlusSyntax( */ @UnstableKMathAPI public data class UnaryMinusSyntax( - public override val operation: String, - public override val operand: OperandSyntax, + override val operation: String, + override val operand: OperandSyntax, ) : UnarySyntax() { init { operand.parent = this @@ -197,8 +197,8 @@ public data class UnaryMinusSyntax( */ @UnstableKMathAPI public data class RadicalSyntax( - public override val operation: String, - public override val operand: MathSyntax, + override val operation: String, + override val operand: MathSyntax, ) : UnarySyntax() { init { operand.parent = this @@ -215,8 +215,8 @@ public data class RadicalSyntax( */ @UnstableKMathAPI public data class ExponentSyntax( - public override val operation: String, - public override val operand: OperandSyntax, + override val operation: String, + override val operand: OperandSyntax, public var useOperatorForm: Boolean, ) : UnarySyntax() { init { @@ -233,9 +233,9 @@ public data class ExponentSyntax( */ @UnstableKMathAPI public data class SuperscriptSyntax( - public override val operation: String, - public override val left: MathSyntax, - public override val right: MathSyntax, + override val operation: String, + override val left: MathSyntax, + override val right: MathSyntax, ) : BinarySyntax() { init { left.parent = this @@ -252,9 +252,9 @@ public data class SuperscriptSyntax( */ @UnstableKMathAPI public data class SubscriptSyntax( - public override val operation: String, - public override val left: MathSyntax, - public override val right: MathSyntax, + override val operation: String, + override val left: MathSyntax, + override val right: MathSyntax, ) : BinarySyntax() { init { left.parent = this @@ -270,10 +270,10 @@ public data class SubscriptSyntax( */ @UnstableKMathAPI public data class BinaryOperatorSyntax( - public override val operation: String, + override val operation: String, public var prefix: MathSyntax, - public override val left: MathSyntax, - public override val right: MathSyntax, + override val left: MathSyntax, + override val right: MathSyntax, ) : BinarySyntax() { init { left.parent = this @@ -290,9 +290,9 @@ public data class BinaryOperatorSyntax( */ @UnstableKMathAPI public data class BinaryPlusSyntax( - public override val operation: String, - public override val left: OperandSyntax, - public override val right: OperandSyntax, + override val operation: String, + override val left: OperandSyntax, + override val right: OperandSyntax, ) : BinarySyntax() { init { left.parent = this @@ -301,7 +301,7 @@ public data class BinaryPlusSyntax( } /** - * Represents binary, infix subtraction (*42 - 42*). + * Represents binary, infix subtraction (*42 − 42*). * * @param left The minuend. * @param right The subtrahend. @@ -309,9 +309,9 @@ public data class BinaryPlusSyntax( */ @UnstableKMathAPI public data class BinaryMinusSyntax( - public override val operation: String, - public override val left: OperandSyntax, - public override val right: OperandSyntax, + override val operation: String, + override val left: OperandSyntax, + override val right: OperandSyntax, ) : BinarySyntax() { init { left.parent = this @@ -329,9 +329,9 @@ public data class BinaryMinusSyntax( */ @UnstableKMathAPI public data class FractionSyntax( - public override val operation: String, - public override val left: OperandSyntax, - public override val right: OperandSyntax, + override val operation: String, + override val left: OperandSyntax, + override val right: OperandSyntax, public var infix: Boolean, ) : BinarySyntax() { init { @@ -349,9 +349,9 @@ public data class FractionSyntax( */ @UnstableKMathAPI public data class RadicalWithIndexSyntax( - public override val operation: String, - public override val left: MathSyntax, - public override val right: MathSyntax, + override val operation: String, + override val left: MathSyntax, + override val right: MathSyntax, ) : BinarySyntax() { init { left.parent = this @@ -369,9 +369,9 @@ public data class RadicalWithIndexSyntax( */ @UnstableKMathAPI public data class MultiplicationSyntax( - public override val operation: String, - public override val left: OperandSyntax, - public override val right: OperandSyntax, + override val operation: String, + override val left: OperandSyntax, + override val right: OperandSyntax, public var times: Boolean, ) : BinarySyntax() { init { 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 fb2b3b66f..362c07d72 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 @@ -9,7 +9,7 @@ import space.kscience.kmath.misc.UnstableKMathAPI /** * Abstraction of writing [MathSyntax] as a string of an actual markup language. Typical implementation should - * involve traversal of MathSyntax with handling each its subtype. + * involve traversal of MathSyntax with handling each subtype. * * @author Iaroslav Postovalov */ 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 863825799..8a4804916 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 @@ -13,15 +13,14 @@ import space.kscience.kmath.operations.* import kotlin.reflect.KClass /** - * Prints any [MST.Symbolic] as a [SymbolSyntax] containing the [MST.Symbolic.value] of it. + * Prints any [Symbol] as a [SymbolSyntax] containing the [Symbol.identity] of it. * * @author Iaroslav Postovalov */ @UnstableKMathAPI -public object PrintSymbolic : RenderFeature { - public override fun render(renderer: FeaturedMathRenderer, node: MST): SymbolSyntax? = - if (node !is Symbol) null - else SymbolSyntax(string = node.identity) +public val PrintSymbol: RenderFeature = RenderFeature { _, node -> + if (node !is Symbol) null + else SymbolSyntax(string = node.identity) } /** @@ -30,8 +29,8 @@ public object PrintSymbolic : RenderFeature { * @author Iaroslav Postovalov */ @UnstableKMathAPI -public object PrintNumeric : RenderFeature { - public override fun render(renderer: FeaturedMathRenderer, node: MST): NumberSyntax? = if (node !is MST.Numeric) +public val PrintNumeric: RenderFeature = RenderFeature { _, node -> + if (node !is MST.Numeric) null else NumberSyntax(string = node.value.toString()) @@ -50,7 +49,7 @@ else NumberSyntax(string = s) /** - * Special printing for numeric types which are printed in form of + * Special printing for numeric types that are printed in form of * *('-'? (DIGIT+ ('.' DIGIT+)? ('E' '-'? DIGIT+)? | 'Infinity')) | 'NaN'*. * * @property types The suitable types. @@ -58,7 +57,7 @@ else */ @UnstableKMathAPI public class PrettyPrintFloats(public val types: Set>) : RenderFeature { - public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { + override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { if (node !is MST.Numeric || node.value::class !in types) return null val toString = when (val v = node.value) { @@ -111,14 +110,14 @@ public class PrettyPrintFloats(public val types: Set>) : Rend } /** - * Special printing for numeric types which are printed in form of *'-'? DIGIT+*. + * Special printing for numeric types that are printed in form of *'-'? DIGIT+*. * * @property types The suitable types. * @author Iaroslav Postovalov */ @UnstableKMathAPI public class PrettyPrintIntegers(public val types: Set>) : RenderFeature { - public override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = + override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = if (node !is MST.Numeric || node.value::class !in types) null else @@ -141,7 +140,7 @@ public class PrettyPrintIntegers(public val types: Set>) : Re */ @UnstableKMathAPI public class PrettyPrintPi(public val symbols: Set) : RenderFeature { - public override fun render(renderer: FeaturedMathRenderer, node: MST): SpecialSymbolSyntax? = + override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = if (node !is Symbol || node.identity !in symbols) null else @@ -156,7 +155,7 @@ public class PrettyPrintPi(public val symbols: Set) : RenderFeature { } /** - * Abstract printing of unary operations which discards [MST] if their operation is not in [operations] or its type is + * Abstract printing of unary operations that discards [MST] if their operation is not in [operations] or its type is * not [MST.Unary]. * * @param operations the allowed operations. If `null`, any operation is accepted. @@ -177,7 +176,7 @@ public abstract class Unary(public val operations: Collection?) : Render } /** - * Abstract printing of unary operations which discards [MST] if their operation is not in [operations] or its type is + * Abstract printing of unary operations that discards [MST] if their operation is not in [operations] or its type is * not [MST.Binary]. * * @property operations the allowed operations. If `null`, any operation is accepted. @@ -203,7 +202,7 @@ public abstract class Binary(public val operations: Collection?) : Rende */ @UnstableKMathAPI public class BinaryPlus(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): BinaryPlusSyntax = + override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryPlusSyntax( operation = node.operation, left = OperandSyntax(parent.render(node.left), true), @@ -225,7 +224,7 @@ public class BinaryPlus(operations: Collection?) : Binary(operations) { */ @UnstableKMathAPI public class BinaryMinus(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): BinaryMinusSyntax = + override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryMinusSyntax( operation = node.operation, left = OperandSyntax(operand = parent.render(node.left), parentheses = true), @@ -247,7 +246,7 @@ public class BinaryMinus(operations: Collection?) : Binary(operations) { */ @UnstableKMathAPI public class UnaryPlus(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): UnaryPlusSyntax = UnaryPlusSyntax( + override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryPlusSyntax( operation = node.operation, operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), ) @@ -267,7 +266,7 @@ public class UnaryPlus(operations: Collection?) : Unary(operations) { */ @UnstableKMathAPI public class UnaryMinus(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): UnaryMinusSyntax = UnaryMinusSyntax( + override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryMinusSyntax( operation = node.operation, operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), ) @@ -287,7 +286,7 @@ public class UnaryMinus(operations: Collection?) : Unary(operations) { */ @UnstableKMathAPI public class Fraction(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): FractionSyntax = FractionSyntax( + override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = FractionSyntax( operation = node.operation, left = OperandSyntax(operand = parent.render(node.left), parentheses = true), right = OperandSyntax(operand = parent.render(node.right), parentheses = true), @@ -309,7 +308,7 @@ public class Fraction(operations: Collection?) : Binary(operations) { */ @UnstableKMathAPI public class BinaryOperator(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): BinaryOperatorSyntax = + override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = BinaryOperatorSyntax( operation = node.operation, prefix = OperatorNameSyntax(name = node.operation), @@ -332,7 +331,7 @@ public class BinaryOperator(operations: Collection?) : Binary(operations */ @UnstableKMathAPI public class UnaryOperator(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): UnaryOperatorSyntax = + override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax( operation = node.operation, prefix = OperatorNameSyntax(node.operation), @@ -354,7 +353,7 @@ public class UnaryOperator(operations: Collection?) : Unary(operations) */ @UnstableKMathAPI public class Power(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): SuperscriptSyntax = + override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = SuperscriptSyntax( operation = node.operation, left = OperandSyntax(parent.render(node.left), true), @@ -374,7 +373,7 @@ public class Power(operations: Collection?) : Binary(operations) { */ @UnstableKMathAPI public class SquareRoot(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): RadicalSyntax = + override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = RadicalSyntax(operation = node.operation, operand = parent.render(node.value)) public companion object { @@ -392,7 +391,7 @@ public class SquareRoot(operations: Collection?) : Unary(operations) { */ @UnstableKMathAPI public class Exponent(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): ExponentSyntax = ExponentSyntax( + override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = ExponentSyntax( operation = node.operation, operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), useOperatorForm = true, @@ -413,7 +412,7 @@ public class Exponent(operations: Collection?) : Unary(operations) { */ @UnstableKMathAPI public class Multiplication(operations: Collection?) : Binary(operations) { - public override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MultiplicationSyntax = + override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = MultiplicationSyntax( operation = node.operation, left = OperandSyntax(operand = parent.render(node.left), parentheses = true), @@ -436,7 +435,7 @@ public class Multiplication(operations: Collection?) : Binary(operations */ @UnstableKMathAPI public class InverseTrigonometricOperations(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): UnaryOperatorSyntax = + override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax( operation = node.operation, prefix = OperatorNameSyntax(name = node.operation.replaceFirst("a", "arc")), @@ -463,7 +462,7 @@ public class InverseTrigonometricOperations(operations: Collection?) : U */ @UnstableKMathAPI public class InverseHyperbolicOperations(operations: Collection?) : Unary(operations) { - public override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): UnaryOperatorSyntax = + override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryOperatorSyntax( operation = node.operation, prefix = OperatorNameSyntax(name = node.operation.replaceFirst("a", "ar")), diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/stages.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt similarity index 75% rename from kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/stages.kt rename to kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt index 1f31af853..574bb54f4 100644 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/stages.kt +++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt @@ -5,6 +5,7 @@ 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.FieldOperations import space.kscience.kmath.operations.GroupOperations @@ -17,8 +18,8 @@ import space.kscience.kmath.operations.RingOperations * @author Iaroslav Postovalov */ @UnstableKMathAPI -public object BetterMultiplication : FeaturedMathRendererWithPostProcess.PostProcessStage { - public override fun perform(node: MathSyntax): Unit = when (node) { +public val BetterMultiplication: PostProcessPhase = PostProcessPhase { node -> + fun perform(node: MathSyntax): Unit = when (node) { is NumberSyntax -> Unit is SymbolSyntax -> Unit is OperatorNameSyntax -> Unit @@ -81,6 +82,8 @@ public object BetterMultiplication : FeaturedMathRendererWithPostProcess.PostPro perform(node.right) } } + + perform(node) } /** @@ -89,68 +92,68 @@ public object BetterMultiplication : FeaturedMathRendererWithPostProcess.PostPro * @author Iaroslav Postovalov */ @UnstableKMathAPI -public object BetterFraction : FeaturedMathRendererWithPostProcess.PostProcessStage { - private fun perform0(node: MathSyntax, infix: Boolean = false): Unit = when (node) { +public val BetterFraction: PostProcessPhase = PostProcessPhase { node -> + fun perform(node: MathSyntax, infix: Boolean = false): Unit = when (node) { is NumberSyntax -> Unit is SymbolSyntax -> Unit is OperatorNameSyntax -> Unit is SpecialSymbolSyntax -> Unit - is OperandSyntax -> perform0(node.operand, infix) + is OperandSyntax -> perform(node.operand, infix) is UnaryOperatorSyntax -> { - perform0(node.prefix, infix) - perform0(node.operand, infix) + perform(node.prefix, infix) + perform(node.operand, infix) } - is UnaryPlusSyntax -> perform0(node.operand, infix) - is UnaryMinusSyntax -> perform0(node.operand, infix) - is RadicalSyntax -> perform0(node.operand, infix) - is ExponentSyntax -> perform0(node.operand, infix) + is UnaryPlusSyntax -> perform(node.operand, infix) + is UnaryMinusSyntax -> perform(node.operand, infix) + is RadicalSyntax -> perform(node.operand, infix) + is ExponentSyntax -> perform(node.operand, infix) is SuperscriptSyntax -> { - perform0(node.left, true) - perform0(node.right, true) + perform(node.left, true) + perform(node.right, true) } is SubscriptSyntax -> { - perform0(node.left, true) - perform0(node.right, true) + perform(node.left, true) + perform(node.right, true) } is BinaryOperatorSyntax -> { - perform0(node.prefix, infix) - perform0(node.left, infix) - perform0(node.right, infix) + perform(node.prefix, infix) + perform(node.left, infix) + perform(node.right, infix) } is BinaryPlusSyntax -> { - perform0(node.left, infix) - perform0(node.right, infix) + perform(node.left, infix) + perform(node.right, infix) } is BinaryMinusSyntax -> { - perform0(node.left, infix) - perform0(node.right, infix) + perform(node.left, infix) + perform(node.right, infix) } is FractionSyntax -> { node.infix = infix - perform0(node.left, infix) - perform0(node.right, infix) + perform(node.left, infix) + perform(node.right, infix) } is RadicalWithIndexSyntax -> { - perform0(node.left, true) - perform0(node.right, true) + perform(node.left, true) + perform(node.right, true) } is MultiplicationSyntax -> { - perform0(node.left, infix) - perform0(node.right, infix) + perform(node.left, infix) + perform(node.right, infix) } } - public override fun perform(node: MathSyntax): Unit = perform0(node) + perform(node) } /** @@ -160,39 +163,37 @@ public object BetterFraction : FeaturedMathRendererWithPostProcess.PostProcessSt * @author Iaroslav Postovalov */ @UnstableKMathAPI -public object BetterExponent : FeaturedMathRendererWithPostProcess.PostProcessStage { - private fun perform0(node: MathSyntax): Boolean { +public val BetterExponent: PostProcessPhase = PostProcessPhase { node -> + fun perform(node: MathSyntax): Boolean { return when (node) { is NumberSyntax -> false is SymbolSyntax -> false is OperatorNameSyntax -> false is SpecialSymbolSyntax -> false - is OperandSyntax -> perform0(node.operand) - is UnaryOperatorSyntax -> perform0(node.prefix) || perform0(node.operand) - is UnaryPlusSyntax -> perform0(node.operand) - is UnaryMinusSyntax -> perform0(node.operand) + is OperandSyntax -> perform(node.operand) + is UnaryOperatorSyntax -> perform(node.prefix) || perform(node.operand) + is UnaryPlusSyntax -> perform(node.operand) + is UnaryMinusSyntax -> perform(node.operand) is RadicalSyntax -> true is ExponentSyntax -> { - val r = perform0(node.operand) + val r = perform(node.operand) node.useOperatorForm = r r } is SuperscriptSyntax -> true is SubscriptSyntax -> true - is BinaryOperatorSyntax -> perform0(node.prefix) || perform0(node.left) || perform0(node.right) - is BinaryPlusSyntax -> perform0(node.left) || perform0(node.right) - is BinaryMinusSyntax -> perform0(node.left) || perform0(node.right) + is BinaryOperatorSyntax -> perform(node.prefix) || perform(node.left) || perform(node.right) + is BinaryPlusSyntax -> perform(node.left) || perform(node.right) + is BinaryMinusSyntax -> perform(node.left) || perform(node.right) is FractionSyntax -> true is RadicalWithIndexSyntax -> true - is MultiplicationSyntax -> perform0(node.left) || perform0(node.right) + is MultiplicationSyntax -> perform(node.left) || perform(node.right) } } - public override fun perform(node: MathSyntax) { - perform0(node) - } + perform(node) } /** @@ -203,8 +204,8 @@ public object BetterExponent : FeaturedMathRendererWithPostProcess.PostProcessSt */ @UnstableKMathAPI public class SimplifyParentheses(public val precedenceFunction: (MathSyntax) -> Int) : - FeaturedMathRendererWithPostProcess.PostProcessStage { - public override fun perform(node: MathSyntax): Unit = when (node) { + PostProcessPhase { + override fun perform(node: MathSyntax): Unit = when (node) { is NumberSyntax -> Unit is SymbolSyntax -> Unit is OperatorNameSyntax -> Unit 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 6209661b3..1edb5923e 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 @@ -11,7 +11,6 @@ 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.IntRing -import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke import kotlin.test.Test import kotlin.test.assertEquals @@ -22,7 +21,7 @@ internal class TestCompilerConsistencyWithInterpreter { val mst = MstRing { binaryOperationFunction("+")( unaryOperationFunction("+")( - (bindSymbol(x) - (2.toByte() + (scale( + (x - (2.toByte() + (scale( add(number(1), number(1)), 2.0, ) + 1.toByte()))) * 3.0 - 1.toByte() @@ -42,7 +41,7 @@ internal class TestCompilerConsistencyWithInterpreter { fun doubleField() = runCompilerTest { val mst = MstField { +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( - (3.0 - (bindSymbol(x) + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 + (3.0 - (x + (scale(add(number(1.0), number(1.0)), 2.0) + 1.0))) * 3 - 1.0 + number(1), number(1) / 2 + number(2.0) * one, ) + zero 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 073a03f14..929d17775 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 @@ -9,7 +9,6 @@ import space.kscience.kmath.expressions.MstExtendedField import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.invoke import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke import kotlin.test.Test import kotlin.test.assertEquals @@ -47,19 +46,19 @@ internal class TestCompilerOperations { @Test fun testSubtract() = runCompilerTest { - val expr = MstExtendedField { bindSymbol(x) - bindSymbol(x) }.compileToExpression(DoubleField) + val expr = MstExtendedField { x - x }.compileToExpression(DoubleField) assertEquals(0.0, expr(x to 2.0)) } @Test fun testDivide() = runCompilerTest { - val expr = MstExtendedField { bindSymbol(x) / bindSymbol(x) }.compileToExpression(DoubleField) + val expr = MstExtendedField { x / x }.compileToExpression(DoubleField) assertEquals(1.0, expr(x to 2.0)) } @Test fun testPower() = runCompilerTest { - val expr = MstExtendedField { bindSymbol(x) pow 2 }.compileToExpression(DoubleField) + val expr = MstExtendedField { x pow 2 }.compileToExpression(DoubleField) assertEquals(4.0, expr(x to 2.0)) } } 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 dcc15b311..af1a2e338 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 @@ -9,7 +9,6 @@ import space.kscience.kmath.expressions.MstRing import space.kscience.kmath.expressions.Symbol.Companion.x import space.kscience.kmath.expressions.invoke import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke import kotlin.test.Test import kotlin.test.assertEquals @@ -18,13 +17,13 @@ import kotlin.test.assertFailsWith internal class TestCompilerVariables { @Test fun testVariable() = runCompilerTest { - val expr = MstRing { bindSymbol(x) }.compileToExpression(IntRing) + val expr = MstRing { x }.compileToExpression(IntRing) assertEquals(1, expr(x to 1)) } @Test fun testUndefinedVariableFails() = runCompilerTest { - val expr = MstRing { bindSymbol(x) }.compileToExpression(IntRing) + val expr = MstRing { x }.compileToExpression(IntRing) assertFailsWith { expr() } } } 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 e5254013e..b62b8c06c 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 @@ -3,6 +3,8 @@ * 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("ClassName") + package space.kscience.kmath.internal.estree import kotlin.js.RegExp 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 95ace1bad..c89ad83c4 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 @@ -27,11 +27,7 @@ internal sealed class WasmBuilder( lateinit var ctx: BinaryenModule open fun visitSymbolic(mst: Symbol): ExpressionRef { - try { - algebra.bindSymbol(mst) - } catch (ignored: Throwable) { - null - }?.let { return visitNumeric(Numeric(it)) } + algebra.bindSymbolOrNull(mst)?.let { return visitNumeric(Numeric(it)) } var idx = keys.indexOf(mst) 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 index 6cb378182..d0e8128b4 100644 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt +++ b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt @@ -7,7 +7,6 @@ package space.kscience.kmath.ast import space.kscience.kmath.expressions.* import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.ExtendedField import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke import kotlin.math.sin @@ -17,18 +16,19 @@ 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 internal class TestExecutionTime { private companion object { private const val times = 1_000_000 private val x by symbol - private val algebra: ExtendedField = DoubleField + private val algebra = DoubleField private val functional = DoubleField.expressionInExtendedField { bindSymbol(x) * const(2.0) + const(2.0) / bindSymbol(x) - const(16.0) / sin(bindSymbol(x)) } private val node = MstExtendedField { - bindSymbol(x) * number(2.0) + number(2.0) / bindSymbol(x) - number(16.0) / sin(bindSymbol(x)) + x * number(2.0) + number(2.0) / x - number(16.0) / sin(x) } private val mst = node.toExpression(DoubleField) @@ -43,7 +43,13 @@ internal class TestExecutionTime { // }; private val raw = Expression { args -> - args.getValue(x) * 2.0 + 2.0 / args.getValue(x) - 16.0 / sin(args.getValue(x)) + val x = args[x]!! + 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) } } @@ -51,21 +57,56 @@ internal class TestExecutionTime { println(name) val rng = Random(0) var sum = 0.0 - measureTime { repeat(times) { sum += expr(x to rng.nextDouble()) } }.also(::println) + 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 93b7e9449..0d896c6f6 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 @@ -10,6 +10,8 @@ import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import space.kscience.kmath.estree.compile as estreeCompile import space.kscience.kmath.estree.compileToExpression as estreeCompileToExpression import space.kscience.kmath.wasm.compile as wasmCompile @@ -34,6 +36,7 @@ private object ESTreeCompilerTestContext : CompilerTestContext { } internal actual inline fun runCompilerTest(action: CompilerTestContext.() -> Unit) { + contract { callsInPlace(action, InvocationKind.AT_LEAST_ONCE) } action(WasmCompilerTestContext) action(ESTreeCompilerTestContext) } 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 abdf865c7..8ae5fcb36 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 @@ -11,7 +11,6 @@ import space.kscience.kmath.expressions.invoke import space.kscience.kmath.expressions.symbol import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.operations.bindSymbol import space.kscience.kmath.operations.invoke import kotlin.test.Test import kotlin.test.assertEquals @@ -31,7 +30,7 @@ internal class TestWasmSpecific { @Test fun argsPassing() { - val res = MstExtendedField { bindSymbol(y) + bindSymbol(x).pow(10) }.compile( + val res = MstExtendedField { y + x.pow(10) }.compile( DoubleField, x to 2.0, y to 100000000.0, @@ -42,7 +41,7 @@ internal class TestWasmSpecific { @Test fun powFunction() { - val expr = MstExtendedField { bindSymbol(x).pow(1.0 / 6.0) }.compileToExpression(DoubleField) + val expr = MstExtendedField { x.pow(1.0 / 6.0) }.compileToExpression(DoubleField) assertEquals(0.9730585187140817, expr(x to 0.8488554755054833)) } 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 cfac59847..06e040e93 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 @@ -57,13 +57,13 @@ internal fun MethodVisitor.label(): Label = Label().also(::visitLabel) /** * Creates a class name for [Expression] subclassed to implement [mst] provided. * - * This methods helps to avoid collisions of class name to prevent loading several classes with the same name. If there + * 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(mst: MST, collision: Int = 0): String { - val name = "kscience.kmath.asm.generated.AsmCompiledExpression_${mst.hashCode()}_$collision" + val name = "space.kscience.kmath.asm.generated.CompiledExpression_${mst.hashCode()}_$collision" try { Class.forName(name) 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 d3b554efd..a7f0bb3fb 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 @@ -10,6 +10,8 @@ import space.kscience.kmath.expressions.MST import space.kscience.kmath.expressions.Symbol import space.kscience.kmath.operations.DoubleField import space.kscience.kmath.operations.IntRing +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import space.kscience.kmath.asm.compile as asmCompile import space.kscience.kmath.asm.compileToExpression as asmCompileToExpression @@ -22,4 +24,7 @@ private object AsmCompilerTestContext : CompilerTestContext { asmCompile(algebra, arguments) } -internal actual inline fun runCompilerTest(action: CompilerTestContext.() -> Unit) = action(AsmCompilerTestContext) +internal actual inline fun runCompilerTest(action: CompilerTestContext.() -> Unit) { + contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } + action(AsmCompilerTestContext) +} 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 a7ee9ff3f..5417b6156 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 @@ -15,7 +15,7 @@ import space.kscience.kmath.operations.NumbersAddOperations * A field over commons-math [DerivativeStructure]. * * @property order The derivation order. - * @property bindings The map of bindings values. All bindings are considered free parameters + * @param bindings The map of bindings values. All bindings are considered free parameters */ @OptIn(UnstableKMathAPI::class) public class DerivativeStructureField( @@ -25,13 +25,13 @@ public class DerivativeStructureField( NumbersAddOperations { public val numberOfVariables: Int = bindings.size - public override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) } - public override val one: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order, 1.0) } + override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) } + override val one: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order, 1.0) } - public override fun number(value: Number): DerivativeStructure = const(value.toDouble()) + override fun number(value: Number): DerivativeStructure = const(value.toDouble()) /** - * A class that implements both [DerivativeStructure] and a [Symbol] + * A class implementing both [DerivativeStructure] and [Symbol]. */ public inner class DerivativeStructureSymbol( size: Int, @@ -39,10 +39,10 @@ public class DerivativeStructureField( symbol: Symbol, value: Double, ) : DerivativeStructure(size, order, index, value), Symbol { - public override val identity: String = symbol.identity - public override fun toString(): String = identity - public override fun equals(other: Any?): Boolean = this.identity == (other as? Symbol)?.identity - public override fun hashCode(): Int = identity.hashCode() + override val identity: String = symbol.identity + override fun toString(): String = identity + override fun equals(other: Any?): Boolean = this.identity == (other as? Symbol)?.identity + override fun hashCode(): Int = identity.hashCode() } /** @@ -52,10 +52,10 @@ public class DerivativeStructureField( key.identity to DerivativeStructureSymbol(numberOfVariables, index, key, value) }.toMap() - public override fun const(value: Double): DerivativeStructure = DerivativeStructure(numberOfVariables, order, value) + override fun const(value: Double): DerivativeStructure = DerivativeStructure(numberOfVariables, order, value) - public override fun bindSymbolOrNull(value: String): DerivativeStructureSymbol? = variables[value] - public override fun bindSymbol(value: String): DerivativeStructureSymbol = variables.getValue(value) + override fun bindSymbolOrNull(value: String): DerivativeStructureSymbol? = variables[value] + override fun bindSymbol(value: String): DerivativeStructureSymbol = variables.getValue(value) public fun bindSymbolOrNull(symbol: Symbol): DerivativeStructureSymbol? = variables[symbol.identity] public fun bindSymbol(symbol: Symbol): DerivativeStructureSymbol = variables.getValue(symbol.identity) @@ -68,45 +68,48 @@ public class DerivativeStructureField( public fun DerivativeStructure.derivative(vararg symbols: Symbol): Double = derivative(symbols.toList()) - public override fun DerivativeStructure.unaryMinus(): DerivativeStructure = negate() + override fun DerivativeStructure.unaryMinus(): DerivativeStructure = negate() - public override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b) + override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b) - public override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure = a.multiply(value) + override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure = a.multiply(value) - public override fun multiply(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.multiply(b) - public override fun divide(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.divide(b) - public override fun sin(arg: DerivativeStructure): DerivativeStructure = arg.sin() - public override fun cos(arg: DerivativeStructure): DerivativeStructure = arg.cos() - public override fun tan(arg: DerivativeStructure): DerivativeStructure = arg.tan() - public override fun asin(arg: DerivativeStructure): DerivativeStructure = arg.asin() - public override fun acos(arg: DerivativeStructure): DerivativeStructure = arg.acos() - public override fun atan(arg: DerivativeStructure): DerivativeStructure = arg.atan() - public override fun sinh(arg: DerivativeStructure): DerivativeStructure = arg.sinh() - public override fun cosh(arg: DerivativeStructure): DerivativeStructure = arg.cosh() - public override fun tanh(arg: DerivativeStructure): DerivativeStructure = arg.tanh() - public override fun asinh(arg: DerivativeStructure): DerivativeStructure = arg.asinh() - public override fun acosh(arg: DerivativeStructure): DerivativeStructure = arg.acosh() - public override fun atanh(arg: DerivativeStructure): DerivativeStructure = arg.atanh() + 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() + override fun asin(arg: DerivativeStructure): DerivativeStructure = arg.asin() + override fun acos(arg: DerivativeStructure): DerivativeStructure = arg.acos() + override fun atan(arg: DerivativeStructure): DerivativeStructure = arg.atan() + override fun sinh(arg: DerivativeStructure): DerivativeStructure = arg.sinh() + override fun cosh(arg: DerivativeStructure): DerivativeStructure = arg.cosh() + override fun tanh(arg: DerivativeStructure): DerivativeStructure = arg.tanh() + override fun asinh(arg: DerivativeStructure): DerivativeStructure = arg.asinh() + override fun acosh(arg: DerivativeStructure): DerivativeStructure = arg.acosh() + override fun atanh(arg: DerivativeStructure): DerivativeStructure = arg.atanh() - public override fun power(arg: DerivativeStructure, pow: Number): DerivativeStructure = when (pow) { + override fun power(arg: DerivativeStructure, pow: Number): DerivativeStructure = when (pow) { is Double -> arg.pow(pow) is Int -> arg.pow(pow) else -> arg.pow(pow.toDouble()) } public fun power(arg: DerivativeStructure, pow: DerivativeStructure): DerivativeStructure = arg.pow(pow) - public override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.exp() - public override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.log() + override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.exp() + override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.log() - public override operator fun DerivativeStructure.plus(b: Number): DerivativeStructure = add(b.toDouble()) - public override operator fun DerivativeStructure.minus(b: Number): DerivativeStructure = subtract(b.toDouble()) - public override operator fun Number.plus(b: DerivativeStructure): DerivativeStructure = b + this - public override operator fun Number.minus(b: DerivativeStructure): DerivativeStructure = b - 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 { - public override fun differentiate( + override fun differentiate( function: DerivativeStructureField.() -> DerivativeStructure, ): DerivativeStructureExpression = DerivativeStructureExpression(function) } @@ -117,13 +120,13 @@ public object DSProcessor : AutoDiffProcessor DerivativeStructure, ) : DifferentiableExpression { - public override operator fun invoke(arguments: Map): Double = + override operator fun invoke(arguments: Map): Double = DerivativeStructureField(0, arguments).function().value /** * Get the derivative expression with given orders */ - public override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> + override fun derivativeOrNull(symbols: List): Expression = Expression { arguments -> with(DerivativeStructureField(symbols.size, arguments)) { function().derivative(symbols) } } } 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 c6f1cd852..c7a253ff7 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 @@ -15,18 +15,18 @@ import kotlin.reflect.KClass import kotlin.reflect.cast public class CMMatrix(public val origin: RealMatrix) : Matrix { - public override val rowNum: Int get() = origin.rowDimension - public override val colNum: Int get() = origin.columnDimension + override val rowNum: Int get() = origin.rowDimension + override val colNum: Int get() = origin.columnDimension - public override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j) + override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j) } public class CMVector(public val origin: RealVector) : Point { - public override val size: Int get() = origin.dimension + override val size: Int get() = origin.dimension - public override operator fun get(index: Int): Double = origin.getEntry(index) + override operator fun get(index: Int): Double = origin.getEntry(index) - public override operator fun iterator(): Iterator = origin.toArray().iterator() + override operator fun iterator(): Iterator = origin.toArray().iterator() } public fun RealVector.toPoint(): CMVector = CMVector(this) @@ -34,7 +34,7 @@ public fun RealVector.toPoint(): CMVector = CMVector(this) public object CMLinearSpace : LinearSpace { override val elementAlgebra: DoubleField get() = DoubleField - public override fun buildMatrix( + override fun buildMatrix( rows: Int, columns: Int, initializer: DoubleField.(i: Int, j: Int) -> Double, @@ -73,16 +73,16 @@ public object CMLinearSpace : LinearSpace { override fun Point.minus(other: Point): CMVector = toCM().origin.subtract(other.toCM().origin).wrap() - public override fun Matrix.dot(other: Matrix): CMMatrix = + override fun Matrix.dot(other: Matrix): CMMatrix = toCM().origin.multiply(other.toCM().origin).wrap() - public override fun Matrix.dot(vector: Point): CMVector = + override fun Matrix.dot(vector: Point): CMVector = toCM().origin.preMultiply(vector.toCM().origin).wrap() - public override operator fun Matrix.minus(other: Matrix): CMMatrix = + override operator fun Matrix.minus(other: Matrix): CMMatrix = toCM().origin.subtract(other.toCM().origin).wrap() - public override operator fun Matrix.times(value: Double): CMMatrix = + override operator fun Matrix.times(value: Double): CMMatrix = toCM().origin.scalarMultiply(value).wrap() override fun Double.times(m: Matrix): CMMatrix = 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 16a6967e2..6aeebb68c 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 @@ -5,35 +5,43 @@ package space.kscience.kmath.commons.random +import kotlinx.coroutines.runBlocking +import space.kscience.kmath.misc.PerformancePitfall +import space.kscience.kmath.samplers.GaussianSampler +import space.kscience.kmath.misc.toIntExact import space.kscience.kmath.stat.RandomGenerator +import space.kscience.kmath.stat.next public class CMRandomGeneratorWrapper( public val factory: (IntArray) -> RandomGenerator, ) : org.apache.commons.math3.random.RandomGenerator { private var generator: RandomGenerator = factory(intArrayOf()) - public override fun nextBoolean(): Boolean = generator.nextBoolean() - public override fun nextFloat(): Float = generator.nextDouble().toFloat() + override fun nextBoolean(): Boolean = generator.nextBoolean() + override fun nextFloat(): Float = generator.nextDouble().toFloat() - public override fun setSeed(seed: Int) { + override fun setSeed(seed: Int) { generator = factory(intArrayOf(seed)) } - public override fun setSeed(seed: IntArray) { + override fun setSeed(seed: IntArray) { generator = factory(seed) } - public override fun setSeed(seed: Long) { - setSeed(seed.toInt()) + override fun setSeed(seed: Long) { + setSeed(seed.toIntExact()) } - public override fun nextBytes(bytes: ByteArray) { + override fun nextBytes(bytes: ByteArray) { generator.fillBytes(bytes) } - public override fun nextInt(): Int = generator.nextInt() - public override fun nextInt(n: Int): Int = generator.nextInt(n) - public override fun nextGaussian(): Double = TODO() - public override fun nextDouble(): Double = generator.nextDouble() - public override fun nextLong(): Long = generator.nextLong() + 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 d29491d63..6fef12138 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 @@ -32,7 +32,7 @@ public object Transformations { /** * Create a virtual buffer on top of array */ - private fun Array.asBuffer() = VirtualBuffer(size) { + private fun Array.asBuffer() = VirtualBuffer(size) { val value = get(it) Complex(value.real, value.imaginary) } 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 966675062..3c57f5467 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 @@ -16,7 +16,7 @@ internal inline fun diff( order: Int, vararg parameters: Pair, block: DerivativeStructureField.() -> Unit, -): Unit { +) { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } DerivativeStructureField(order, mapOf(*parameters)).run(block) } @@ -34,7 +34,7 @@ internal class AutoDiffTest { println(z.derivative(x)) println(z.derivative(y, x)) assertEquals(z.derivative(x, y), z.derivative(y, x)) - //check that improper order cause failure + // check improper order cause failure assertFails { z.derivative(x, x, y) } } } 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 97761cfa2..170fceceb 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 @@ -11,9 +11,12 @@ 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.optimization.* import space.kscience.kmath.stat.RandomGenerator +import space.kscience.kmath.structures.asBuffer +import space.kscience.kmath.structures.map import kotlin.math.pow import kotlin.test.Test @@ -49,26 +52,27 @@ 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) + val x = (1..100).map(Int::toDouble).asBuffer() val y = x.map { it.pow(2) + it + 1 + chain.next() } - val yErr = List(x.size) { sigma } + val yErr = List(x.size) { sigma }.asBuffer() - val model = DSProcessor.differentiate { x1 -> + val chi2 = DSProcessor.chiSquaredExpression( + x, y, yErr + ) { arg -> val cWithDefault = bindSymbolOrNull(c) ?: one - bindSymbol(a) * x1.pow(2) + bindSymbol(b) * x1 + cWithDefault + bindSymbol(a) * arg.pow(2) + bindSymbol(b) * arg + cWithDefault } - val chi2 = FunctionOptimization.chiSquared(x, y, yErr) { x1 -> - val cWithDefault = bindSymbolOrNull(c) ?: one - bindSymbol(a) * x1.pow(2) + bindSymbol(b) * x1 + cWithDefault - } - - val result = chi2.minimize(a to 1.5, b to 0.9, c to 1.0) + val result: FunctionOptimization = chi2.optimizeWith( + CMOptimizer, + mapOf(a to 1.5, b to 0.9, c to 1.0), + FunctionOptimizationTarget.MINIMIZE + ) println(result) - println("Chi2/dof = ${result.value / (x.size - 3)}") + println("Chi2/dof = ${result.resultValue / (x.size - 3)}") } } diff --git a/kmath-complex/README.md b/kmath-complex/README.md index 04431cf6c..110529b72 100644 --- a/kmath-complex/README.md +++ b/kmath-complex/README.md @@ -8,7 +8,7 @@ Complex and hypercomplex number systems in KMath. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-14`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-complex:0.3.0-dev-11' + 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-11") + 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 a96d046c9..8b064a05f 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 @@ -54,8 +54,8 @@ private val PI_DIV_2 = Complex(PI / 2, 0) @OptIn(UnstableKMathAPI::class) public object ComplexField : ExtendedField, Norm, NumbersAddOperations, ScaleOperations { - public override val zero: Complex = 0.0.toComplex() - public override val one: Complex = 1.0.toComplex() + override val zero: Complex = 0.0.toComplex() + override val one: Complex = 1.0.toComplex() /** * The imaginary unit. @@ -68,13 +68,13 @@ public object ComplexField : ExtendedField, Norm, Num override fun scale(a: Complex, value: Double): Complex = Complex(a.re * value, a.im * value) - public override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im) -// public override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble()) + 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()) - public override fun multiply(a: Complex, b: Complex): Complex = + 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) - public override fun divide(a: Complex, b: Complex): Complex = when { + 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 @@ -100,31 +100,31 @@ public object ComplexField : ExtendedField, Norm, Num override operator fun Complex.div(k: Number): Complex = Complex(re / k.toDouble(), im / k.toDouble()) - public override fun sin(arg: Complex): Complex = i * (exp(-i * arg) - exp(i * arg)) / 2.0 - public override fun cos(arg: Complex): Complex = (exp(-i * arg) + exp(i * arg)) / 2.0 + override fun sin(arg: Complex): Complex = i * (exp(-i * arg) - exp(i * arg)) / 2.0 + override fun cos(arg: Complex): Complex = (exp(-i * arg) + exp(i * arg)) / 2.0 - public override fun tan(arg: Complex): Complex { + override fun tan(arg: Complex): Complex { val e1 = exp(-i * arg) val e2 = exp(i * arg) return i * (e1 - e2) / (e1 + e2) } - public override fun asin(arg: Complex): Complex = -i * ln(sqrt(1 - (arg * arg)) + i * arg) - public override fun acos(arg: Complex): Complex = PI_DIV_2 + i * ln(sqrt(1 - (arg * arg)) + i * arg) + override fun asin(arg: Complex): Complex = -i * ln(sqrt(1 - (arg * arg)) + i * arg) + override fun acos(arg: Complex): Complex = PI_DIV_2 + i * ln(sqrt(1 - (arg * arg)) + i * arg) - public override fun atan(arg: Complex): Complex { + override fun atan(arg: Complex): Complex { val iArg = i * arg return i * (ln(1 - iArg) - ln(1 + iArg)) / 2 } - public 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 exp(pow * ln(arg)) - public override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im)) + override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im)) - public override fun ln(arg: Complex): Complex = ln(arg.r) + i * atan2(arg.im, arg.re) + override fun ln(arg: Complex): Complex = ln(arg.r) + i * atan2(arg.im, arg.re) /** * Adds complex number to real one. @@ -171,9 +171,9 @@ public object ComplexField : ExtendedField, Norm, Num */ public operator fun Double.times(c: Complex): Complex = Complex(c.re * this, c.im * this) - public override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg) + override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg) - public override fun bindSymbolOrNull(value: String): Complex? = if (value == "i") i else null + override fun bindSymbolOrNull(value: String): Complex? = if (value == "i") i else null } /** @@ -187,16 +187,16 @@ public data class Complex(val re: Double, val im: Double) { public constructor(re: Number, im: Number) : this(re.toDouble(), im.toDouble()) public constructor(re: Number) : this(re.toDouble(), 0.0) - public override fun toString(): String = "($re + i * $im)" + override fun toString(): String = "($re + i * $im)" public companion object : MemorySpec { - public override val objectSize: Int + override val objectSize: Int get() = 16 - public override fun MemoryReader.read(offset: Int): Complex = + override fun MemoryReader.read(offset: Int): Complex = Complex(readDouble(offset), readDouble(offset + 8)) - public override fun MemoryWriter.write(offset: Int, value: Complex) { + override fun MemoryWriter.write(offset: Int, value: Complex) { writeDouble(offset, value.re) writeDouble(offset + 8, value.im) } 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 2c783eda0..1b54fc227 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 @@ -27,10 +27,10 @@ public class ComplexFieldND( NumbersAddOperations>, ExtendedField> { - public override val zero: BufferND by lazy { produce { zero } } - public override val one: BufferND by lazy { produce { one } } + override val zero: BufferND by lazy { produce { zero } } + override val one: BufferND by lazy { produce { one } } - public override fun number(value: Number): BufferND { + override fun number(value: Number): BufferND { val d = value.toComplex() // minimize conversions return produce { d } } @@ -81,25 +81,25 @@ public class ComplexFieldND( // return BufferedNDFieldElement(this, buffer) // } - public override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) } + override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) } - public override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } + override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } - public override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } + override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } - public override fun sin(arg: StructureND): BufferND = arg.map { sin(it) } - public override fun cos(arg: StructureND): BufferND = arg.map { cos(it) } - public override fun tan(arg: StructureND): BufferND = arg.map { tan(it) } - public override fun asin(arg: StructureND): BufferND = arg.map { asin(it) } - public override fun acos(arg: StructureND): BufferND = arg.map { acos(it) } - public override fun atan(arg: StructureND): BufferND = arg.map { atan(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) } - public override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) } - public override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) } - public override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) } - public override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) } - public override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) } - public override fun atanh(arg: StructureND): BufferND = arg.map { atanh(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) } } 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 c59aabdcb..423cef1d1 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 @@ -63,20 +63,20 @@ public object QuaternionField : Field, Norm, */ public val k: Quaternion = Quaternion(0, 0, 0, 1) - public override fun add(a: Quaternion, b: Quaternion): Quaternion = + 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) - public override fun scale(a: Quaternion, value: Double): Quaternion = + override fun scale(a: Quaternion, value: Double): Quaternion = Quaternion(a.w * value, a.x * value, a.y * value, a.z * value) - public override fun multiply(a: Quaternion, b: Quaternion): Quaternion = Quaternion( + 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, ) - public override fun divide(a: Quaternion, b: Quaternion): Quaternion { + 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( @@ -87,7 +87,7 @@ public object QuaternionField : Field, Norm, ) } - public override fun power(arg: Quaternion, pow: Number): Quaternion { + override fun power(arg: Quaternion, pow: Number): Quaternion { if (pow is Int) return pwr(arg, pow) if (floor(pow.toDouble()) == pow.toDouble()) return pwr(arg, pow.toInt()) return exp(pow * ln(arg)) @@ -131,7 +131,7 @@ public object QuaternionField : Field, Norm, return Quaternion(a2 * a2 - 6 * a2 * n1 + n1 * n1, x.x * n2, x.y * n2, x.z * n2) } - public override fun exp(arg: Quaternion): Quaternion { + override fun exp(arg: Quaternion): Quaternion { val un = arg.x * arg.x + arg.y * arg.y + arg.z * arg.z if (un == 0.0) return exp(arg.w).toQuaternion() val n1 = sqrt(un) @@ -140,14 +140,14 @@ public object QuaternionField : Field, Norm, return Quaternion(ea * cos(n1), n2 * arg.x, n2 * arg.y, n2 * arg.z) } - public override fun ln(arg: Quaternion): Quaternion { + override fun ln(arg: Quaternion): Quaternion { val nu2 = arg.x * arg.x + arg.y * arg.y + arg.z * arg.z if (nu2 == 0.0) return if (arg.w > 0) Quaternion(ln(arg.w), 0, 0, 0) else { - val l = ComplexField { ComplexField.ln(arg.w.toComplex()) } + val l = ComplexField { ln(arg.w.toComplex()) } Quaternion(l.re, l.im, 0, 0) } @@ -158,21 +158,21 @@ public object QuaternionField : Field, Norm, return Quaternion(ln(n), th * arg.x, th * arg.y, th * arg.z) } - public override operator fun Number.plus(b: Quaternion): Quaternion = Quaternion(toDouble() + b.w, b.x, b.y, b.z) + override operator fun Number.plus(b: Quaternion): Quaternion = Quaternion(toDouble() + b.w, b.x, b.y, b.z) - public override operator fun Number.minus(b: Quaternion): Quaternion = + override operator fun Number.minus(b: Quaternion): Quaternion = Quaternion(toDouble() - b.w, -b.x, -b.y, -b.z) - public override operator fun Quaternion.plus(b: Number): Quaternion = Quaternion(w + b.toDouble(), x, y, z) - public override operator fun Quaternion.minus(b: Number): Quaternion = Quaternion(w - b.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) - public override operator fun Number.times(b: Quaternion): Quaternion = + override operator fun Number.times(b: Quaternion): Quaternion = Quaternion(toDouble() * b.w, toDouble() * b.x, toDouble() * b.y, toDouble() * b.z) - public override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z) - public override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg) + override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z) + override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg) - public override fun bindSymbolOrNull(value: String): Quaternion? = when (value) { + override fun bindSymbolOrNull(value: String): Quaternion? = when (value) { "i" -> i "j" -> j "k" -> k @@ -181,12 +181,12 @@ public object QuaternionField : Field, Norm, override fun number(value: Number): Quaternion = value.toQuaternion() - public override fun sinh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / 2.0 - public override fun cosh(arg: Quaternion): Quaternion = (exp(arg) + exp(-arg)) / 2.0 - public override fun tanh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) - public override fun asinh(arg: Quaternion): Quaternion = ln(sqrt(arg * arg + one) + arg) - public override fun acosh(arg: Quaternion): Quaternion = ln(arg + sqrt((arg - one) * (arg + one))) - public override fun atanh(arg: Quaternion): Quaternion = (ln(arg + one) - ln(one - arg)) / 2.0 + override fun sinh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / 2.0 + override fun cosh(arg: Quaternion): Quaternion = (exp(arg) + exp(-arg)) / 2.0 + override fun tanh(arg: Quaternion): Quaternion = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) + override fun asinh(arg: Quaternion): Quaternion = ln(sqrt(arg * arg + one) + arg) + override fun acosh(arg: Quaternion): Quaternion = ln(arg + sqrt((arg - one) * (arg + one))) + override fun atanh(arg: Quaternion): Quaternion = (ln(arg + one) - ln(one - arg)) / 2.0 } /** @@ -224,16 +224,16 @@ public data class Quaternion( /** * Returns a string representation of this quaternion. */ - public override fun toString(): String = "($w + $x * i + $y * j + $z * k)" + override fun toString(): String = "($w + $x * i + $y * j + $z * k)" public companion object : MemorySpec { - public override val objectSize: Int + override val objectSize: Int get() = 32 - public override fun MemoryReader.read(offset: Int): Quaternion = + override fun MemoryReader.read(offset: Int): Quaternion = Quaternion(readDouble(offset), readDouble(offset + 8), readDouble(offset + 16), readDouble(offset + 24)) - public override fun MemoryWriter.write(offset: Int, value: Quaternion) { + override fun MemoryWriter.write(offset: Int, value: Quaternion) { writeDouble(offset, value.w) writeDouble(offset + 8, value.x) writeDouble(offset + 16, value.y) diff --git a/kmath-core/README.md b/kmath-core/README.md index 700eaef38..4ea493f44 100644 --- a/kmath-core/README.md +++ b/kmath-core/README.md @@ -10,12 +10,12 @@ The core interfaces of KMath. objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high performance calculations to code generation. - [domains](src/commonMain/kotlin/space/kscience/kmath/domains) : Domains - - [autodif](src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation + - [autodiff](src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-core:0.3.0-dev-14`. **Gradle:** ```gradle @@ -25,7 +25,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-core:0.3.0-dev-11' + 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-11") + 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 92a5f419d..564d06f49 100644 --- a/kmath-core/build.gradle.kts +++ b/kmath-core/build.gradle.kts @@ -19,51 +19,42 @@ readme { feature( id = "algebras", - description = """ - Algebraic structures like rings, spaces and fields. - """.trimIndent(), - ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt" - ) + ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt", + ) { "Algebraic structures like rings, spaces and fields." } feature( id = "nd", - description = "Many-dimensional structures and operations on them.", - ref = "src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt" - ) + ref = "src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt", + ) { "Many-dimensional structures and operations on them." } feature( id = "linear", - description = """ - Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition. - """.trimIndent(), - ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt" - ) + ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt", + ) { "Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. Advanced linear algebra operations like matrix inversion and LU decomposition." } feature( id = "buffers", - description = "One-dimensional structure", - ref = "src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt" - ) + ref = "src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt", + ) { "One-dimensional structure" } feature( id = "expressions", - description = """ + ref = "src/commonMain/kotlin/space/kscience/kmath/expressions" + ) { + """ By writing a single mathematical expression once, users will be able to apply different types of objects to the expression by providing a context. Expressions can be used for a wide variety of purposes from high performance calculations to code generation. - """.trimIndent(), - ref = "src/commonMain/kotlin/space/kscience/kmath/expressions" - ) + """.trimIndent() + } feature( id = "domains", - description = "Domains", - ref = "src/commonMain/kotlin/space/kscience/kmath/domains" - ) + ref = "src/commonMain/kotlin/space/kscience/kmath/domains", + ) { "Domains" } feature( - id = "autodif", - description = "Automatic differentiation", + id = "autodiff", ref = "src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt" - ) + ) { "Automatic differentiation" } } 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 2dc82c02e..bd0e13b9d 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 @@ -16,7 +16,7 @@ import kotlin.math.max * The buffer of X values. */ @UnstableKMathAPI -public interface XYColumnarData : ColumnarData { +public interface XYColumnarData : ColumnarData { /** * The buffer of X values */ 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 bc21b7f45..e99ae0698 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 @@ -14,7 +14,7 @@ import space.kscience.kmath.structures.Buffer * Inherits [XYColumnarData]. */ @UnstableKMathAPI -public interface XYZColumnarData : XYColumnarData { +public interface XYZColumnarData : XYColumnarData { public val z: Buffer override fun get(symbol: Symbol): Buffer? = when (symbol) { @@ -23,4 +23,4 @@ public interface XYZColumnarData : XYColumna Symbol.z -> z else -> null } -} \ No newline at end of file +} 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 e6e703cbf..b5a84cf6c 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 @@ -12,7 +12,7 @@ import space.kscience.kmath.linear.Point * * @param T the type of element of this domain. */ -public interface Domain { +public interface Domain { /** * Checks if the specified point is contained in this domain. */ 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 f5560d935..bd5514623 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 @@ -17,17 +17,17 @@ import space.kscience.kmath.structures.indices */ @UnstableKMathAPI public class HyperSquareDomain(private val lower: Buffer, private val upper: Buffer) : DoubleDomain { - public override val dimension: Int get() = lower.size + override val dimension: Int get() = lower.size - public override operator fun contains(point: Point): Boolean = point.indices.all { i -> + override operator fun contains(point: Point): Boolean = point.indices.all { i -> point[i] in lower[i]..upper[i] } - public override fun getLowerBound(num: Int): Double = lower[num] + override fun getLowerBound(num: Int): Double = lower[num] - public override fun getUpperBound(num: Int): Double = upper[num] + override fun getUpperBound(num: Int): Double = upper[num] - public override fun volume(): Double { + override fun volume(): Double { var res = 1.0 for (i in 0 until dimension) { 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 7ffc0659d..32a5fc56c 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 @@ -8,12 +8,12 @@ import space.kscience.kmath.linear.Point import space.kscience.kmath.misc.UnstableKMathAPI @UnstableKMathAPI -public class UnconstrainedDomain(public override val dimension: Int) : DoubleDomain { - public override operator fun contains(point: Point): Boolean = true +public class UnconstrainedDomain(override val dimension: Int) : DoubleDomain { + override operator fun contains(point: Point): Boolean = true - public override fun getLowerBound(num: Int): Double = Double.NEGATIVE_INFINITY + override fun getLowerBound(num: Int): Double = Double.NEGATIVE_INFINITY - public override fun getUpperBound(num: Int): Double = Double.POSITIVE_INFINITY + override fun getUpperBound(num: Int): Double = Double.POSITIVE_INFINITY - public override fun volume(): Double = Double.POSITIVE_INFINITY + override fun volume(): Double = Double.POSITIVE_INFINITY } 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 e7acada85..9020ef8cb 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 @@ -10,24 +10,24 @@ import space.kscience.kmath.misc.UnstableKMathAPI @UnstableKMathAPI public class UnivariateDomain(public val range: ClosedFloatingPointRange) : DoubleDomain { - public override val dimension: Int get() = 1 + override val dimension: Int get() = 1 public operator fun contains(d: Double): Boolean = range.contains(d) - public override operator fun contains(point: Point): Boolean { + override operator fun contains(point: Point): Boolean { require(point.size == 0) return contains(point[0]) } - public override fun getLowerBound(num: Int): Double { + override fun getLowerBound(num: Int): Double { require(num == 0) return range.start } - public override fun getUpperBound(num: Int): Double { + override fun getUpperBound(num: Int): Double { require(num == 0) return range.endInclusive } - public override fun volume(): Double = range.endInclusive - range.start + override fun volume(): Double = range.endInclusive - range.start } 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 1782ff406..12b7df0ea 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 @@ -8,10 +8,9 @@ package space.kscience.kmath.expressions import space.kscience.kmath.operations.Algebra /** - * Represents expression which structure can be differentiated. + * Represents expression, which structure can be differentiated. * * @param T the type this expression takes as argument and returns. - * @param R the type of expression this expression can be differentiated to. */ public interface DifferentiableExpression : Expression { /** @@ -26,16 +25,18 @@ public interface DifferentiableExpression : Expression { public fun DifferentiableExpression.derivative(symbols: List): Expression = derivativeOrNull(symbols) ?: error("Derivative by symbols $symbols not provided") -public fun DifferentiableExpression.derivative(vararg symbols: Symbol): Expression = +public fun DifferentiableExpression.derivative(vararg symbols: Symbol): Expression = derivative(symbols.toList()) -public fun DifferentiableExpression.derivative(name: String): Expression = +public fun DifferentiableExpression.derivative(name: String): Expression = derivative(StringSymbol(name)) /** - * A special type of [DifferentiableExpression] which returns typed expressions as derivatives + * A special type of [DifferentiableExpression] which returns typed expressions as derivatives. + * + * @param R the type of expression this expression can be differentiated to. */ -public interface SpecialDifferentiableExpression>: DifferentiableExpression { +public interface SpecialDifferentiableExpression> : DifferentiableExpression { override fun derivativeOrNull(symbols: List): R? } @@ -55,9 +56,9 @@ public abstract class FirstDerivativeExpression : DifferentiableExpression /** * Returns first derivative of this expression by given [symbol]. */ - public abstract fun derivativeOrNull(symbol: Symbol): Expression? + public abstract fun derivativeOrNull(symbol: Symbol): Expression? - public final override fun derivativeOrNull(symbols: List): Expression? { + public final override fun derivativeOrNull(symbols: List): Expression? { val dSymbol = symbols.firstOrNull() ?: return null return derivativeOrNull(dSymbol) } @@ -69,6 +70,6 @@ public abstract class FirstDerivativeExpression : DifferentiableExpression * @param I type of the actual expression state * @param A type of expression algebra */ -public fun interface AutoDiffProcessor> { +public fun interface AutoDiffProcessor> { public fun differentiate(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 84e66918f..5105c2bec 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 @@ -43,7 +43,7 @@ public operator fun Expression.invoke(vararg pairs: Pair): T = /** * Calls this expression from arguments. * - * @param pairs the pairs of arguments' names to values. + * @param pairs the pairs of arguments' names to value. * @return a value. */ @JvmName("callByString") @@ -60,7 +60,7 @@ public operator fun Expression.invoke(vararg pairs: Pair): T = public interface ExpressionAlgebra : Algebra { /** - * A constant expression which does not depend on arguments + * A constant expression that does not depend on arguments. */ public fun const(value: T): E } 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 951ec9474..838118339 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 @@ -6,43 +6,39 @@ package space.kscience.kmath.expressions import space.kscience.kmath.operations.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract /** * A context class for [Expression] construction. * * @param algebra The algebra to provide for Expressions built. */ -public abstract class FunctionalExpressionAlgebra>( +public abstract class FunctionalExpressionAlgebra>( public val algebra: A, ) : ExpressionAlgebra> { /** - * Builds an Expression of constant expression which does not depend on arguments. + * Builds an Expression of constant expression that does not depend on arguments. */ - public override fun const(value: T): Expression = Expression { value } + override fun const(value: T): Expression = Expression { value } /** * Builds an Expression to access a variable. */ - public override fun bindSymbolOrNull(value: String): Expression? = Expression { arguments -> + override fun bindSymbolOrNull(value: String): Expression? = Expression { arguments -> algebra.bindSymbolOrNull(value) ?: arguments[StringSymbol(value)] ?: error("Symbol '$value' is not supported in $this") } - /** - * Builds an Expression of dynamic call of binary operation [operation] on [left] and [right]. - */ - public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = { left, right -> Expression { arguments -> algebra.binaryOperationFunction(operation)(left.invoke(arguments), right.invoke(arguments)) } } - /** - * Builds an Expression of dynamic call of unary operation with name [operation] on [arg]. - */ - public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = { arg -> + override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = { arg -> Expression { arguments -> algebra.unaryOperationFunction(operation)(arg.invoke(arguments)) } } } @@ -50,24 +46,24 @@ public abstract class FunctionalExpressionAlgebra>( /** * A context class for [Expression] construction for [Ring] algebras. */ -public open class FunctionalExpressionGroup>( +public open class FunctionalExpressionGroup>( algebra: A, ) : FunctionalExpressionAlgebra(algebra), Group> { - public override val zero: Expression get() = const(algebra.zero) + override val zero: Expression get() = const(algebra.zero) - public override fun Expression.unaryMinus(): Expression = + override fun Expression.unaryMinus(): Expression = unaryOperation(GroupOperations.MINUS_OPERATION, this) /** * Builds an Expression of addition of two another expressions. */ - public override fun add(a: Expression, b: Expression): Expression = + override fun add(a: Expression, b: Expression): Expression = binaryOperation(GroupOperations.PLUS_OPERATION, a, b) // /** // * Builds an Expression of multiplication of expression by number. // */ -// public override fun multiply(a: Expression, k: Number): Expression = Expression { arguments -> +// override fun multiply(a: Expression, k: Number): Expression = Expression { arguments -> // algebra.multiply(a.invoke(arguments), k) // } @@ -76,110 +72,122 @@ public open class FunctionalExpressionGroup>( public operator fun T.plus(arg: Expression): Expression = arg + this public operator fun T.minus(arg: Expression): Expression = arg - this - public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = super.unaryOperationFunction(operation) - public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = super.binaryOperationFunction(operation) } -public open class FunctionalExpressionRing>( +public open class FunctionalExpressionRing>( algebra: A, ) : FunctionalExpressionGroup(algebra), Ring> { - public override val one: Expression get() = const(algebra.one) + override val one: Expression get() = const(algebra.one) /** * Builds an Expression of multiplication of two expressions. */ - public override fun multiply(a: Expression, b: Expression): Expression = + 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 - public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = super.unaryOperationFunction(operation) - public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = super.binaryOperationFunction(operation) } -public open class FunctionalExpressionField>( +public open class FunctionalExpressionField>( algebra: A, ) : FunctionalExpressionRing(algebra), Field>, ScaleOperations> { /** * Builds an Expression of division an expression by another one. */ - public override fun divide(a: Expression, b: Expression): Expression = + 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 - public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = super.unaryOperationFunction(operation) - public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = super.binaryOperationFunction(operation) - public override fun scale(a: Expression, value: Double): Expression = algebra { + override fun scale(a: Expression, value: Double): Expression = algebra { Expression { args -> a(args) * value } } - public override fun bindSymbolOrNull(value: String): Expression? = + override fun bindSymbolOrNull(value: String): Expression? = super.bindSymbolOrNull(value) } -public open class FunctionalExpressionExtendedField>( +public open class FunctionalExpressionExtendedField>( algebra: A, ) : FunctionalExpressionField(algebra), ExtendedField> { - public override fun number(value: Number): Expression = const(algebra.number(value)) + override fun number(value: Number): Expression = const(algebra.number(value)) - public override fun sqrt(arg: Expression): Expression = + override fun sqrt(arg: Expression): Expression = unaryOperationFunction(PowerOperations.SQRT_OPERATION)(arg) - public override fun sin(arg: Expression): Expression = + override fun sin(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg) - public override fun cos(arg: Expression): Expression = + override fun cos(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg) - public override fun asin(arg: Expression): Expression = + override fun asin(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.ASIN_OPERATION)(arg) - public override fun acos(arg: Expression): Expression = + override fun acos(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.ACOS_OPERATION)(arg) - public override fun atan(arg: Expression): Expression = + override fun atan(arg: Expression): Expression = unaryOperationFunction(TrigonometricOperations.ATAN_OPERATION)(arg) - public override fun power(arg: Expression, pow: Number): Expression = + override fun power(arg: Expression, pow: Number): Expression = binaryOperationFunction(PowerOperations.POW_OPERATION)(arg, number(pow)) - public override fun exp(arg: Expression): Expression = + override fun exp(arg: Expression): Expression = unaryOperationFunction(ExponentialOperations.EXP_OPERATION)(arg) - public override fun ln(arg: Expression): Expression = + override fun ln(arg: Expression): Expression = unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg) - public override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = + override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = super.unaryOperationFunction(operation) - public override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = + override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = super.binaryOperationFunction(operation) - public override fun bindSymbol(value: String): Expression = super.bindSymbol(value) + override fun bindSymbol(value: String): Expression = super.bindSymbol(value) } -public inline fun > A.expressionInSpace(block: FunctionalExpressionGroup.() -> Expression): Expression = - FunctionalExpressionGroup(this).block() +public inline fun > A.expressionInGroup( + block: FunctionalExpressionGroup.() -> Expression, +): Expression { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return FunctionalExpressionGroup(this).block() +} -public inline fun > A.expressionInRing(block: FunctionalExpressionRing.() -> Expression): Expression = - FunctionalExpressionRing(this).block() +public inline fun > A.expressionInRing( + block: FunctionalExpressionRing.() -> Expression, +): Expression { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return FunctionalExpressionRing(this).block() +} -public inline fun > A.expressionInField(block: FunctionalExpressionField.() -> Expression): Expression = - FunctionalExpressionField(this).block() +public inline fun > A.expressionInField( + block: FunctionalExpressionField.() -> Expression, +): Expression { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return FunctionalExpressionField(this).block() +} public inline fun > A.expressionInExtendedField( block: FunctionalExpressionExtendedField.() -> Expression, 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 4729f19ea..d8489e30c 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 @@ -12,14 +12,14 @@ import space.kscience.kmath.operations.* * [Algebra] over [MST] nodes. */ public object MstNumericAlgebra : NumericAlgebra { - public override fun number(value: Number): MST.Numeric = MST.Numeric(value) - public override fun bindSymbolOrNull(value: String): Symbol = StringSymbol(value) + override fun number(value: Number): MST.Numeric = MST.Numeric(value) + override fun bindSymbolOrNull(value: String): Symbol = StringSymbol(value) override fun bindSymbol(value: String): Symbol = bindSymbolOrNull(value) - public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = { arg -> MST.Unary(operation, arg) } - public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = { left, right -> MST.Binary(operation, left, right) } } @@ -27,27 +27,27 @@ public object MstNumericAlgebra : NumericAlgebra { * [Group] over [MST] nodes. */ public object MstGroup : Group, NumericAlgebra, ScaleOperations { - public override val zero: MST.Numeric = number(0.0) + override val zero: MST.Numeric = number(0.0) - public override fun number(value: Number): MST.Numeric = MstNumericAlgebra.number(value) - public override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - public override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(GroupOperations.PLUS_OPERATION)(a, b) - public override operator fun MST.unaryPlus(): MST.Unary = + override fun number(value: Number): MST.Numeric = MstNumericAlgebra.number(value) + override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) + override fun add(a: MST, b: MST): MST.Binary = binaryOperationFunction(GroupOperations.PLUS_OPERATION)(a, b) + override operator fun MST.unaryPlus(): MST.Unary = unaryOperationFunction(GroupOperations.PLUS_OPERATION)(this) - public override operator fun MST.unaryMinus(): MST.Unary = + override operator fun MST.unaryMinus(): MST.Unary = unaryOperationFunction(GroupOperations.MINUS_OPERATION)(this) - public override operator fun MST.minus(b: MST): MST.Binary = + override operator fun MST.minus(b: MST): MST.Binary = binaryOperationFunction(GroupOperations.MINUS_OPERATION)(this, b) - public override fun scale(a: MST, value: Double): MST.Binary = + override fun scale(a: MST, value: Double): MST.Binary = binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, number(value)) - public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstNumericAlgebra.binaryOperationFunction(operation) - public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstNumericAlgebra.unaryOperationFunction(operation) } @@ -57,27 +57,27 @@ public object MstGroup : Group, NumericAlgebra, ScaleOperations { @Suppress("OVERRIDE_BY_INLINE") @OptIn(UnstableKMathAPI::class) public object MstRing : Ring, NumbersAddOperations, ScaleOperations { - public override inline val zero: MST.Numeric get() = MstGroup.zero - public override val one: MST.Numeric = number(1.0) + override inline val zero: MST.Numeric get() = MstGroup.zero + override val one: MST.Numeric = number(1.0) - public override fun number(value: Number): MST.Numeric = MstGroup.number(value) - public override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - public override fun add(a: MST, b: MST): MST.Binary = MstGroup.add(a, b) + override fun number(value: Number): MST.Numeric = MstGroup.number(value) + override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) + override fun add(a: MST, b: MST): MST.Binary = MstGroup.add(a, b) - public override fun scale(a: MST, value: Double): MST.Binary = + override fun scale(a: MST, value: Double): MST.Binary = MstGroup.binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, MstGroup.number(value)) - public override fun multiply(a: MST, b: MST): MST.Binary = + override fun multiply(a: MST, b: MST): MST.Binary = binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b) - public override operator fun MST.unaryPlus(): MST.Unary = MstGroup { +this@unaryPlus } - public override operator fun MST.unaryMinus(): MST.Unary = MstGroup { -this@unaryMinus } - public override operator fun MST.minus(b: MST): MST.Binary = MstGroup { this@minus - 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(b: MST): MST.Binary = MstGroup { this@minus - b } - public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstGroup.binaryOperationFunction(operation) - public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstNumericAlgebra.unaryOperationFunction(operation) } @@ -87,28 +87,28 @@ public object MstRing : Ring, NumbersAddOperations, ScaleOperations, NumbersAddOperations, ScaleOperations { - public override inline val zero: MST.Numeric get() = MstRing.zero - public override inline val one: MST.Numeric get() = MstRing.one + override inline val zero: MST.Numeric get() = MstRing.zero + override inline val one: MST.Numeric get() = MstRing.one - public override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - public override fun number(value: Number): MST.Numeric = MstRing.number(value) - public override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b) + override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) + override fun number(value: Number): MST.Numeric = MstRing.number(value) + override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b) - public override fun scale(a: MST, value: Double): MST.Binary = + override fun scale(a: MST, value: Double): MST.Binary = MstGroup.binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, MstGroup.number(value)) - public override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b) - public override fun divide(a: MST, b: MST): MST.Binary = + 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) - public override operator fun MST.unaryPlus(): MST.Unary = MstRing { +this@unaryPlus } - public override operator fun MST.unaryMinus(): MST.Unary = MstRing { -this@unaryMinus } - public override operator fun MST.minus(b: MST): MST.Binary = MstRing { this@minus - 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(b: MST): MST.Binary = MstRing { this@minus - b } - public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstRing.binaryOperationFunction(operation) - public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstRing.unaryOperationFunction(operation) } @@ -117,45 +117,45 @@ public object MstField : Field, NumbersAddOperations, ScaleOperations< */ @Suppress("OVERRIDE_BY_INLINE") public object MstExtendedField : ExtendedField, NumericAlgebra { - public override inline val zero: MST.Numeric get() = MstField.zero - public override inline val one: MST.Numeric get() = MstField.one + override inline val zero: MST.Numeric get() = MstField.zero + override inline val one: MST.Numeric get() = MstField.one - public override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - public override fun number(value: Number): MST.Numeric = MstRing.number(value) - public override fun sin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg) - public override fun cos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg) - public override fun tan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.TAN_OPERATION)(arg) - public override fun asin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ASIN_OPERATION)(arg) - public override fun acos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ACOS_OPERATION)(arg) - public override fun atan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ATAN_OPERATION)(arg) - public override fun sinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.SINH_OPERATION)(arg) - public override fun cosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.COSH_OPERATION)(arg) - public override fun tanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.TANH_OPERATION)(arg) - public override fun asinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ASINH_OPERATION)(arg) - public override fun acosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ACOSH_OPERATION)(arg) - public override fun atanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.ATANH_OPERATION)(arg) - public override fun add(a: MST, b: MST): MST.Binary = MstField.add(a, b) - public override fun sqrt(arg: MST): MST = unaryOperationFunction(PowerOperations.SQRT_OPERATION)(arg) + override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) + override fun number(value: Number): MST.Numeric = MstRing.number(value) + override fun sin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg) + override fun cos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg) + override fun tan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.TAN_OPERATION)(arg) + override fun asin(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ASIN_OPERATION)(arg) + override fun acos(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ACOS_OPERATION)(arg) + override fun atan(arg: MST): MST.Unary = unaryOperationFunction(TrigonometricOperations.ATAN_OPERATION)(arg) + override fun sinh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.SINH_OPERATION)(arg) + override fun cosh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.COSH_OPERATION)(arg) + override fun tanh(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.TANH_OPERATION)(arg) + 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(a: MST, b: MST): MST.Binary = MstField.add(a, b) + override fun sqrt(arg: MST): MST = unaryOperationFunction(PowerOperations.SQRT_OPERATION)(arg) - public override fun scale(a: MST, value: Double): MST = + override fun scale(a: MST, value: Double): MST = binaryOperation(GroupOperations.PLUS_OPERATION, a, number(value)) - public override fun multiply(a: MST, b: MST): MST.Binary = MstField.multiply(a, b) - public override fun divide(a: MST, b: MST): MST.Binary = MstField.divide(a, b) - public override operator fun MST.unaryPlus(): MST.Unary = MstField { +this@unaryPlus } - public override operator fun MST.unaryMinus(): MST.Unary = MstField { -this@unaryMinus } - public override operator fun MST.minus(b: MST): MST.Binary = MstField { this@minus - b } + 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(b: MST): MST.Binary = MstField { this@minus - b } - public override fun power(arg: MST, pow: Number): MST.Binary = + override fun power(arg: MST, pow: Number): MST.Binary = binaryOperationFunction(PowerOperations.POW_OPERATION)(arg, number(pow)) - public override fun exp(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.EXP_OPERATION)(arg) - public override fun ln(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg) + override fun exp(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.EXP_OPERATION)(arg) + override fun ln(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg) - public override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = + override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = MstField.binaryOperationFunction(operation) - public override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = + override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = MstField.unaryOperationFunction(operation) } @@ -164,7 +164,7 @@ public object MstExtendedField : ExtendedField, NumericAlgebra { */ @UnstableKMathAPI public object MstLogicAlgebra : LogicAlgebra { - public override fun bindSymbolOrNull(value: String): MST = super.bindSymbolOrNull(value) ?: StringSymbol(value) + override fun bindSymbolOrNull(value: String): MST = super.bindSymbolOrNull(value) ?: StringSymbol(value) override fun const(boolean: Boolean): Symbol = if (boolean) { LogicAlgebra.TRUE 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 478b85620..323748ae2 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 @@ -60,8 +60,8 @@ public open class SimpleAutoDiffField>( public val context: F, bindings: Map, ) : Field>, ExpressionAlgebra>, NumbersAddOperations> { - public override val zero: AutoDiffValue get() = const(context.zero) - public override val one: AutoDiffValue get() = const(context.one) + override val zero: AutoDiffValue get() = const(context.zero) + override val one: AutoDiffValue get() = const(context.one) // this stack contains pairs of blocks and values to apply them to private var stack: Array = arrayOfNulls(8) @@ -119,8 +119,6 @@ public open class SimpleAutoDiffField>( get() = getDerivative(this) set(value) = setDerivative(this, value) - public inline fun const(block: F.() -> T): AutoDiffValue = const(context.block()) - /** * Performs update of derivative after the rest of the formula in the back-pass. * @@ -151,17 +149,17 @@ public open class SimpleAutoDiffField>( // // Overloads for Double constants // -// public override operator fun Number.plus(b: AutoDiffValue): AutoDiffValue = +// override operator fun Number.plus(b: AutoDiffValue): AutoDiffValue = // derive(const { this@plus.toDouble() * one + b.value }) { z -> // b.d += z.d // } // -// public override operator fun AutoDiffValue.plus(b: Number): AutoDiffValue = b.plus(this) +// override operator fun AutoDiffValue.plus(b: Number): AutoDiffValue = b.plus(this) // -// public override operator fun Number.minus(b: AutoDiffValue): AutoDiffValue = +// override operator fun Number.minus(b: AutoDiffValue): AutoDiffValue = // derive(const { this@minus.toDouble() * one - b.value }) { z -> b.d -= z.d } // -// public override operator fun AutoDiffValue.minus(b: Number): AutoDiffValue = +// override operator fun AutoDiffValue.minus(b: Number): AutoDiffValue = // derive(const { this@minus.value - one * b.toDouble() }) { z -> d += z.d } @@ -170,30 +168,35 @@ public open class SimpleAutoDiffField>( // Basic math (+, -, *, /) - public override fun add(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = + override fun add(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = derive(const { a.value + b.value }) { z -> a.d += z.d b.d += z.d } - public override fun multiply(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = + 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 } - public override fun divide(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = + 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) } - public override fun scale(a: AutoDiffValue, value: Double): AutoDiffValue = + override fun scale(a: AutoDiffValue, value: Double): AutoDiffValue = derive(const { value * a.value }) { z -> a.d += z.d * value } } +public inline fun > SimpleAutoDiffField.const(block: F.() -> T): AutoDiffValue { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return const(context.block()) +} + /** * Runs differentiation and establishes [SimpleAutoDiffField] context inside the block of code. @@ -208,7 +211,7 @@ public open class SimpleAutoDiffField>( * assertEquals(9.0, x.d) // dy/dx * ``` * - * @param body the action in [SimpleAutoDiffField] context returning [AutoDiffVariable] to differentiate with respect to. + * @param body the action in [SimpleAutoDiffField] context returning [AutoDiffValue] to differentiate with respect to. * @return the result of differentiation. */ public fun > F.simpleAutoDiff( @@ -233,12 +236,12 @@ public class SimpleAutoDiffExpression>( public val field: F, public val function: SimpleAutoDiffField.() -> AutoDiffValue, ) : FirstDerivativeExpression() { - public override operator fun invoke(arguments: Map): T { + override operator fun invoke(arguments: Map): T { //val bindings = arguments.entries.map { it.key.bind(it.value) } return SimpleAutoDiffField(field, arguments).function().value } - public override fun derivativeOrNull(symbol: Symbol): Expression = Expression { arguments -> + override fun derivativeOrNull(symbol: Symbol): Expression = Expression { arguments -> //val bindings = arguments.entries.map { it.key.bind(it.value) } val derivationResult = SimpleAutoDiffField(field, arguments).differentiate(function) derivationResult.derivative(symbol) @@ -248,7 +251,9 @@ public class SimpleAutoDiffExpression>( /** * Generate [AutoDiffProcessor] for [SimpleAutoDiffExpression] */ -public fun > simpleAutoDiff(field: F): AutoDiffProcessor, SimpleAutoDiffField, Expression> = +public fun > simpleAutoDiff( + field: F +): AutoDiffProcessor, SimpleAutoDiffField> = AutoDiffProcessor { function -> SimpleAutoDiffExpression(field, function) } @@ -343,28 +348,28 @@ public class SimpleAutoDiffExtendedField>( override fun bindSymbol(value: String): AutoDiffValue = super.bindSymbol(value) - public override fun number(value: Number): AutoDiffValue = const { number(value) } + override fun number(value: Number): AutoDiffValue = const { number(value) } - public override fun scale(a: AutoDiffValue, value: Double): AutoDiffValue = a * number(value) + override fun scale(a: AutoDiffValue, value: Double): AutoDiffValue = a * number(value) // x ^ 2 public fun sqr(x: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).sqr(x) // x ^ 1/2 - public override fun sqrt(arg: AutoDiffValue): AutoDiffValue = + override fun sqrt(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).sqrt(arg) // x ^ y (const) - public override fun power(arg: AutoDiffValue, pow: Number): AutoDiffValue = + override fun power(arg: AutoDiffValue, pow: Number): AutoDiffValue = (this as SimpleAutoDiffField).pow(arg, pow.toDouble()) // exp(x) - public override fun exp(arg: AutoDiffValue): AutoDiffValue = + override fun exp(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).exp(arg) // ln(x) - public override fun ln(arg: AutoDiffValue): AutoDiffValue = + override fun ln(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).ln(arg) // x ^ y (any) @@ -374,40 +379,40 @@ public class SimpleAutoDiffExtendedField>( ): AutoDiffValue = exp(y * ln(x)) // sin(x) - public override fun sin(arg: AutoDiffValue): AutoDiffValue = + override fun sin(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).sin(arg) // cos(x) - public override fun cos(arg: AutoDiffValue): AutoDiffValue = + override fun cos(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).cos(arg) - public override fun tan(arg: AutoDiffValue): AutoDiffValue = + override fun tan(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).tan(arg) - public override fun asin(arg: AutoDiffValue): AutoDiffValue = + override fun asin(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).asin(arg) - public override fun acos(arg: AutoDiffValue): AutoDiffValue = + override fun acos(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).acos(arg) - public override fun atan(arg: AutoDiffValue): AutoDiffValue = + override fun atan(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).atan(arg) - public override fun sinh(arg: AutoDiffValue): AutoDiffValue = + override fun sinh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).sinh(arg) - public override fun cosh(arg: AutoDiffValue): AutoDiffValue = + override fun cosh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).cosh(arg) - public override fun tanh(arg: AutoDiffValue): AutoDiffValue = + override fun tanh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).tanh(arg) - public override fun asinh(arg: AutoDiffValue): AutoDiffValue = + override fun asinh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).asinh(arg) - public override fun acosh(arg: AutoDiffValue): AutoDiffValue = + override fun acosh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).acosh(arg) - public override fun atanh(arg: AutoDiffValue): AutoDiffValue = + override fun atanh(arg: AutoDiffValue): AutoDiffValue = (this as SimpleAutoDiffField).atanh(arg) } 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 3a3fd7841..bf37e9615 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 @@ -10,6 +10,8 @@ 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 /** @@ -75,9 +77,13 @@ public value class SimpleSymbolIndexer(override val symbols: List) : Sym * Execute the block with symbol indexer based on given symbol order */ @UnstableKMathAPI -public inline fun withSymbols(vararg symbols: Symbol, block: SymbolIndexer.() -> R): R = - with(SimpleSymbolIndexer(symbols.toList()), block) +public inline fun withSymbols(vararg symbols: Symbol, block: SymbolIndexer.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return with(SimpleSymbolIndexer(symbols.toList()), block) +} @UnstableKMathAPI -public inline fun withSymbols(symbols: Collection, block: SymbolIndexer.() -> R): R = - with(SimpleSymbolIndexer(symbols.toList()), block) \ No newline at end of file +public inline fun withSymbols(symbols: Collection, block: SymbolIndexer.() -> R): R { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return with(SimpleSymbolIndexer(symbols.toList()), block) +} 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 new file mode 100644 index 000000000..ede4a779c --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/specialExpressions.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2018-2021 KMath 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.structures.Buffer +import space.kscience.kmath.structures.indices + +/** + * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic + * differentiation. + */ +public fun 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 + } +} \ 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 9b4451a62..f1839077f 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 @@ -15,7 +15,7 @@ import space.kscience.kmath.structures.VirtualBuffer import space.kscience.kmath.structures.indices -public class BufferedLinearSpace>( +public class BufferedLinearSpace>( override val elementAlgebra: A, private val bufferFactory: BufferFactory, ) : LinearSpace { @@ -88,4 +88,4 @@ public class BufferedLinearSpace>( override fun Matrix.times(value: T): Matrix = ndRing(rowNum, colNum).run { unwrap().map { it * value }.as2D() } -} \ No newline at end of file +} 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 288fabbaf..fae9e7c91 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 @@ -6,8 +6,8 @@ package space.kscience.kmath.linear /** - * A group of methods to solve for *X* in equation *X = A -1 · B*, where *A* and *B* are matrices or - * vectors. + * A group of methods to solve for *X* in equation *X = A−1 · B*, where *A* and *B* are + * matrices or vectors. * * @param T the type of items. */ 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 94083f70d..2075d1671 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 @@ -29,10 +29,10 @@ public typealias MutableMatrix = MutableStructure2D public typealias Point = Buffer /** - * Basic operations on matrices and vectors. Operates on [Matrix]. + * Basic operations on matrices and vectors. * * @param T the type of items in the matrices. - * @param M the type of operated matrices. + * @param A the type of ring over [T]. */ public interface LinearSpace> { public val elementAlgebra: A @@ -164,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 + * Compute 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. @@ -195,7 +195,7 @@ public interface LinearSpace> { } /** - * Get 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 T the type of items in the matrices. * @param F the type of feature. 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 3b6208468..f23e542be 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 @@ -115,7 +115,7 @@ public fun > LinearSpace>.lup( for (i in 0 until col) sum -= luRow[i] * lu[i, col] luRow[col] = sum - // maintain best permutation choice + // maintain the best permutation choice if (abs(sum) > largest) { largest = abs(sum) max = row 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 37c93d249..b70e9d8a9 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 @@ -31,11 +31,11 @@ public object ZeroFeature : DiagonalFeature public object UnitFeature : DiagonalFeature /** - * Matrices with this feature can be inverted: [inverse] = `a`-1 where `a` is the owning matrix. + * Matrices with this feature can be inverted: *[inverse] = a−1* where *a* is the owning matrix. * * @param T the type of matrices' items. */ -public interface InverseMatrixFeature : MatrixFeature { +public interface InverseMatrixFeature : MatrixFeature { /** * The inverse matrix of the matrix that owns this feature. */ @@ -47,7 +47,7 @@ public interface InverseMatrixFeature : MatrixFeature { * * @param T the type of matrices' items. */ -public interface DeterminantFeature : MatrixFeature { +public interface DeterminantFeature : MatrixFeature { /** * The determinant of the matrix that owns this feature. */ @@ -80,7 +80,7 @@ public object UFeature : MatrixFeature * * @param T the type of matrices' items. */ -public interface LUDecompositionFeature : MatrixFeature { +public interface LUDecompositionFeature : MatrixFeature { /** * The lower triangular matrix in this decomposition. It may have [LFeature]. */ @@ -98,7 +98,7 @@ public interface LUDecompositionFeature : MatrixFeature { * * @param T the type of matrices' items. */ -public interface LupDecompositionFeature : MatrixFeature { +public interface LupDecompositionFeature : MatrixFeature { /** * The lower triangular matrix in this decomposition. It may have [LFeature]. */ @@ -126,7 +126,7 @@ public object OrthogonalFeature : MatrixFeature * * @param T the type of matrices' items. */ -public interface QRDecompositionFeature : MatrixFeature { +public interface QRDecompositionFeature : MatrixFeature { /** * The orthogonal matrix in this decomposition. It may have [OrthogonalFeature]. */ @@ -144,7 +144,7 @@ public interface QRDecompositionFeature : MatrixFeature { * * @param T the type of matrices' items. */ -public interface CholeskyDecompositionFeature : MatrixFeature { +public interface CholeskyDecompositionFeature : MatrixFeature { /** * The triangular matrix in this decomposition. It may have either [UFeature] or [LFeature]. */ @@ -157,7 +157,7 @@ public interface CholeskyDecompositionFeature : MatrixFeature { * * @param T the type of matrices' items. */ -public interface SingularValueDecompositionFeature : MatrixFeature { +public interface SingularValueDecompositionFeature : MatrixFeature { /** * The matrix in this decomposition. It is unitary, and it consists from left singular vectors. */ 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 df62c6fc0..5186fbadf 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 @@ -23,14 +23,15 @@ public class MatrixWrapper internal constructor( ) : Matrix by origin { /** - * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the criteria + * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the + * criteria. */ @UnstableKMathAPI @Suppress("UNCHECKED_CAST") - public override fun getFeature(type: KClass): F? = + override fun getFeature(type: KClass): F? = features.getFeature(type) ?: origin.getFeature(type) - public override fun toString(): String = "MatrixWrapper(matrix=$origin, features=$features)" + override fun toString(): String = "MatrixWrapper(matrix=$origin, features=$features)" } /** @@ -64,7 +65,7 @@ public fun Matrix.withFeatures(newFeatures: Iterable } /** - * Diagonal matrix of ones. The matrix is virtual no actual matrix is created + * Diagonal matrix of ones. The matrix is virtual no actual matrix is created. */ public fun LinearSpace>.one( rows: Int, @@ -93,4 +94,4 @@ public class TransposedFeature(public val original: Matrix) : Ma public fun Matrix.transpose(): Matrix = getFeature>()?.original ?: VirtualMatrix( colNum, rowNum, -) { i, j -> get(j, i) }.withFeature(TransposedFeature(this)) \ No newline at end of file +) { i, j -> get(j, i) }.withFeature(TransposedFeature(this)) 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 39b2779eb..73ecd6492 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 @@ -7,8 +7,8 @@ package space.kscience.kmath.misc /** * Marks declarations that are still experimental in the KMath APIs, which means that the design of the corresponding - * declarations has open issues which may (or may not) lead to their changes in the future. Roughly speaking, there is - * a chance that those declarations will be deprecated in the near future or the semantics of their behavior may change + * declarations has open issues that may (or may not) lead to their changes in the future. Roughly speaking, there is + * a chance of those declarations will be deprecated in the near future or the semantics of their behavior may change * in some way that may break some code. */ @MustBeDocumented @@ -17,7 +17,7 @@ package space.kscience.kmath.misc public annotation class UnstableKMathAPI /** - * Marks API which could cause performance problems. The code, marked by this API is not necessary slow, but could cause + * Marks API that could cause performance problems. The code marked by this API is unnecessary slow but could cause * slow-down in some cases. Refer to the documentation and benchmark it to be sure. */ @MustBeDocumented 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 889eb4f22..ee7f1d8be 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 @@ -34,7 +34,7 @@ public inline fun Iterable.cumulative(initial: R, crossinline operatio public inline fun Sequence.cumulative(initial: R, crossinline operation: (R, T) -> R): Sequence = Sequence { this@cumulative.iterator().cumulative(initial, operation) } -public fun List.cumulative(initial: R, operation: (R, T) -> R): List = +public inline fun List.cumulative(initial: R, crossinline operation: (R, T) -> R): List = iterator().cumulative(initial, operation).asSequence().toList() //Cumulative sum diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/VectorSpaceTest.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt similarity index 68% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/VectorSpaceTest.kt rename to kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt index f2c7f1f90..f879a06d5 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/VectorSpaceTest.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -3,3 +3,6 @@ * 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 + +public expect fun Long.toIntExact(): Int 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 35bbc44f6..454a33e86 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 @@ -11,7 +11,7 @@ import space.kscience.kmath.structures.* import kotlin.reflect.KClass /** - * An exception is thrown when the expected ans actual shape of NDArray differs. + * An exception is thrown when the expected and actual shape of NDArray differ. * * @property expected the expected shape. * @property actual the actual shape. @@ -24,7 +24,6 @@ public class ShapeMismatchException(public val expected: IntArray, public val ac * * @param T the type of ND-structure element. * @param C the type of the element context. - * @param N the type of the structure. */ public interface AlgebraND> { /** @@ -64,7 +63,7 @@ public interface AlgebraND> { structure.map { value -> this@invoke(value) } /** - * Get 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. @@ -80,7 +79,7 @@ public interface AlgebraND> { /** - * Get 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 T the type of items in the matrices. * @param F the type of feature. @@ -118,8 +117,7 @@ internal fun > AlgebraND.checkShape(element: StructureND * Space of [StructureND]. * * @param T the type of the element contained in ND structure. - * @param N the type of ND structure. - * @param S the type of space of structure elements. + * @param S the type of group over structure elements. */ public interface GroupND> : Group>, AlgebraND { /** @@ -129,18 +127,9 @@ public interface GroupND> : Group>, AlgebraND * @param b the addend. * @return the sum. */ - public override fun add(a: StructureND, b: StructureND): StructureND = + override fun add(a: StructureND, b: StructureND): StructureND = combine(a, b) { aValue, bValue -> add(aValue, bValue) } -// /** -// * Element-wise multiplication by scalar. -// * -// * @param a the multiplicand. -// * @param k the multiplier. -// * @return the product. -// */ -// public override fun multiply(a: NDStructure, k: Number): NDStructure = a.map { multiply(it, k) } - // TODO move to extensions after KEEP-176 /** @@ -186,8 +175,7 @@ public interface GroupND> : Group>, AlgebraND * Ring of [StructureND]. * * @param T the type of the element contained in ND structure. - * @param N the type of ND structure. - * @param R the type of ring of structure elements. + * @param R the type of ring over structure elements. */ public interface RingND> : Ring>, GroupND { /** @@ -197,7 +185,7 @@ public interface RingND> : Ring>, GroupND, b: StructureND): StructureND = + override fun multiply(a: StructureND, b: StructureND): StructureND = combine(a, b) { aValue, bValue -> multiply(aValue, bValue) } //TODO move to extensions after KEEP-176 @@ -227,9 +215,9 @@ public interface RingND> : Ring>, GroupND> : Field>, RingND, ScaleOperations> { +public interface FieldND> : Field>, RingND { /** * Element-wise division. * @@ -237,7 +225,7 @@ public interface FieldND> : Field>, RingND, b: StructureND): StructureND = + override fun divide(a: StructureND, b: StructureND): StructureND = combine(a, b) { aValue, bValue -> divide(aValue, bValue) } //TODO move to extensions after KEEP-176 @@ -259,6 +247,15 @@ public interface FieldND> : Field>, RingND): StructureND = arg.map { divide(it, this@div) } + /** + * 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) } + // @ThreadLocal // public companion object { // private val realNDFieldCache: MutableMap = hashMapOf() 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 2b82a36ae..6eacf1ca5 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 @@ -57,7 +57,7 @@ public interface BufferAlgebraND> : AlgebraND { } } -public open class BufferedGroupND>( +public open class BufferedGroupND>( final override val shape: IntArray, final override val elementContext: A, final override val bufferFactory: BufferFactory, @@ -67,7 +67,7 @@ public open class BufferedGroupND>( override fun StructureND.unaryMinus(): StructureND = produce { -get(it) } } -public open class BufferedRingND>( +public open class BufferedRingND>( shape: IntArray, elementContext: R, bufferFactory: BufferFactory, @@ -75,7 +75,7 @@ public open class BufferedRingND>( override val one: BufferND by lazy { produce { one } } } -public open class BufferedFieldND>( +public open class BufferedFieldND>( shape: IntArray, elementContext: R, bufferFactory: BufferFactory, 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 71532594e..925301272 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 @@ -22,15 +22,15 @@ public class DoubleFieldND( ScaleOperations>, ExtendedField> { - public override val zero: BufferND by lazy { produce { zero } } - public override val one: BufferND by lazy { produce { one } } + override val zero: BufferND by lazy { produce { zero } } + override val one: BufferND by lazy { produce { one } } - public override fun number(value: Number): BufferND { + override fun number(value: Number): BufferND { val d = value.toDouble() // minimize conversions return produce { d } } - public override val StructureND.buffer: DoubleBuffer + override val StructureND.buffer: DoubleBuffer get() = when { !shape.contentEquals(this@DoubleFieldND.shape) -> throw ShapeMismatchException( this@DoubleFieldND.shape, @@ -41,7 +41,7 @@ public class DoubleFieldND( } @Suppress("OVERRIDE_BY_INLINE") - public override inline fun StructureND.map( + override inline fun StructureND.map( transform: DoubleField.(Double) -> Double, ): BufferND { val buffer = DoubleBuffer(strides.linearSize) { offset -> DoubleField.transform(buffer.array[offset]) } @@ -49,7 +49,7 @@ public class DoubleFieldND( } @Suppress("OVERRIDE_BY_INLINE") - public override inline fun produce(initializer: DoubleField.(IntArray) -> Double): BufferND { + override inline fun produce(initializer: DoubleField.(IntArray) -> Double): BufferND { val array = DoubleArray(strides.linearSize) { offset -> val index = strides.index(offset) DoubleField.initializer(index) @@ -58,7 +58,7 @@ public class DoubleFieldND( } @Suppress("OVERRIDE_BY_INLINE") - public override inline fun StructureND.mapIndexed( + override inline fun StructureND.mapIndexed( transform: DoubleField.(index: IntArray, Double) -> Double, ): BufferND = BufferND( strides, @@ -70,7 +70,7 @@ public class DoubleFieldND( }) @Suppress("OVERRIDE_BY_INLINE") - public override inline fun combine( + override inline fun combine( a: StructureND, b: StructureND, transform: DoubleField.(Double, Double) -> Double, @@ -81,26 +81,26 @@ public class DoubleFieldND( return BufferND(strides, buffer) } - public override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } + override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } - public override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) } + override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) } - public override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } - public override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } + override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } + override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } - public override fun sin(arg: StructureND): BufferND = arg.map { sin(it) } - public override fun cos(arg: StructureND): BufferND = arg.map { cos(it) } - public override fun tan(arg: StructureND): BufferND = arg.map { tan(it) } - public override fun asin(arg: StructureND): BufferND = arg.map { asin(it) } - public override fun acos(arg: StructureND): BufferND = arg.map { acos(it) } - public override fun atan(arg: StructureND): BufferND = arg.map { atan(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) } - public override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) } - public override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) } - public override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) } - public override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) } - public override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) } - public override fun atanh(arg: StructureND): BufferND = arg.map { atanh(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 fun AlgebraND.Companion.real(vararg shape: Int): DoubleFieldND = DoubleFieldND(shape) 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 720a06ace..1305558e5 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 @@ -31,11 +31,10 @@ public class ShortRingND( /** * Fast element production using function inlining. */ -public inline fun BufferedRingND.produceInline(crossinline initializer: ShortRing.(Int) -> Short): BufferND { - return BufferND(strides, ShortBuffer(ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) })) -} +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) -} \ No newline at end of file +} 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 150ebf6fb..1af80149c 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 @@ -16,14 +16,14 @@ import kotlin.jvm.JvmInline * A structure that is guaranteed to be one-dimensional */ public interface Structure1D : StructureND, Buffer { - public override val dimension: Int get() = 1 + override val dimension: Int get() = 1 - public override operator fun get(index: IntArray): T { + override operator fun get(index: IntArray): T { require(index.size == 1) { "Index dimension mismatch. Expected 1 but found ${index.size}" } return get(index[0]) } - public override operator fun iterator(): Iterator = (0 until size).asSequence().map(::get).iterator() + override operator fun iterator(): Iterator = (0 until size).asSequence().map(::get).iterator() public companion object } @@ -32,7 +32,7 @@ public interface Structure1D : StructureND, Buffer { * A mutable structure that is guaranteed to be one-dimensional */ public interface MutableStructure1D : Structure1D, MutableStructureND, MutableBuffer { - public override operator fun set(index: IntArray, value: T) { + override operator fun set(index: IntArray, value: T) { require(index.size == 1) { "Index dimension mismatch. Expected 1 but found ${index.size}" } set(index[0], value) } @@ -110,7 +110,7 @@ internal class MutableBuffer1DWrapper(val buffer: MutableBuffer) : Mutable } /** - * Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch + * Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch. */ public fun StructureND.as1D(): Structure1D = this as? Structure1D ?: if (shape.size == 1) { when (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 f353b6974..293faaeda 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 @@ -29,7 +29,7 @@ public interface Structure2D : StructureND { */ public val colNum: Int - public override val shape: IntArray get() = intArrayOf(rowNum, colNum) + override val shape: IntArray get() = intArrayOf(rowNum, colNum) /** * The buffer of rows of this structure. It gets elements from the structure dynamically. @@ -144,13 +144,16 @@ private class MutableStructure2DWrapper(val structure: MutableStructureND) } /** - * Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch + * Represents a [StructureND] as [Structure2D]. Throws runtime error in case of dimension mismatch. */ public fun StructureND.as2D(): Structure2D = this as? Structure2D ?: when (shape.size) { 2 -> Structure2DWrapper(this) else -> error("Can't create 2d-structure from ${shape.size}d-structure") } +/** + * 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") 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 4962dcb7d..8e7646b8f 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 @@ -5,10 +5,13 @@ 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 @@ -18,7 +21,7 @@ import kotlin.reflect.KClass public interface StructureFeature : Feature /** - * Represents n-dimensional structure, i.e. multidimensional container of items of the same type and size. The number + * Represents n-dimensional structure i.e., multidimensional container of items of the same type and size. The number * of dimensions and items in an array is defined by its shape, which is a sequence of non-negative integers that * specify the sizes of each dimension. * @@ -28,7 +31,7 @@ public interface StructureFeature : Feature */ public interface StructureND : Featured { /** - * The shape of structure, i.e. non-empty sequence of non-negative integers that specify sizes of dimensions of + * The shape of structure i.e., non-empty sequence of non-negative integers that specify sizes of dimensions of * this structure. */ public val shape: IntArray @@ -55,8 +58,8 @@ public interface StructureND : Featured { public fun elements(): Sequence> /** - * Feature is some additional strucure information which allows to access it special properties or hints. - * If the feature is not present, null is returned. + * Feature is some additional structure information that allows to access it special properties or hints. + * If the feature is not present, `null` is returned. */ @UnstableKMathAPI override fun getFeature(type: KClass): F? = null @@ -147,6 +150,44 @@ public interface StructureND : Featured { } } +/** + * Indicates whether some [StructureND] is equal to another one. + */ +@PerformancePitfall +public fun > AlgebraND>.contentEquals( + st1: StructureND, + st2: StructureND, +): Boolean = StructureND.contentEquals(st1, st2) + +/** + * Indicates whether some [StructureND] is equal to another one. + */ +@PerformancePitfall +public fun > LinearSpace>.contentEquals( + st1: StructureND, + st2: StructureND, +): Boolean = StructureND.contentEquals(st1, st2) + +/** + * Indicates whether some [StructureND] is equal to another one with [absoluteTolerance]. + */ +@PerformancePitfall +public fun > GroupND>.contentEquals( + st1: StructureND, + st2: StructureND, + absoluteTolerance: T, +): Boolean = st1.elements().all { (index, value) -> elementContext { (value - st2[index]) } < absoluteTolerance } + +/** + * Indicates whether some [StructureND] is equal to another one with [absoluteTolerance]. + */ +@PerformancePitfall +public fun > LinearSpace>.contentEquals( + st1: StructureND, + st2: StructureND, + absoluteTolerance: T, +): Boolean = st1.elements().all { (index, value) -> elementAlgebra { (value - st2[index]) } < absoluteTolerance } + /** * Returns the value at the specified indices. * @@ -179,7 +220,7 @@ public inline fun MutableStructureND.mapInPlace(action: (IntArray, T) -> elements().forEach { (index, oldValue) -> this[index] = action(index, oldValue) } /** - * A way to convert ND index to linear one and back. + * A way to convert ND indices to linear one and back. */ public interface Strides { /** 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 3a1ec430e..1009742e1 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 @@ -23,15 +23,13 @@ public interface Algebra { * Wraps a raw string to [T] object. This method is designed for three purposes: * * 1. Mathematical constants (`e`, `pi`). - * 2. Variables for expression-like contexts (`a`, `b`, `c`...). - * 3. Literals (`{1, 2}`, (`(3; 4)`)). + * 1. Variables for expression-like contexts (`a`, `b`, `c`…). + * 1. Literals (`{1, 2}`, (`(3; 4)`)). * - * In case if algebra can't parse the string, this method must throw [kotlin.IllegalStateException]. - * - * Returns `null` if symbol could not be bound to the context + * If algebra can't parse the string, then this method must throw [kotlin.IllegalStateException]. * * @param value the raw string. - * @return an object. + * @return an object or `null` if symbol could not be bound to the context. */ public fun bindSymbolOrNull(value: String): T? = null @@ -42,13 +40,12 @@ public interface Algebra { bindSymbolOrNull(value) ?: error("Symbol '$value' is not supported in $this") /** - * Dynamically dispatches an unary operation with the certain name. + * Dynamically dispatches a unary operation with the certain name. * - * This function must has two features: + * Implementations must fulfil the following requirements: * - * 1. In case operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with second `unaryOperation` overload: - * i.e. `unaryOperationFunction(a)(b) == unaryOperation(a, b)`. + * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [unaryOperation]: for any `a` and `b`, `unaryOperationFunction(a)(b) == unaryOperation(a, b)`. * * @param operation the name of operation. * @return an operation. @@ -57,13 +54,13 @@ public interface Algebra { error("Unary operation $operation not defined in $this") /** - * Dynamically invokes an unary operation with the certain name. + * Dynamically invokes a unary operation with the certain name. * - * This function must follow two properties: + * Implementations must fulfil the following requirements: * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with second [unaryOperationFunction] overload: - * i.e. `unaryOperationFunction(a)(b) == unaryOperation(a, b)`. + * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [unaryOperationFunction]: i.e., for any `a` and `b`, + * `unaryOperationFunction(a)(b) == unaryOperation(a, b)`. * * @param operation the name of operation. * @param arg the argument of operation. @@ -74,11 +71,11 @@ public interface Algebra { /** * Dynamically dispatches a binary operation with the certain name. * - * This function must follow two properties: + * Implementations must fulfil the following requirements: * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with second [binaryOperationFunction] overload: - * i.e. `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. + * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [binaryOperation]: for any `a`, `b`, and `c`, + * `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. * * @param operation the name of operation. * @return an operation. @@ -89,11 +86,11 @@ public interface Algebra { /** * Dynamically invokes a binary operation with the certain name. * - * This function must follow two properties: + * Implementations must fulfil the following requirements: * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with second [binaryOperationFunction] overload: - * i.e. `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. + * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [binaryOperationFunction]: for any `a`, `b`, and `c`, + * `binaryOperationFunction(a)(b, c) == binaryOperation(a, b, c)`. * * @param operation the name of operation. * @param left the first argument of operation. @@ -115,7 +112,7 @@ public fun Algebra.bindSymbol(symbol: Symbol): T = bindSymbol(symbol.iden public inline operator fun , R> A.invoke(block: A.() -> R): R = run(block) /** - * Represents group without neutral element (also known as inverse semigroup), i.e. algebraic structure with + * Represents group without neutral element (also known as inverse semigroup) i.e., algebraic structure with * associative, binary operation [add]. * * @param T the type of element of this semispace. @@ -130,7 +127,7 @@ public interface GroupOperations : Algebra { */ 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 + // Operations to be performed in this context. Could be moved to extensions in case of KEEP-176. /** * The negation of this element. @@ -166,13 +163,13 @@ public interface GroupOperations : Algebra { */ public operator fun T.minus(b: T): T = add(this, -b) - public override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { + override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { PLUS_OPERATION -> { arg -> +arg } MINUS_OPERATION -> { arg -> -arg } else -> super.unaryOperationFunction(operation) } - public override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { + override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { PLUS_OPERATION -> ::add MINUS_OPERATION -> { left, right -> left - right } else -> super.binaryOperationFunction(operation) @@ -192,7 +189,7 @@ public interface GroupOperations : Algebra { } /** - * Represents group, i.e. algebraic structure with associative, binary operation [add]. + * Represents group i.e., algebraic structure with associative, binary operation [add]. * * @param T the type of element of this semispace. */ @@ -204,7 +201,7 @@ public interface Group : GroupOperations { } /** - * Represents ring without multiplicative and additive identities, i.e. algebraic structure with + * Represents ring without multiplicative and additive identities i.e., algebraic structure with * associative, binary, commutative operation [add] and associative, operation [multiply] distributive over [add]. * * @param T the type of element of this semiring. @@ -226,7 +223,7 @@ public interface RingOperations : GroupOperations { */ public operator fun T.times(b: T): T = multiply(this, b) - public override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { + override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { TIMES_OPERATION -> ::multiply else -> super.binaryOperationFunction(operation) } @@ -240,7 +237,7 @@ public interface RingOperations : GroupOperations { } /** - * Represents ring, i.e. algebraic structure with two associative binary operations called "addition" and + * Represents ring i.e., algebraic structure with two associative binary operations called "addition" and * "multiplication" and their neutral elements. * * @param T the type of element of this ring. @@ -253,8 +250,9 @@ public interface Ring : Group, RingOperations { } /** - * Represents field without without multiplicative and additive identities, i.e. algebraic structure with associative, binary, commutative operations - * [add] and [multiply]; binary operation [divide] as multiplication of left operand by reciprocal of right one. + * Represents field without multiplicative and additive identities i.e., algebraic structure with associative, binary, + * commutative operations [add] and [multiply]; binary operation [divide] as multiplication of left operand by + * reciprocal of right one. * * @param T the type of element of this semifield. */ @@ -277,7 +275,7 @@ public interface FieldOperations : RingOperations { */ public operator fun T.div(b: T): T = divide(this, b) - public override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { + override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { DIV_OPERATION -> ::divide else -> super.binaryOperationFunction(operation) } @@ -291,12 +289,12 @@ public interface FieldOperations : RingOperations { } /** - * Represents field, i.e. algebraic structure with three operations: associative, commutative addition and + * Represents field i.e., algebraic structure with three operations: associative, commutative addition and * multiplication, and division. **This interface differs from the eponymous mathematical definition: fields in KMath * also support associative multiplication by scalar.** * * @param T the type of element of this field. */ public interface Field : Ring, FieldOperations, ScaleOperations, NumericAlgebra { - public override fun number(value: Number): T = scale(one, value.toDouble()) + override fun number(value: Number): T = scale(one, value.toDouble()) } 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 index cc058d3fc..6b0e2cabd 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt @@ -8,14 +8,14 @@ package space.kscience.kmath.operations import space.kscience.kmath.misc.UnstableKMathAPI /** - * The generic mathematics elements which is able to store its context + * 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> { +public interface AlgebraElement> { /** * The context this element belongs to. */ 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 ac53c4d5e..8111691aa 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 @@ -49,16 +49,16 @@ public class BigInt internal constructor( private val sign: Byte, private val magnitude: Magnitude, ) : Comparable { - public override fun compareTo(other: BigInt): Int = when { + override fun compareTo(other: BigInt): Int = when { (sign == 0.toByte()) and (other.sign == 0.toByte()) -> 0 sign < other.sign -> -1 sign > other.sign -> 1 else -> sign * compareMagnitudes(magnitude, other.magnitude) } - public override fun equals(other: Any?): Boolean = other is BigInt && compareTo(other) == 0 + override fun equals(other: Any?): Boolean = other is BigInt && compareTo(other) == 0 - public override fun hashCode(): Int = magnitude.hashCode() + sign + override fun hashCode(): Int = magnitude.hashCode() + sign public fun abs(): BigInt = if (sign == 0.toByte()) this else BigInt(1, magnitude) @@ -121,7 +121,7 @@ public class BigInt internal constructor( var r = ZERO val bitSize = - (BASE_SIZE * (this.magnitude.size - 1) + log2(this.magnitude.lastOrNull()?.toFloat() ?: 0f + 1)).toInt() + (BASE_SIZE * (this.magnitude.size - 1) + log2(this.magnitude.lastOrNull()?.toFloat() ?: (0f + 1))).toInt() for (i in bitSize downTo 0) { r = r shl 1 @@ -442,10 +442,10 @@ public fun UIntArray.toBigInt(sign: Byte): BigInt { } /** - * Returns null if a valid number can not be read from a string + * Returns `null` if a valid number cannot be read from a string */ public fun String.parseBigInteger(): BigInt? { - if (this.isEmpty()) return null + if (isEmpty()) return null val sign: Int val positivePartIndex = when (this[0]) { 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 deeb07e0e..92070b33d 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 @@ -26,11 +26,11 @@ public interface NumericAlgebra : Algebra { /** * Dynamically dispatches a binary operation with the certain name with numeric first argument. * - * This function must follow two properties: + * Implementations must fulfil the following requirements: * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with the other [leftSideNumberOperation] overload: - * i.e. `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b)`. + * 1. If operation is not defined in the structure, then function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [leftSideNumberOperation]: for any `a`, `b`, and `c`, + * `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b)`. * * @param operation the name of operation. * @return an operation. @@ -41,11 +41,11 @@ public interface NumericAlgebra : Algebra { /** * Dynamically invokes a binary operation with the certain name with numeric first argument. * - * This function must follow two properties: + * Implementations must fulfil the following requirements: * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with second [leftSideNumberOperation] overload: - * i.e. `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. + * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [leftSideNumberOperation]: for any `a`, `b`, and `c`, + * `leftSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. * * @param operation the name of operation. * @param left the first argument of operation. @@ -58,11 +58,11 @@ public interface NumericAlgebra : Algebra { /** * Dynamically dispatches a binary operation with the certain name with numeric first argument. * - * This function must follow two properties: + * Implementations must fulfil the following requirements: * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with the other [rightSideNumberOperationFunction] overload: - * i.e. `rightSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. + * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [rightSideNumberOperation]: for any `a`, `b`, and `c`, + * `rightSideNumberOperationFunction(a)(b, c) == leftSideNumberOperation(a, b, c)`. * * @param operation the name of operation. * @return an operation. @@ -73,11 +73,11 @@ public interface NumericAlgebra : Algebra { /** * Dynamically invokes a binary operation with the certain name with numeric second argument. * - * This function must follow two properties: + * Implementations must fulfil the following requirements: * - * 1. In case if operation is not defined in the structure, the function throws [kotlin.IllegalStateException]. - * 2. This function is symmetric with the other [rightSideNumberOperationFunction] overload: - * i.e. `rightSideNumberOperationFunction(a)(b, c) == rightSideNumberOperation(a, b, c)`. + * 1. If operation is not defined in the structure, then the function throws [kotlin.IllegalStateException]. + * 1. Equivalence to [rightSideNumberOperationFunction]: for any `a`, `b`, and `c`, + * `rightSideNumberOperationFunction(a)(b, c) == rightSideNumberOperation(a, b, c)`. * * @param operation the name of operation. * @param left the first argument of operation. @@ -87,7 +87,7 @@ public interface NumericAlgebra : Algebra { public fun rightSideNumberOperation(operation: String, left: T, right: Number): T = rightSideNumberOperationFunction(operation)(left, right) - public override fun bindSymbolOrNull(value: String): T? = when (value) { + override fun bindSymbolOrNull(value: String): T? = when (value) { "pi" -> number(PI) "e" -> number(E) else -> super.bindSymbolOrNull(value) 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 86365394f..31bd47bc3 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 @@ -330,13 +330,13 @@ public fun >> atanh(arg: T): */ public interface Norm { /** - * Computes the norm of [arg] (i.e. absolute value or vector length). + * Computes the norm of [arg] (i.e., absolute value or vector length). */ public fun norm(arg: T): R } /** - * Computes the norm of [arg] (i.e. absolute value or vector length). + * 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/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt index 0d6d9e98d..19cb5f25c 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 @@ -15,10 +15,10 @@ public interface ExtendedFieldOperations : TrigonometricOperations, PowerOperations, ExponentialOperations { - public override fun tan(arg: T): T = sin(arg) / cos(arg) - public override fun tanh(arg: T): T = sinh(arg) / cosh(arg) + override fun tan(arg: T): T = sin(arg) / cos(arg) + override fun tanh(arg: T): T = sinh(arg) / cosh(arg) - public override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { + override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { TrigonometricOperations.COS_OPERATION -> ::cos TrigonometricOperations.SIN_OPERATION -> ::sin TrigonometricOperations.TAN_OPERATION -> ::tan @@ -42,14 +42,14 @@ public interface ExtendedFieldOperations : * Advanced Number-like field that implements basic operations. */ public interface ExtendedField : ExtendedFieldOperations, Field, NumericAlgebra, ScaleOperations { - public override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2.0 - public override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2.0 - public override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) - public override fun asinh(arg: T): T = ln(sqrt(arg * arg + one) + arg) - public override fun acosh(arg: T): T = ln(arg + sqrt((arg - one) * (arg + one))) - public override fun atanh(arg: T): T = (ln(arg + one) - ln(one - arg)) / 2.0 + 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)) + override fun asinh(arg: T): T = ln(sqrt(arg * arg + one) + arg) + 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 - public override fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = + override fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = when (operation) { PowerOperations.POW_OPERATION -> ::power else -> super.rightSideNumberOperationFunction(operation) @@ -61,49 +61,50 @@ public interface ExtendedField : ExtendedFieldOperations, Field, Numeri */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object DoubleField : ExtendedField, Norm, ScaleOperations { - public override inline val zero: Double get() = 0.0 - public override inline val one: Double get() = 1.0 + override inline val zero: Double get() = 0.0 + override inline val one: Double get() = 1.0 - public override fun number(value: Number): Double = value.toDouble() + override inline fun number(value: Number): Double = value.toDouble() - public override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = + override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = when (operation) { PowerOperations.POW_OPERATION -> ::power else -> super.binaryOperationFunction(operation) } - public override inline fun add(a: Double, b: Double): Double = a + b + override inline fun add(a: Double, b: Double): Double = a + b - public override inline fun multiply(a: Double, b: Double): Double = a * b - public override inline fun divide(a: Double, b: Double): Double = a / b + override inline fun multiply(a: Double, b: Double): Double = a * b + override inline fun divide(a: Double, b: Double): Double = a / b - public override fun scale(a: Double, value: Double): Double = a * value + override inline fun scale(a: Double, value: Double): Double = a * value - public override inline fun sin(arg: Double): Double = kotlin.math.sin(arg) - public override inline fun cos(arg: Double): Double = kotlin.math.cos(arg) - public override inline fun tan(arg: Double): Double = kotlin.math.tan(arg) - public override inline fun acos(arg: Double): Double = kotlin.math.acos(arg) - public override inline fun asin(arg: Double): Double = kotlin.math.asin(arg) - public override inline fun atan(arg: Double): Double = kotlin.math.atan(arg) + override inline fun sin(arg: Double): Double = kotlin.math.sin(arg) + override inline fun cos(arg: Double): Double = kotlin.math.cos(arg) + override inline fun tan(arg: Double): Double = kotlin.math.tan(arg) + override inline fun acos(arg: Double): Double = kotlin.math.acos(arg) + override inline fun asin(arg: Double): Double = kotlin.math.asin(arg) + override inline fun atan(arg: Double): Double = kotlin.math.atan(arg) - public override inline fun sinh(arg: Double): Double = kotlin.math.sinh(arg) - public override inline fun cosh(arg: Double): Double = kotlin.math.cosh(arg) - public override inline fun tanh(arg: Double): Double = kotlin.math.tanh(arg) - public override inline fun asinh(arg: Double): Double = kotlin.math.asinh(arg) - public override inline fun acosh(arg: Double): Double = kotlin.math.acosh(arg) - public override inline fun atanh(arg: Double): Double = kotlin.math.atanh(arg) + override inline fun sinh(arg: Double): Double = kotlin.math.sinh(arg) + override inline fun cosh(arg: Double): Double = kotlin.math.cosh(arg) + override inline fun tanh(arg: Double): Double = kotlin.math.tanh(arg) + override inline fun asinh(arg: Double): Double = kotlin.math.asinh(arg) + override inline fun acosh(arg: Double): Double = kotlin.math.acosh(arg) + override inline fun atanh(arg: Double): Double = kotlin.math.atanh(arg) - public override inline fun power(arg: Double, pow: Number): Double = arg.kpow(pow.toDouble()) - public override inline fun exp(arg: Double): Double = kotlin.math.exp(arg) - public override inline fun ln(arg: Double): Double = kotlin.math.ln(arg) + 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) - public override inline fun norm(arg: Double): Double = abs(arg) + override inline fun norm(arg: Double): Double = abs(arg) - public override inline fun Double.unaryMinus(): Double = -this - public override inline fun Double.plus(b: Double): Double = this + b - public override inline fun Double.minus(b: Double): Double = this - b - public override inline fun Double.times(b: Double): Double = this * b - public override inline fun Double.div(b: Double): Double = this / b + override inline fun Double.unaryMinus(): Double = -this + 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 } /** @@ -111,49 +112,50 @@ public object DoubleField : ExtendedField, Norm, ScaleOp */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object FloatField : ExtendedField, Norm { - public override inline val zero: Float get() = 0.0f - public override inline val one: Float get() = 1.0f + override inline val zero: Float get() = 0.0f + override inline val one: Float get() = 1.0f - public override fun number(value: Number): Float = value.toFloat() + override fun number(value: Number): Float = value.toFloat() - public override fun binaryOperationFunction(operation: String): (left: Float, right: Float) -> Float = + override fun binaryOperationFunction(operation: String): (left: Float, right: Float) -> Float = when (operation) { PowerOperations.POW_OPERATION -> ::power else -> super.binaryOperationFunction(operation) } - public override inline fun add(a: Float, b: Float): Float = a + b - public override fun scale(a: Float, value: Double): Float = a * value.toFloat() + override inline fun add(a: Float, b: Float): Float = a + b + override fun scale(a: Float, value: Double): Float = a * value.toFloat() - public override inline fun multiply(a: Float, b: Float): Float = a * b + override inline fun multiply(a: Float, b: Float): Float = a * b - public override inline fun divide(a: Float, b: Float): Float = a / b + override inline fun divide(a: Float, b: Float): Float = a / b - public override inline fun sin(arg: Float): Float = kotlin.math.sin(arg) - public override inline fun cos(arg: Float): Float = kotlin.math.cos(arg) - public override inline fun tan(arg: Float): Float = kotlin.math.tan(arg) - public override inline fun acos(arg: Float): Float = kotlin.math.acos(arg) - public override inline fun asin(arg: Float): Float = kotlin.math.asin(arg) - public override inline fun atan(arg: Float): Float = kotlin.math.atan(arg) + override inline fun sin(arg: Float): Float = kotlin.math.sin(arg) + override inline fun cos(arg: Float): Float = kotlin.math.cos(arg) + override inline fun tan(arg: Float): Float = kotlin.math.tan(arg) + override inline fun acos(arg: Float): Float = kotlin.math.acos(arg) + override inline fun asin(arg: Float): Float = kotlin.math.asin(arg) + override inline fun atan(arg: Float): Float = kotlin.math.atan(arg) - public override inline fun sinh(arg: Float): Float = kotlin.math.sinh(arg) - public override inline fun cosh(arg: Float): Float = kotlin.math.cosh(arg) - public override inline fun tanh(arg: Float): Float = kotlin.math.tanh(arg) - public override inline fun asinh(arg: Float): Float = kotlin.math.asinh(arg) - public override inline fun acosh(arg: Float): Float = kotlin.math.acosh(arg) - public override inline fun atanh(arg: Float): Float = kotlin.math.atanh(arg) + override inline fun sinh(arg: Float): Float = kotlin.math.sinh(arg) + override inline fun cosh(arg: Float): Float = kotlin.math.cosh(arg) + override inline fun tanh(arg: Float): Float = kotlin.math.tanh(arg) + override inline fun asinh(arg: Float): Float = kotlin.math.asinh(arg) + override inline fun acosh(arg: Float): Float = kotlin.math.acosh(arg) + override inline fun atanh(arg: Float): Float = kotlin.math.atanh(arg) - public override inline fun power(arg: Float, pow: Number): Float = arg.kpow(pow.toFloat()) - public override inline fun exp(arg: Float): Float = kotlin.math.exp(arg) - public override inline fun ln(arg: Float): Float = kotlin.math.ln(arg) + 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) - public override inline fun norm(arg: Float): Float = abs(arg) + override inline fun norm(arg: Float): Float = abs(arg) - public override inline fun Float.unaryMinus(): Float = -this - public override inline fun Float.plus(b: Float): Float = this + b - public override inline fun Float.minus(b: Float): Float = this - b - public override inline fun Float.times(b: Float): Float = this * b - public override inline fun Float.div(b: Float): Float = this / b + override inline fun Float.unaryMinus(): Float = -this + 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 } /** @@ -161,21 +163,21 @@ public object FloatField : ExtendedField, Norm { */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object IntRing : Ring, Norm, NumericAlgebra { - public override inline val zero: Int + override inline val zero: Int get() = 0 - public override inline val one: Int + override inline val one: Int get() = 1 - public override fun number(value: Number): Int = value.toInt() - public override inline fun add(a: Int, b: Int): Int = a + b - public override inline fun multiply(a: Int, b: Int): Int = a * b - public override inline fun norm(arg: Int): Int = abs(arg) + override fun number(value: Number): Int = value.toInt() + 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) - public override inline fun Int.unaryMinus(): Int = -this - public override inline fun Int.plus(b: Int): Int = this + b - public override inline fun Int.minus(b: Int): Int = this - b - public override inline fun Int.times(b: Int): Int = this * b + override inline fun Int.unaryMinus(): Int = -this + 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 } /** @@ -183,21 +185,21 @@ public object IntRing : Ring, Norm, NumericAlgebra { */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object ShortRing : Ring, Norm, NumericAlgebra { - public override inline val zero: Short + override inline val zero: Short get() = 0 - public override inline val one: Short + override inline val one: Short get() = 1 - public override fun number(value: Number): Short = value.toShort() - public override inline fun add(a: Short, b: Short): Short = (a + b).toShort() - public override inline fun multiply(a: Short, b: Short): Short = (a * b).toShort() - public override fun norm(arg: Short): Short = if (arg > 0) arg else (-arg).toShort() + override fun number(value: Number): Short = value.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() - public override inline fun Short.unaryMinus(): Short = (-this).toShort() - public override inline fun Short.plus(b: Short): Short = (this + b).toShort() - public override inline fun Short.minus(b: Short): Short = (this - b).toShort() - public override inline fun Short.times(b: Short): Short = (this * b).toShort() + override inline fun Short.unaryMinus(): Short = (-this).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() } /** @@ -205,21 +207,21 @@ public object ShortRing : Ring, Norm, NumericAlgebra */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object ByteRing : Ring, Norm, NumericAlgebra { - public override inline val zero: Byte + override inline val zero: Byte get() = 0 - public override inline val one: Byte + override inline val one: Byte get() = 1 - public override fun number(value: Number): Byte = value.toByte() - public override inline fun add(a: Byte, b: Byte): Byte = (a + b).toByte() - public override inline fun multiply(a: Byte, b: Byte): Byte = (a * b).toByte() - public override fun norm(arg: Byte): Byte = if (arg > 0) arg else (-arg).toByte() + override fun number(value: Number): Byte = value.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() - public override inline fun Byte.unaryMinus(): Byte = (-this).toByte() - public override inline fun Byte.plus(b: Byte): Byte = (this + b).toByte() - public override inline fun Byte.minus(b: Byte): Byte = (this - b).toByte() - public override inline fun Byte.times(b: Byte): Byte = (this * b).toByte() + override inline fun Byte.unaryMinus(): Byte = (-this).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() } /** @@ -227,19 +229,19 @@ public object ByteRing : Ring, Norm, NumericAlgebra { */ @Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public object LongRing : Ring, Norm, NumericAlgebra { - public override inline val zero: Long + override inline val zero: Long get() = 0L - public override inline val one: Long + override inline val one: Long get() = 1L - public override fun number(value: Number): Long = value.toLong() - public override inline fun add(a: Long, b: Long): Long = a + b - public override inline fun multiply(a: Long, b: Long): Long = a * b - public override fun norm(arg: Long): Long = abs(arg) + override fun number(value: Number): Long = value.toLong() + 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) - public override inline fun Long.unaryMinus(): Long = (-this) - public override inline fun Long.plus(b: Long): Long = (this + b) - public override inline fun Long.minus(b: Long): Long = (this - b) - public override inline fun Long.times(b: Long): Long = (this * b) + override inline fun Long.unaryMinus(): Long = (-this) + 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) } 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 b4ef37598..7a79663c4 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 @@ -32,7 +32,7 @@ public value class DoubleBuffer(public val array: DoubleArray) : MutableBuffer Double): DoubleBuffer = DoubleBuffer(DoubleArray(size) { init(it) }) @@ -47,7 +47,7 @@ public fun DoubleBuffer(vararg doubles: Double): DoubleBuffer = DoubleBuffer(dou public fun DoubleBuffer.contentEquals(vararg doubles: Double): Boolean = array.contentEquals(doubles) /** - * Returns a new [DoubleArray] containing all of the elements of this [Buffer]. + * Returns a new [DoubleArray] containing all the elements of this [Buffer]. */ public fun Buffer.toDoubleArray(): DoubleArray = when (this) { is DoubleBuffer -> array.copyOf() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt index c65a0a48a..f1afdfa8c 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt @@ -7,10 +7,7 @@ package space.kscience.kmath.structures import space.kscience.kmath.linear.Point import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.ExtendedFieldOperations -import space.kscience.kmath.operations.Norm +import space.kscience.kmath.operations.* import kotlin.math.* /** @@ -24,7 +21,7 @@ public object DoubleBufferFieldOperations : ExtendedFieldOperations, b: Buffer): DoubleBuffer { + 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} " } @@ -36,7 +33,7 @@ public object DoubleBufferFieldOperations : ExtendedFieldOperations, k: Number): RealBuffer { +// override fun multiply(a: Buffer, k: Number): RealBuffer { // val kValue = k.toDouble() // // return if (a is RealBuffer) { @@ -45,7 +42,7 @@ public object DoubleBufferFieldOperations : ExtendedFieldOperations, k: Number): RealBuffer { +// override fun divide(a: Buffer, k: Number): RealBuffer { // val kValue = k.toDouble() // // return if (a is RealBuffer) { @@ -54,7 +51,7 @@ public object DoubleBufferFieldOperations : ExtendedFieldOperations, b: Buffer): DoubleBuffer { + 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} " } @@ -67,7 +64,7 @@ public object DoubleBufferFieldOperations : ExtendedFieldOperations, b: Buffer): DoubleBuffer { + 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} " } @@ -79,87 +76,87 @@ public object DoubleBufferFieldOperations : ExtendedFieldOperations): DoubleBuffer = if (arg is DoubleBuffer) { + 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]) }) - public override fun cos(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + 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]) }) - public override fun tan(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + 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]) }) - public override fun asin(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + 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]) }) - public override fun acos(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + 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]) }) - public override fun atan(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + 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]) }) - public override fun sinh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + 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]) }) - public override fun cosh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + 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]) }) - public override fun tanh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + 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]) }) - public override fun asinh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + 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]) }) - public override fun acosh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + 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]) }) - public override fun atanh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + 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]) }) - public override fun power(arg: Buffer, pow: Number): DoubleBuffer = if (arg is DoubleBuffer) { + 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()) }) - public override fun exp(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + 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]) }) - public override fun ln(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { + override fun ln(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { val array = arg.array DoubleBuffer(DoubleArray(arg.size) { ln(array[it]) }) } else @@ -177,8 +174,8 @@ public object DoubleL2Norm : Norm, Double> { */ @Deprecated("To be replaced by generic BufferAlgebra") public class DoubleBufferField(public val size: Int) : ExtendedField>, Norm, Double> { - public override val zero: Buffer by lazy { DoubleBuffer(size) { 0.0 } } - public override val one: Buffer by lazy { DoubleBuffer(size) { 1.0 } } + 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() } @@ -186,12 +183,12 @@ public class DoubleBufferField(public val size: Int) : ExtendedField, b: Buffer): DoubleBuffer { + 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) } - public override fun scale(a: Buffer, value: Double): DoubleBuffer { + 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) { @@ -200,87 +197,87 @@ public class DoubleBufferField(public val size: Int) : ExtendedField, b: Buffer): DoubleBuffer { + 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) } - public override fun divide(a: Buffer, b: Buffer): DoubleBuffer { + 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) } - public override fun sin(arg: Buffer): DoubleBuffer { + 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) } - public override fun cos(arg: Buffer): DoubleBuffer { + 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) } - public override fun tan(arg: Buffer): DoubleBuffer { + 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) } - public override fun asin(arg: Buffer): DoubleBuffer { + 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) } - public override fun acos(arg: Buffer): DoubleBuffer { + 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) } - public override fun atan(arg: Buffer): DoubleBuffer { + 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) } - public override fun sinh(arg: Buffer): DoubleBuffer { + 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) } - public override fun cosh(arg: Buffer): DoubleBuffer { + 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) } - public override fun tanh(arg: Buffer): DoubleBuffer { + 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) } - public override fun asinh(arg: Buffer): DoubleBuffer { + 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) } - public override fun acosh(arg: Buffer): DoubleBuffer { + 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) } - public override fun atanh(arg: Buffer): DoubleBuffer { + 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) } - public override fun power(arg: Buffer, pow: Number): DoubleBuffer { + 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) } - public override fun exp(arg: Buffer): DoubleBuffer { + 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) } - public override fun ln(arg: Buffer): DoubleBuffer { + 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 0b16a3afc..efb8504c2 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 @@ -51,7 +51,7 @@ public fun FlaggedBuffer<*>.hasFlag(index: Int, flag: ValueFlag): Boolean = (get public fun FlaggedBuffer<*>.isMissing(index: Int): Boolean = hasFlag(index, ValueFlag.MISSING) /** - * A real buffer which supports flags for each value like NaN or Missing + * 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 { 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 58b7c6aea..e7e98fc71 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 @@ -34,7 +34,7 @@ public value class FloatBuffer(public val array: FloatArray) : MutableBuffer Float): FloatBuffer = FloatBuffer(FloatArray(size) { init(it) }) @@ -44,7 +44,7 @@ public inline fun FloatBuffer(size: Int, init: (Int) -> Float): FloatBuffer = Fl public fun FloatBuffer(vararg floats: Float): FloatBuffer = FloatBuffer(floats) /** - * Returns a new [FloatArray] containing all of the elements of this [Buffer]. + * Returns a new [FloatArray] containing all the elements of this [Buffer]. */ public fun Buffer.toFloatArray(): FloatArray = when (this) { is FloatBuffer -> array.copyOf() 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 57b6cfde3..35b722e2b 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 @@ -33,7 +33,7 @@ public value class IntBuffer(public val array: IntArray) : MutableBuffer { * [init] function. * * The function [init] is called for each array element sequentially starting from the first one. - * It should return the value for an buffer element given its index. + * It should return the value for a buffer element given its index. */ public inline fun IntBuffer(size: Int, init: (Int) -> Int): IntBuffer = IntBuffer(IntArray(size) { init(it) }) @@ -43,7 +43,7 @@ public inline fun IntBuffer(size: Int, init: (Int) -> Int): IntBuffer = IntBuffe public fun IntBuffer(vararg ints: Int): IntBuffer = IntBuffer(ints) /** - * Returns a new [IntArray] containing all of the elements of this [Buffer]. + * Returns a new [IntArray] containing all the elements of this [Buffer]. */ public fun Buffer.toIntArray(): IntArray = when (this) { is IntBuffer -> array.copyOf() 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 57affa1c5..c69f4646d 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 @@ -33,7 +33,7 @@ public value class LongBuffer(public val array: LongArray) : MutableBuffer * [init] function. * * The function [init] is called for each array element sequentially starting from the first one. - * It should return the value for an buffer element given its index. + * It should return the value for a buffer element given its index. */ public inline fun LongBuffer(size: Int, init: (Int) -> Long): LongBuffer = LongBuffer(LongArray(size) { init(it) }) @@ -43,7 +43,7 @@ public inline fun LongBuffer(size: Int, init: (Int) -> Long): LongBuffer = LongB public fun LongBuffer(vararg longs: Long): LongBuffer = LongBuffer(longs) /** - * Returns a new [LongArray] containing all of the elements of this [Buffer]. + * Returns a new [LongArray] containing all the elements of this [Buffer]. */ public fun Buffer.toLongArray(): LongArray = when (this) { is LongBuffer -> array.copyOf() 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 8c98ab9c8..5d660c8cb 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 @@ -48,8 +48,8 @@ public class MutableMemoryBuffer(memory: Memory, spec: MemorySpec) : private val writer: MemoryWriter = memory.writer() - public override operator fun set(index: Int, value: T): Unit = writer.write(spec, spec.objectSize * index, value) - public override fun copy(): MutableBuffer = MutableMemoryBuffer(memory.copy(), spec) + override operator fun set(index: Int, value: T): Unit = writer.write(spec, spec.objectSize * index, value) + override fun copy(): MutableBuffer = MutableMemoryBuffer(memory.copy(), spec) public companion object { public fun create(spec: MemorySpec, size: Int): MutableMemoryBuffer = 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 3d4c68b3c..20691511b 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 @@ -14,16 +14,16 @@ import kotlin.jvm.JvmInline */ @JvmInline public value class ShortBuffer(public val array: ShortArray) : MutableBuffer { - public override val size: Int get() = array.size + override val size: Int get() = array.size - public override operator fun get(index: Int): Short = array[index] + override operator fun get(index: Int): Short = array[index] - public override operator fun set(index: Int, value: Short) { + override operator fun set(index: Int, value: Short) { array[index] = value } - public override operator fun iterator(): ShortIterator = array.iterator() - public override fun copy(): MutableBuffer = ShortBuffer(array.copyOf()) + override operator fun iterator(): ShortIterator = array.iterator() + override fun copy(): MutableBuffer = ShortBuffer(array.copyOf()) } /** @@ -31,7 +31,7 @@ public value class ShortBuffer(public val array: ShortArray) : MutableBuffer Short): ShortBuffer = ShortBuffer(ShortArray(size) { init(it) }) @@ -41,7 +41,7 @@ public inline fun ShortBuffer(size: Int, init: (Int) -> Short): ShortBuffer = Sh public fun ShortBuffer(vararg shorts: Short): ShortBuffer = ShortBuffer(shorts) /** - * Returns a new [ShortArray] containing all of the elements of this [Buffer]. + * Returns a new [ShortArray] containing all the elements of this [Buffer]. */ public fun Buffer.toShortArray(): ShortArray = when (this) { is ShortBuffer -> array.copyOf() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt index 1b89e7838..3dad14ac5 100644 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt +++ b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt @@ -67,9 +67,9 @@ public inline fun Buffer.map(block: (T) -> R): Buf * Create a new buffer from this one with the given mapping function. * Provided [bufferFactory] is used to construct the new buffer. */ -public fun Buffer.map( +public inline fun Buffer.map( bufferFactory: BufferFactory, - block: (T) -> R, + crossinline block: (T) -> R, ): Buffer = bufferFactory(size) { block(get(it)) } /** diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt index feae07c1e..e0b706eed 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt +++ b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt @@ -17,6 +17,7 @@ import kotlin.test.assertTrue @OptIn(PerformancePitfall::class) @Suppress("UNUSED_VARIABLE") class MatrixTest { + @Test fun testTranspose() { val matrix = LinearSpace.double.one(3, 3) 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 bd09ff449..20a7b6a72 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 @@ -10,7 +10,7 @@ import space.kscience.kmath.operations.invoke import kotlin.test.assertEquals import kotlin.test.assertNotEquals -internal class FieldVerifier>( +internal class FieldVerifier>( algebra: A, a: T, b: T, c: T, x: Number, ) : RingVerifier(algebra, a, b, c, x) { 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 885857f04..daf18834a 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 @@ -10,7 +10,7 @@ import space.kscience.kmath.operations.ScaleOperations import space.kscience.kmath.operations.invoke import kotlin.test.assertEquals -internal open class RingVerifier(algebra: A, a: T, b: T, c: T, x: Number) : +internal open class RingVerifier(algebra: A, a: T, b: T, c: T, x: Number) : SpaceVerifier(algebra, a, b, c, x) where A : Ring, A : ScaleOperations { override fun verify() { 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 new file mode 100644 index 000000000..68a3c995b --- /dev/null +++ b/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -0,0 +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. + */ + +package space.kscience.kmath.misc + +public actual fun Long.toIntExact(): Int { + val i = toInt() + if (i.toLong() == this) throw ArithmeticException("integer overflow") + return i +} 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 new file mode 100644 index 000000000..5ba0dbc9b --- /dev/null +++ b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt @@ -0,0 +1,8 @@ +/* + * Copyright 2018-2021 KMath 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 + +public actual fun Long.toIntExact(): Int = Math.toIntExact(this) 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 9b46369bb..7ac2c6f83 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 @@ -13,16 +13,16 @@ import java.math.MathContext * A field over [BigInteger]. */ public object JBigIntegerField : Ring, NumericAlgebra { - public override val zero: BigInteger get() = BigInteger.ZERO + override val zero: BigInteger get() = BigInteger.ZERO - public override val one: BigInteger get() = BigInteger.ONE + override val one: BigInteger get() = BigInteger.ONE - public override fun number(value: Number): BigInteger = BigInteger.valueOf(value.toLong()) - public override fun add(a: BigInteger, b: BigInteger): BigInteger = a.add(b) - public override operator fun BigInteger.minus(b: BigInteger): BigInteger = subtract(b) - public override fun multiply(a: BigInteger, b: BigInteger): BigInteger = a.multiply(b) + override fun number(value: Number): BigInteger = BigInteger.valueOf(value.toLong()) + 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) - public override operator fun BigInteger.unaryMinus(): BigInteger = negate() + override operator fun BigInteger.unaryMinus(): BigInteger = negate() } /** @@ -33,24 +33,24 @@ public object JBigIntegerField : Ring, NumericAlgebra { public abstract class JBigDecimalFieldBase internal constructor( private val mathContext: MathContext = MathContext.DECIMAL64, ) : Field, PowerOperations, NumericAlgebra, ScaleOperations { - public override val zero: BigDecimal + override val zero: BigDecimal get() = BigDecimal.ZERO - public override val one: BigDecimal + override val one: BigDecimal get() = BigDecimal.ONE - public override fun add(a: BigDecimal, b: BigDecimal): BigDecimal = a.add(b) - public override operator fun BigDecimal.minus(b: BigDecimal): BigDecimal = subtract(b) - public override fun number(value: Number): BigDecimal = BigDecimal.valueOf(value.toDouble()) + 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()) - public override fun scale(a: BigDecimal, value: Double): BigDecimal = + override fun scale(a: BigDecimal, value: Double): BigDecimal = a.multiply(value.toBigDecimal(mathContext), mathContext) - public override fun multiply(a: BigDecimal, b: BigDecimal): BigDecimal = a.multiply(b, mathContext) - public override fun divide(a: BigDecimal, b: BigDecimal): BigDecimal = a.divide(b, mathContext) - public override fun power(arg: BigDecimal, pow: Number): BigDecimal = arg.pow(pow.toInt(), mathContext) - public override fun sqrt(arg: BigDecimal): BigDecimal = arg.sqrt(mathContext) - public override operator fun BigDecimal.unaryMinus(): BigDecimal = negate(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/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt new file mode 100644 index 000000000..68a3c995b --- /dev/null +++ b/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt @@ -0,0 +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. + */ + +package space.kscience.kmath.misc + +public actual fun Long.toIntExact(): Int { + val i = toInt() + if (i.toLong() == this) throw ArithmeticException("integer overflow") + return i +} diff --git a/kmath-coroutines/build.gradle.kts b/kmath-coroutines/build.gradle.kts index 1546e7d96..317691ae5 100644 --- a/kmath-coroutines/build.gradle.kts +++ b/kmath-coroutines/build.gradle.kts @@ -1,6 +1,7 @@ plugins { kotlin("multiplatform") id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } kotlin.sourceSets { 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 70849f942..87aebff61 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 @@ -32,9 +32,9 @@ public interface BlockingBufferChain : BlockingChain, BufferChain { public fun nextBufferBlocking(size: Int): Buffer - public override fun nextBlocking(): T = nextBufferBlocking(1)[0] + override fun nextBlocking(): T = nextBufferBlocking(1)[0] - public override suspend fun nextBuffer(size: Int): Buffer = nextBufferBlocking(size) + override suspend fun nextBuffer(size: Int): Buffer = nextBufferBlocking(size) override suspend fun fork(): BlockingBufferChain } 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 526250cf0..25e20291e 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 @@ -15,7 +15,7 @@ public interface BlockingDoubleChain : BlockingBufferChain { /** * Returns an [DoubleArray] chunk of [size] values of [next]. */ - public override fun nextBufferBlocking(size: Int): DoubleBuffer + override fun nextBufferBlocking(size: Int): DoubleBuffer override suspend fun fork(): BlockingDoubleChain @@ -29,4 +29,4 @@ public fun BlockingDoubleChain.map(transform: (Double) -> Double): BlockingDoubl } override suspend fun fork(): BlockingDoubleChain = this@map.fork().map(transform) -} \ No newline at end of file +} 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 b29165e32..f8d2549e5 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 @@ -13,7 +13,7 @@ import kotlinx.coroutines.sync.withLock /** * A not-necessary-Markov chain of some type - * @param T - the chain element type + * @param T the chain element type */ public interface Chain : Flow { /** @@ -22,7 +22,7 @@ public interface Chain : Flow { public suspend fun next(): T /** - * Create a copy of current chain state. Consuming resulting chain does not affect initial chain + * Create a copy of current chain state. Consuming resulting chain does not affect initial chain. */ public suspend fun fork(): Chain @@ -39,8 +39,8 @@ public fun Sequence.asChain(): Chain = iterator().asChain() * A simple chain of independent tokens. [fork] returns the same chain. */ public class SimpleChain(private val gen: suspend () -> R) : Chain { - public override suspend fun next(): R = gen() - public override suspend fun fork(): Chain = this + override suspend fun next(): R = gen() + override suspend fun fork(): Chain = this } /** @@ -52,19 +52,21 @@ public class MarkovChain(private val seed: suspend () -> R, private public fun value(): R? = value - public override suspend fun next(): R = mutex.withLock { + override suspend fun next(): R = mutex.withLock { val newValue = gen(value ?: seed()) value = newValue newValue } - public override suspend fun fork(): Chain = MarkovChain(seed = { value ?: seed() }, gen = gen) + override suspend fun fork(): Chain = MarkovChain(seed = { value ?: seed() }, gen = gen) } /** - * A chain with possibly mutable state. The state must not be changed outside the chain. Two chins should never share the state - * @param S - the state of the chain - * @param forkState - the function to copy current state without modifying it + * A chain with possibly mutable state. The state must not be changed outside the chain. Two chins should never share + * the state. + * + * @param S the state of the chain. + * @param forkState the function to copy current state without modifying it. */ public class StatefulChain( private val state: S, @@ -77,26 +79,26 @@ public class StatefulChain( public fun value(): R? = value - public override suspend fun next(): R = mutex.withLock { + override suspend fun next(): R = mutex.withLock { val newValue = state.gen(value ?: state.seed()) value = newValue newValue } - public override suspend fun fork(): Chain = StatefulChain(forkState(state), seed, forkState, gen) + override suspend fun fork(): Chain = StatefulChain(forkState(state), seed, forkState, gen) } /** * A chain that repeats the same value */ public class ConstantChain(public val value: T) : Chain { - public override suspend fun next(): T = value - public override suspend fun fork(): Chain = this + override suspend fun next(): T = value + override suspend fun fork(): Chain = this } /** * Map the chain result using suspended transformation. Initial chain result can no longer be safely consumed - * since mapped chain consumes tokens. Accepts regular transformation function + * since mapped chain consumes tokens. Accepts regular transformation function. */ public fun Chain.map(func: suspend (T) -> R): Chain = object : Chain { override suspend fun next(): R = func(this@map.next()) 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 49f32f82f..1f17efe49 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 @@ -15,30 +15,33 @@ public val Dispatchers.Math: CoroutineDispatcher /** * An imitator of [Deferred] which holds a suspended function block and dispatcher */ -internal class LazyDeferred(val dispatcher: CoroutineDispatcher, val block: suspend CoroutineScope.() -> T) { +@PublishedApi +internal class LazyDeferred(val dispatcher: CoroutineDispatcher, val block: suspend CoroutineScope.() -> T) { private var deferred: Deferred? = null - internal fun start(scope: CoroutineScope) { + fun start(scope: CoroutineScope) { if (deferred == null) deferred = scope.async(dispatcher, block = block) } suspend fun await(): T = deferred?.await() ?: error("Coroutine not started") } -public class AsyncFlow internal constructor(internal val deferredFlow: Flow>) : Flow { +public class AsyncFlow @PublishedApi internal constructor( + @PublishedApi internal val deferredFlow: Flow>, +) : Flow { override suspend fun collect(collector: FlowCollector): Unit = deferredFlow.collect { collector.emit((it.await())) } } -public fun Flow.async( +public inline fun Flow.async( dispatcher: CoroutineDispatcher = Dispatchers.Default, - block: suspend CoroutineScope.(T) -> R, + crossinline block: suspend CoroutineScope.(T) -> R, ): AsyncFlow { val flow = map { LazyDeferred(dispatcher) { block(it) } } return AsyncFlow(flow) } -public fun AsyncFlow.map(action: (T) -> R): AsyncFlow = +public inline fun AsyncFlow.map(crossinline action: (T) -> R): AsyncFlow = AsyncFlow(deferredFlow.map { input -> //TODO add function composition LazyDeferred(input.dispatcher) { 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 0d6a1178a..4d4493aa4 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 @@ -76,7 +76,7 @@ public fun Flow.chunked(bufferSize: Int): Flow = flow { /** * Map a flow to a moving window buffer. The window step is one. - * In order to get different steps, one could use skip operation. + * To get different steps, one could use skip operation. */ public fun Flow.windowed(window: Int): Flow> = flow { require(window > 1) { "Window size must be more than one" } 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 05f2876e3..93c4a401b 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 @@ -22,10 +22,10 @@ public class RingBuffer( ) : Buffer { private val mutex: Mutex = Mutex() - public override var size: Int = size + override var size: Int = size private set - public override operator fun get(index: Int): T { + override operator fun get(index: Int): T { require(index >= 0) { "Index must be positive" } require(index < size) { "Index $index is out of circular buffer size $size" } return buffer[startIndex.forward(index)] as T @@ -36,7 +36,7 @@ public class RingBuffer( /** * Iterator could provide wrong results if buffer is changed in initialization (iteration is safe) */ - public override operator fun iterator(): Iterator = object : AbstractIterator() { + override operator fun iterator(): Iterator = object : AbstractIterator() { private var count = size private var index = startIndex val copy = buffer.copy() 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 ded8c9c44..f9ef62529 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 @@ -13,7 +13,7 @@ import space.kscience.kmath.nd.StructureND public class LazyStructureND( public val scope: CoroutineScope, - public override val shape: IntArray, + override val shape: IntArray, public val function: suspend (IntArray) -> T, ) : StructureND { private val cache: MutableMap> = HashMap() @@ -23,10 +23,10 @@ public class LazyStructureND( } public suspend fun await(index: IntArray): T = deferred(index).await() - public override operator fun get(index: IntArray): T = runBlocking { deferred(index).await() } + override operator fun get(index: IntArray): T = runBlocking { deferred(index).await() } @OptIn(PerformancePitfall::class) - public override fun elements(): Sequence> { + override fun elements(): Sequence> { val strides = DefaultStrides(shape) val res = runBlocking { strides.indices().toList().map { index -> index to await(index) } } return res.asSequence() diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimensions.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt similarity index 67% rename from kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimensions.kt rename to kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index 8b17d252f..e57c22834 100644 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimensions.kt +++ b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -8,47 +8,47 @@ package space.kscience.kmath.dimensions import kotlin.reflect.KClass /** - * Represents a quantity of dimensions in certain structure. + * Represents a quantity of dimensions in certain structure. **This interface must be implemented only by objects.** * * @property dim The number of dimensions. */ public interface Dimension { - public val dim: UInt + public val dim: Int public companion object } -public fun KClass.dim(): UInt = Dimension.resolve(this).dim +public fun KClass.dim(): Int = Dimension.resolve(this).dim public expect fun Dimension.Companion.resolve(type: KClass): D /** * Finds or creates [Dimension] with [Dimension.dim] equal to [dim]. */ -public expect fun Dimension.Companion.of(dim: UInt): Dimension +public expect fun Dimension.Companion.of(dim: Int): Dimension /** * Finds [Dimension.dim] of given type [D]. */ -public inline fun Dimension.Companion.dim(): UInt = D::class.dim() +public inline fun Dimension.Companion.dim(): Int = D::class.dim() /** * Type representing 1 dimension. */ public object D1 : Dimension { - override val dim: UInt get() = 1U + override val dim: Int get() = 1 } /** * Type representing 2 dimensions. */ public object D2 : Dimension { - override val dim: UInt get() = 2U + override val dim: Int get() = 2 } /** * Type representing 3 dimensions. */ public object D3 : Dimension { - override val dim: UInt get() = 3U + override val dim: Int get() = 3 } 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 91ab6a5d6..d4aebbac1 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 @@ -17,17 +17,17 @@ import kotlin.jvm.JvmInline /** * A matrix with compile-time controlled dimension */ -public interface DMatrix : Structure2D { +public interface DMatrix : Structure2D { public companion object { /** - * Coerces a regular matrix to a matrix with type-safe dimensions and throws a error if coercion failed + * Coerces a regular matrix to a matrix with type-safe dimensions and throws an error if coercion failed */ public inline fun coerce(structure: Structure2D): DMatrix { - require(structure.rowNum == Dimension.dim().toInt()) { + require(structure.rowNum == Dimension.dim()) { "Row number mismatch: expected ${Dimension.dim()} but found ${structure.rowNum}" } - require(structure.colNum == Dimension.dim().toInt()) { + require(structure.colNum == Dimension.dim()) { "Column number mismatch: expected ${Dimension.dim()} but found ${structure.colNum}" } @@ -35,7 +35,7 @@ public interface DMatrix : Structure2D { } /** - * The same as [DMatrix.coerce] but without dimension checks. Use with caution + * The same as [DMatrix.coerce] but without dimension checks. Use with caution. */ public fun coerceUnsafe(structure: Structure2D): DMatrix = DMatrixWrapper(structure) @@ -46,7 +46,7 @@ public interface DMatrix : Structure2D { * An inline wrapper for a Matrix */ @JvmInline -public value class DMatrixWrapper( +public value class DMatrixWrapper( private val structure: Structure2D, ) : DMatrix { override val shape: IntArray get() = structure.shape @@ -58,10 +58,10 @@ public value class DMatrixWrapper( /** * Dimension-safe point */ -public interface DPoint : Point { +public interface DPoint : Point { public companion object { public inline fun coerce(point: Point): DPoint { - require(point.size == Dimension.dim().toInt()) { + require(point.size == Dimension.dim()) { "Vector dimension mismatch: expected ${Dimension.dim()}, but found ${point.size}" } @@ -76,7 +76,7 @@ public interface DPoint : Point { * Dimension-safe point wrapper */ @JvmInline -public value class DPointWrapper(public val point: Point) : +public value class DPointWrapper(public val point: Point) : DPoint { override val size: Int get() = point.size @@ -92,11 +92,11 @@ public value class DPointWrapper(public val point: Point) : @JvmInline public value class DMatrixContext>(public val context: LinearSpace) { public inline fun Matrix.coerce(): DMatrix { - require(rowNum == Dimension.dim().toInt()) { + require(rowNum == Dimension.dim()) { "Row number mismatch: expected ${Dimension.dim()} but found $rowNum" } - require(colNum == Dimension.dim().toInt()) { + require(colNum == Dimension.dim()) { "Column number mismatch: expected ${Dimension.dim()} but found $colNum" } @@ -111,7 +111,7 @@ public value class DMatrixContext>(public val context: ): DMatrix { val rows = Dimension.dim() val cols = Dimension.dim() - return context.buildMatrix(rows.toInt(), cols.toInt(), initializer).coerce() + return context.buildMatrix(rows, cols, initializer).coerce() } public inline fun point(noinline initializer: A.(Int) -> T): DPoint { @@ -119,7 +119,7 @@ public value class DMatrixContext>(public val context: return DPoint.coerceUnsafe( context.buildVector( - size.toInt(), + size, initializer ) ) @@ -167,4 +167,4 @@ public inline fun DMatrixContext.on public inline fun DMatrixContext.zero(): DMatrix = produce { _, _ -> 0.0 - } \ No newline at end of file + } diff --git a/kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt b/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt similarity index 100% rename from kmath-dimensions/src/commonTest/kotlin/kscience/dimensions/DMatrixContextTest.kt rename to kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt diff --git a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/dimJs.kt b/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt similarity index 62% rename from kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/dimJs.kt rename to kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index 27912f5bc..610e8b4c0 100644 --- a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/dimJs.kt +++ b/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -7,17 +7,17 @@ package space.kscience.kmath.dimensions import kotlin.reflect.KClass -private val dimensionMap: MutableMap = hashMapOf(1u to D1, 2u to D2, 3u to D3) +private val dimensionMap: MutableMap = hashMapOf(1 to D1, 2 to D2, 3 to D3) @Suppress("UNCHECKED_CAST") public actual fun Dimension.Companion.resolve(type: KClass): D = dimensionMap .entries - .map(MutableMap.MutableEntry::value) + .map(MutableMap.MutableEntry::value) .find { it::class == type } as? D ?: error("Can't resolve dimension $type") -public actual fun Dimension.Companion.of(dim: UInt): Dimension = dimensionMap.getOrPut(dim) { +public actual fun Dimension.Companion.of(dim: Int): Dimension = dimensionMap.getOrPut(dim) { object : Dimension { - override val dim: UInt get() = dim + override val dim: Int get() = dim } } diff --git a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/dimJvm.kt b/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt similarity index 69% rename from kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/dimJvm.kt rename to kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index f21a3e18f..e6d8b3b35 100644 --- a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/dimJvm.kt +++ b/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -3,6 +3,8 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ +@file:JvmName("DimensionJVM") + package space.kscience.kmath.dimensions import kotlin.reflect.KClass @@ -10,12 +12,12 @@ import kotlin.reflect.KClass public actual fun Dimension.Companion.resolve(type: KClass): D = type.objectInstance ?: error("No object instance for dimension class") -public actual fun Dimension.Companion.of(dim: UInt): Dimension = when (dim) { - 1u -> D1 - 2u -> D2 - 3u -> D3 +public actual fun Dimension.Companion.of(dim: Int): Dimension = when (dim) { + 1 -> D1 + 2 -> D2 + 3 -> D3 else -> object : Dimension { - override val dim: UInt get() = dim + override val dim: Int get() = dim } -} \ No newline at end of file +} diff --git a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/dimNative.kt b/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt similarity index 65% rename from kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/dimNative.kt rename to kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt index 9aa58e64a..64edbe935 100644 --- a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/dimNative.kt +++ b/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt @@ -9,17 +9,17 @@ import kotlin.native.concurrent.ThreadLocal import kotlin.reflect.KClass @ThreadLocal -private val dimensionMap: MutableMap = hashMapOf(1u to D1, 2u to D2, 3u to D3) +private val dimensionMap: MutableMap = hashMapOf(1 to D1, 2 to D2, 3 to D3) @Suppress("UNCHECKED_CAST") public actual fun Dimension.Companion.resolve(type: KClass): D = dimensionMap .entries - .map(MutableMap.MutableEntry::value) + .map(MutableMap.MutableEntry::value) .find { it::class == type } as? D ?: error("Can't resolve dimension $type") -public actual fun Dimension.Companion.of(dim: UInt): Dimension = dimensionMap.getOrPut(dim) { +public actual fun Dimension.Companion.of(dim: Int): Dimension = dimensionMap.getOrPut(dim) { object : Dimension { - override val dim: UInt get() = dim + override val dim: Int get() = dim } } diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md index 79a28b824..f88f53000 100644 --- a/kmath-ejml/README.md +++ b/kmath-ejml/README.md @@ -9,7 +9,7 @@ EJML based linear algebra implementation. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-14`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-ejml:0.3.0-dev-11' + 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-11") + implementation("space.kscience:kmath-ejml:0.3.0-dev-14") } ``` diff --git a/kmath-ejml/build.gradle.kts b/kmath-ejml/build.gradle.kts index 5107cfb68..727d21e3a 100644 --- a/kmath-ejml/build.gradle.kts +++ b/kmath-ejml/build.gradle.kts @@ -6,10 +6,10 @@ plugins { } dependencies { - api("org.ejml:ejml-ddense:0.40") - api("org.ejml:ejml-fdense:0.40") - api("org.ejml:ejml-dsparse:0.40") - api("org.ejml:ejml-fsparse:0.40") + api("org.ejml:ejml-ddense:0.41") + api("org.ejml:ejml-fdense:0.41") + api("org.ejml:ejml-dsparse:0.41") + api("org.ejml:ejml-fsparse:0.41") api(project(":kmath-core")) } 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 cec31eb7d..27fd3fc53 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 @@ -17,6 +17,6 @@ import space.kscience.kmath.nd.Structure2D * @author Iaroslav Postovalov */ public abstract class EjmlMatrix(public open val origin: M) : Structure2D { - public override val rowNum: Int get() = origin.numRows - public override val colNum: Int get() = origin.numCols + override val rowNum: Int get() = origin.numRows + override val colNum: Int get() = origin.numCols } 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 5d10d1fbb..37995c27e 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 @@ -17,10 +17,10 @@ import space.kscience.kmath.linear.Point * @author Iaroslav Postovalov */ public abstract class EjmlVector(public open val origin: M) : Point { - public override val size: Int + override val size: Int get() = origin.numCols - public override operator fun iterator(): Iterator = object : Iterator { + override operator fun iterator(): Iterator = object : Iterator { private var cursor: Int = 0 override fun next(): T { @@ -31,5 +31,5 @@ public abstract class EjmlVector(public open val origin: override fun hasNext(): Boolean = cursor < origin.numCols * origin.numRows } - public override fun toString(): String = "EjmlVector(origin=$origin)" + override fun toString(): String = "EjmlVector(origin=$origin)" } diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md index 5ca805093..d449b4540 100644 --- a/kmath-for-real/README.md +++ b/kmath-for-real/README.md @@ -9,7 +9,7 @@ Specialization of KMath APIs for Double numbers. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-14`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-for-real:0.3.0-dev-11' + 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-11") + implementation("space.kscience:kmath-for-real:0.3.0-dev-14") } ``` diff --git a/kmath-for-real/build.gradle.kts b/kmath-for-real/build.gradle.kts index f6d12decd..4cccaef5c 100644 --- a/kmath-for-real/build.gradle.kts +++ b/kmath-for-real/build.gradle.kts @@ -1,6 +1,7 @@ plugins { kotlin("multiplatform") id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } kotlin.sourceSets.commonMain { @@ -11,7 +12,7 @@ kotlin.sourceSets.commonMain { readme { description = """ - Extension module that should be used to achieve numpy-like behavior. + 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. """.trimIndent() 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 38e5b4beb..e79f4307a 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 @@ -184,4 +184,4 @@ public fun tan(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.tan(it) } public fun ln(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.ln(it) } -public fun log10(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.log10(it) } \ No newline at end of file +public fun log10(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.log10(it) } diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt index dbf81b133..414d473e2 100644 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt +++ b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt @@ -19,7 +19,7 @@ public typealias DoubleVector = Point public fun DoubleVector(vararg doubles: Double): DoubleVector = doubles.asBuffer() /** - * Fill the vector of given [size] with given [value] + * Fill the vector with given [size] with given [value] */ @UnstableKMathAPI public fun Buffer.Companion.same(size: Int, value: Number): DoubleVector = double(size) { value.toDouble() } 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 c3556216d..1926ef02c 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 @@ -45,8 +45,8 @@ public fun Buffer.Companion.withFixedStep(range: ClosedFloatingPointRange { + val m = Sequence { listOf( DoubleArray(10) { 10.0 }, DoubleArray(10) { 20.0 }, diff --git a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleVectorTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt similarity index 97% rename from kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleVectorTest.kt rename to kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt index ec7b536ba..81e90fc07 100644 --- a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/DoubleVectorTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package kaceince.kmath.real +package space.kscience.kmath.real import space.kscience.kmath.linear.LinearSpace import space.kscience.kmath.linear.asMatrix diff --git a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/GridTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt similarity index 96% rename from kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/GridTest.kt rename to kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt index 0d3b80336..8fed8d10e 100644 --- a/kmath-for-real/src/commonTest/kotlin/kaceince/kmath/real/GridTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt @@ -3,7 +3,7 @@ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ -package kaceince.kmath.real +package space.kscience.kmath.real import space.kscience.kmath.misc.UnstableKMathAPI import space.kscience.kmath.real.DoubleVector diff --git a/kmath-functions/README.md b/kmath-functions/README.md index 2497f7102..d0beae2c8 100644 --- a/kmath-functions/README.md +++ b/kmath-functions/README.md @@ -11,7 +11,7 @@ Functions and interpolations. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-14`. **Gradle:** ```gradle @@ -21,7 +21,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-functions:0.3.0-dev-11' + 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-11") + implementation("space.kscience:kmath-functions:0.3.0-dev-14") } ``` diff --git a/kmath-functions/build.gradle.kts b/kmath-functions/build.gradle.kts index 622b8f8da..fadbac091 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -1,8 +1,11 @@ plugins { kotlin("multiplatform") id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } +description = "Functions, integration and interpolation" + kotlin.sourceSets.commonMain { dependencies { api(project(":kmath-core")) @@ -10,7 +13,6 @@ kotlin.sourceSets.commonMain { } readme { - description = "Functions, integration and interpolation" maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) @@ -29,4 +31,4 @@ readme { feature("integration") { "Univariate and multivariate quadratures" } -} \ No newline at end of file +} 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 73fa57c7b..16af7f555 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 @@ -14,7 +14,7 @@ import space.kscience.kmath.operations.Ring * @param T the piece key type. * @param R the sub-function type. */ -public fun interface Piecewise { +public fun interface Piecewise { /** * Returns the appropriate sub-function for given piece key. */ @@ -23,12 +23,14 @@ public fun interface Piecewise { /** * Represents piecewise-defined function where all the sub-functions are polynomials. - * @param pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no "holes" in it. + * + * @property pieces An ordered list of range-polynomial pairs. The list does not in general guarantee that there are no + * "holes" in it. */ public interface PiecewisePolynomial> : Piecewise> { public val pieces: Collection, Polynomial>> - public override fun findPiece(arg: T): Polynomial? + override fun findPiece(arg: T): Polynomial? } /** @@ -44,8 +46,8 @@ public fun > PiecewisePolynomial( } /** - * An optimized piecewise which uses not separate pieces, but a range separated by delimiters. - * The pices search is logarithmic + * An optimized piecewise that uses not separate pieces, but a range separated by delimiters. + * The pieces search is logarithmic. */ private class OrderedPiecewisePolynomial>( override val pieces: List, Polynomial>>, @@ -77,7 +79,7 @@ public class PiecewiseBuilder>(delimiter: T) { /** * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) * - * @param right new rightmost position. If is less then current rightmost position, an error is thrown. + * @param right new rightmost position. If is less than current rightmost position, an error is thrown. * @param piece the sub-function. */ public fun putRight(right: T, piece: Polynomial) { @@ -89,7 +91,7 @@ public class PiecewiseBuilder>(delimiter: T) { /** * Dynamically adds a piece to the left side (beyond maximum argument value of previous piece) * - * @param left the new leftmost position. If is less then current rightmost position, an error is thrown. + * @param left the new leftmost position. If is less than current rightmost position, an error is thrown. * @param piece the sub-function. */ public fun putLeft(left: T, piece: Polynomial) { @@ -112,7 +114,7 @@ public fun > PiecewisePolynomial( ): PiecewisePolynomial = PiecewiseBuilder(startingPoint).apply(builder).build() /** - * Return a value of polynomial function with given [ring] an given [arg] or null if argument is outside of piecewise + * Return a value of polynomial function with given [ring] a given [arg] or null if argument is outside piecewise * definition. */ public fun , C : Ring> PiecewisePolynomial.value(ring: C, arg: T): T? = 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 ba77d7b25..f0f744530 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 @@ -17,7 +17,7 @@ import kotlin.math.pow * * @param coefficients constant is the leftmost coefficient. */ -public class Polynomial(public val coefficients: List) { +public class Polynomial(public val coefficients: List) { override fun toString(): String = "Polynomial$coefficients" } @@ -69,7 +69,7 @@ public fun Polynomial.differentiate( public fun Polynomial.integrate( algebra: A, ): Polynomial where A : Field, A : NumericAlgebra = algebra { - val integratedCoefficients = buildList(coefficients.size + 1) { + val integratedCoefficients = buildList(coefficients.size + 1) { add(zero) coefficients.forEachIndexed{ index, t -> add(t / (number(index) + one)) } } @@ -98,13 +98,13 @@ public fun > Polynomial.integrate( public class PolynomialSpace( private val ring: C, ) : Group>, ScaleOperations> where C : Ring, C : ScaleOperations { - public override val zero: Polynomial = Polynomial(emptyList()) + override val zero: Polynomial = Polynomial(emptyList()) override fun Polynomial.unaryMinus(): Polynomial = ring { Polynomial(coefficients.map { -it }) } - public override fun add(a: Polynomial, b: Polynomial): Polynomial { + override fun add(a: Polynomial, b: Polynomial): Polynomial { val dim = max(a.coefficients.size, b.coefficients.size) return ring { @@ -114,7 +114,7 @@ public class PolynomialSpace( } } - public override fun scale(a: Polynomial, value: Double): Polynomial = + override fun scale(a: Polynomial, value: Double): Polynomial = ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) } /** 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 f794b075f..9b938394a 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 @@ -10,15 +10,17 @@ import space.kscience.kmath.structures.Buffer import space.kscience.kmath.structures.asBuffer import space.kscience.kmath.structures.indices - - /** * A simple one-pass integrator based on Gauss rule * Following integrand features are accepted: - * [GaussIntegratorRuleFactory] - A factory for computing the Gauss integration rule. By default uses [GaussLegendreRuleFactory] - * [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. - * [IntegrandMaxCalls] - the maximum number of function calls during integration. For non-iterative rules, always uses the maximum number of points. By default uses 10 points. - * [UnivariateIntegrandRanges] - Set of ranges and number of points per range. Defaults to given [IntegrationRange] and [IntegrandMaxCalls] + * + * * [GaussIntegratorRuleFactory]—a factory for computing the Gauss integration rule. By default, uses + * [GaussLegendreRuleFactory]. + * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. + * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always + * uses the maximum number of points. By default, uses 10 points. + * * [UnivariateIntegrandRanges]—set of ranges and number of points per range. Defaults to given + * [IntegrationRange] and [IntegrandMaxCalls]. */ public class GaussIntegrator( public val algebra: Field, @@ -71,14 +73,14 @@ public class GaussIntegrator( } /** - * Create a Gauss-Legendre integrator for this field + * Create a Gauss-Legendre integrator for this field. * @see [GaussIntegrator] */ -public val Field.gaussIntegrator: GaussIntegrator get() = GaussIntegrator(this) +public val Field.gaussIntegrator: GaussIntegrator get() = GaussIntegrator(this) /** - * Integrate using [intervals] segments with Gauss-Legendre rule of [order] order + * Integrate using [intervals] segments with Gauss-Legendre rule of [order] order. */ @UnstableKMathAPI public fun GaussIntegrator.integrate( 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 594ca9940..2eceec135 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 @@ -72,7 +72,7 @@ public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory { } // Get previous rule. - // If it has not been computed yet it will trigger a recursive call + // If it has not been computed, yet it will trigger a recursive call // to this method. val previousPoints: Buffer = getOrBuildRule(numPoints - 1).first @@ -146,7 +146,7 @@ public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory { } // If "numPoints" is odd, 0 is a root. // Note: as written, the test for oddness will work for negative - // integers too (although it is not necessary here), preventing + // integers too (although it is unnecessary here), preventing // a FindBugs warning. if (numPoints % 2 != 0) { var pmc = 1.0 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 f90159c81..05e2e5c55 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 @@ -21,7 +21,7 @@ public interface Integrand : Featured { public inline fun Integrand.getFeature(): T? = getFeature(T::class) -public class IntegrandValue(public val value: T) : IntegrandFeature { +public class IntegrandValue(public val value: T) : IntegrandFeature { override fun toString(): String = "Value($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 77f01101a..7815757aa 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 @@ -13,9 +13,10 @@ import space.kscience.kmath.operations.sum /** * Use double pass Simpson rule integration with a fixed number of points. - * Requires [UnivariateIntegrandRanges] or [IntegrationRange] and [IntegrandMaxCalls] - * [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. - * [IntegrandMaxCalls] - the maximum number of function calls during integration. For non-iterative rules, always uses the maximum number of points. By default uses 10 points. + * Requires [UnivariateIntegrandRanges] or [IntegrationRange] and [IntegrandMaxCalls]. + * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. + * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always + * uses the maximum number of points. By default, uses 10 points. */ @UnstableKMathAPI public class SimpsonIntegrator( @@ -63,12 +64,12 @@ public val Field.simpsonIntegrator: SimpsonIntegrator get() = Si /** * Use double pass Simpson rule integration with a fixed number of points. - * Requires [UnivariateIntegrandRanges] or [IntegrationRange] and [IntegrandMaxCalls] - * [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. - * [IntegrandMaxCalls] - the maximum number of function calls during integration. For non-iterative rules, always uses the maximum number of points. By default uses 10 points. + * Requires [UnivariateIntegrandRanges] or [IntegrationRange] and [IntegrandMaxCalls]. + * * [IntegrationRange]—the univariate range of integration. By default, uses `0.0..1.0` interval. + * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always uses + * the maximum number of points. By default, uses 10 points. */ public object DoubleSimpsonIntegrator : UnivariateIntegrator { - private fun integrateRange( integrand: UnivariateIntegrand, range: ClosedRange, numPoints: Int, ): Double { 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 54fa29e83..a863e1031 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 @@ -45,8 +45,9 @@ public fun > PiecewisePolynomial.integrate( /** * A generic spline-interpolation-based analytic integration - * [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. - * [IntegrandMaxCalls] - the maximum number of function calls during integration. For non-iterative rules, always uses the maximum number of points. By default uses 10 points. + * * [IntegrationRange]—the univariate range of integration. By default, uses `0..1` interval. + * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always uses + * the maximum number of points. By default, uses 10 points. */ @UnstableKMathAPI public class SplineIntegrator>( @@ -57,6 +58,7 @@ public class SplineIntegrator>( val range = integrand.getFeature()?.range ?: 0.0..1.0 val interpolator: PolynomialInterpolator = SplineInterpolator(algebra, bufferFactory) + val nodes: Buffer = integrand.getFeature()?.nodes ?: run { val numPoints = integrand.getFeature()?.maxCalls ?: 100 val step = (range.endInclusive - range.start) / (numPoints - 1) @@ -75,15 +77,16 @@ public class SplineIntegrator>( /** * A simplified double-based spline-interpolation-based analytic integration - * [IntegrationRange] - the univariate range of integration. By default uses 0..1 interval. - * [IntegrandMaxCalls] - the maximum number of function calls during integration. For non-iterative rules, always uses the maximum number of points. By default uses 10 points. + * * [IntegrationRange]—the univariate range of integration. By default, uses `0.0..1.0` interval. + * * [IntegrandMaxCalls]—the maximum number of function calls during integration. For non-iterative rules, always + * uses the maximum number of points. By default, uses 10 points. */ @UnstableKMathAPI public object DoubleSplineIntegrator : UnivariateIntegrator { override fun process(integrand: UnivariateIntegrand): UnivariateIntegrand { val range = integrand.getFeature()?.range ?: 0.0..1.0 - val interpolator: PolynomialInterpolator = SplineInterpolator(DoubleField, ::DoubleBuffer) + val nodes: Buffer = integrand.getFeature()?.nodes ?: run { val numPoints = integrand.getFeature()?.maxCalls ?: 100 val step = (range.endInclusive - range.start) / (numPoints - 1) 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 82fed30cd..6fd75e6e6 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 @@ -31,8 +31,8 @@ public class IntegrationRange(public val range: ClosedRange) : Integrand } /** - * Set of univariate integration ranges. First components correspond to ranges themselves, second components to number of - * integration nodes per range + * Set of univariate integration ranges. First components correspond to the ranges themselves, second components to + * number of integration nodes per range. */ public class UnivariateIntegrandRanges(public val ranges: List, Int>>) : IntegrandFeature { public constructor(vararg pairs: Pair, Int>) : this(pairs.toList()) @@ -84,7 +84,7 @@ public fun UnivariateIntegrator.integrate( ): UnivariateIntegrand = process(UnivariateIntegrand(function, IntegrationRange(range), *features)) /** - * A shortcut method to integrate a [function] in [range] with additional [features]. + * A shortcut method to integrate a [function] in [range] with additional features. * The [function] is placed in the end position to allow passing a lambda. */ @UnstableKMathAPI 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 c9ec0d527..f4a0abd5d 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 @@ -18,7 +18,7 @@ import space.kscience.kmath.structures.asBuffer /** * And interpolator for data with x column type [X], y column type [Y]. */ -public fun interface Interpolator { +public fun interface Interpolator { public fun interpolate(points: XYColumnarData): (X) -> Y } 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 24c049647..edd0e6b0a 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 @@ -21,9 +21,9 @@ 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>(public override val algebra: Field) : PolynomialInterpolator { +public class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { @OptIn(UnstableKMathAPI::class) - public override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { + override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { require(points.size > 0) { "Point array should not be empty" } insureSorted(points) 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 bf291c315..39c33ee69 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 @@ -23,13 +23,13 @@ import space.kscience.kmath.structures.MutableBufferFactory * https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java */ public class SplineInterpolator>( - public override val algebra: Field, + override val algebra: Field, public val bufferFactory: MutableBufferFactory, ) : PolynomialInterpolator { //TODO possibly optimize zeroed buffers @OptIn(UnstableKMathAPI::class) - public override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { + override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { require(points.size >= 3) { "Can't use spline interpolator with less than 3 points" } insureSorted(points) // Number of intervals. The number of data points is n + 1. diff --git a/kmath-geometry/build.gradle.kts b/kmath-geometry/build.gradle.kts index 9b6e593b2..7eb814683 100644 --- a/kmath-geometry/build.gradle.kts +++ b/kmath-geometry/build.gradle.kts @@ -1,6 +1,7 @@ plugins { kotlin("multiplatform") id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } kotlin.sourceSets.commonMain { 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 2a4837ee0..2b91c2334 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 @@ -15,15 +15,15 @@ import kotlin.math.sqrt public interface Vector2D : Point, Vector{ public val x: Double public val y: Double - public override val size: Int get() = 2 + override val size: Int get() = 2 - public override operator fun get(index: Int): Double = when (index) { + override operator fun get(index: Int): Double = when (index) { 1 -> x 2 -> y else -> error("Accessing outside of point bounds") } - public override operator fun iterator(): Iterator = listOf(x, y).iterator() + override operator fun iterator(): Iterator = listOf(x, y).iterator() } public val Vector2D.r: Double @@ -41,13 +41,13 @@ private data class Vector2DImpl( * 2D Euclidean space */ public object Euclidean2DSpace : GeometrySpace, ScaleOperations { - public override val zero: Vector2D by lazy { Vector2D(0.0, 0.0) } + override val zero: Vector2D by lazy { Vector2D(0.0, 0.0) } public fun Vector2D.norm(): Double = sqrt(x * x + y * y) override fun Vector2D.unaryMinus(): Vector2D = Vector2D(-x, -y) - public override fun Vector2D.distanceTo(other: Vector2D): Double = (this - other).norm() - public override fun add(a: Vector2D, b: Vector2D): Vector2D = Vector2D(a.x + b.x, a.y + b.y) - public override fun scale(a: Vector2D, value: Double): Vector2D = Vector2D(a.x * value, a.y * value) - public override fun Vector2D.dot(other: Vector2D): Double = x * other.x + y * other.y + override fun Vector2D.distanceTo(other: Vector2D): Double = (this - other).norm() + override fun add(a: Vector2D, b: Vector2D): Vector2D = Vector2D(a.x + b.x, a.y + b.y) + override fun scale(a: Vector2D, value: Double): Vector2D = Vector2D(a.x * value, a.y * value) + override fun Vector2D.dot(other: Vector2D): Double = x * other.x + y * other.y } diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt index 37e7d2cb2..628106b0b 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt @@ -16,16 +16,16 @@ public interface Vector3D : Point, Vector { public val x: Double public val y: Double public val z: Double - public override val size: Int get() = 3 + override val size: Int get() = 3 - public override operator fun get(index: Int): Double = when (index) { + override operator fun get(index: Int): Double = when (index) { 1 -> x 2 -> y 3 -> z else -> error("Accessing outside of point bounds") } - public override operator fun iterator(): Iterator = listOf(x, y, z).iterator() + override operator fun iterator(): Iterator = listOf(x, y, z).iterator() } @Suppress("FunctionName") @@ -40,19 +40,19 @@ private data class Vector3DImpl( ) : Vector3D public object Euclidean3DSpace : GeometrySpace, ScaleOperations { - public override val zero: Vector3D by lazy { Vector3D(0.0, 0.0, 0.0) } + override val zero: Vector3D by lazy { Vector3D(0.0, 0.0, 0.0) } public fun Vector3D.norm(): Double = sqrt(x * x + y * y + z * z) override fun Vector3D.unaryMinus(): Vector3D = Vector3D(-x, -y, -z) - public override fun Vector3D.distanceTo(other: Vector3D): Double = (this - other).norm() + override fun Vector3D.distanceTo(other: Vector3D): Double = (this - other).norm() - public override fun add(a: Vector3D, b: Vector3D): Vector3D = + override fun add(a: Vector3D, b: Vector3D): Vector3D = Vector3D(a.x + b.x, a.y + b.y, a.z + b.z) - public override fun scale(a: Vector3D, value: Double): Vector3D = + override fun scale(a: Vector3D, value: Double): Vector3D = Vector3D(a.x * value, a.y * value, a.z * value) - public override fun Vector3D.dot(other: Vector3D): Double = + override fun Vector3D.dot(other: Vector3D): Double = x * other.x + y * other.y + z * other.z } diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt index 5a6d23709..8c6ccb55e 100644 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt +++ b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt @@ -5,7 +5,7 @@ package space.kscience.kmath.geometry -public data class Line(val base: V, val direction: V) +public data class Line(val base: V, val direction: V) public typealias Line2D = Line public typealias Line3D = Line diff --git a/kmath-histograms/build.gradle.kts b/kmath-histograms/build.gradle.kts index 2167726c0..7e511faa0 100644 --- a/kmath-histograms/build.gradle.kts +++ b/kmath-histograms/build.gradle.kts @@ -1,6 +1,7 @@ plugins { kotlin("multiplatform") id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } kscience { 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 fcb5e96dc..4e803fc63 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 @@ -11,16 +11,16 @@ import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.asBuffer /** - * The binned data element. Could be a histogram bin with a number of counts or an artificial construct + * The binned data element. Could be a histogram bin with a number of counts or an artificial construct. */ -public interface Bin : Domain { +public interface Bin : Domain { /** * The value of this bin. */ public val value: Number } -public interface Histogram> { +public interface Histogram> { /** * Find existing bin, corresponding to given coordinates */ @@ -34,7 +34,7 @@ public interface Histogram> { public val bins: Iterable } -public fun interface HistogramBuilder { +public fun interface HistogramBuilder { /** * Increment appropriate bin 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 e5f6830c5..79b6b4e02 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 @@ -18,9 +18,9 @@ import space.kscience.kmath.operations.invoke /** * A simple histogram bin based on domain */ -public data class DomainBin>( +public data class DomainBin>( public val domain: Domain, - public override val value: Number, + override val value: Number, ) : Bin, Domain by domain @OptIn(UnstableKMathAPI::class) 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 6ae8b5ee3..daea4a82e 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 @@ -35,51 +35,57 @@ public class TreeHistogram( override val bins: Collection get() = binMap.values } +@OptIn(UnstableKMathAPI::class) +@PublishedApi +internal class TreeHistogramBuilder(val binFactory: (Double) -> UnivariateDomain) : UnivariateHistogramBuilder { + + internal class BinCounter(val domain: UnivariateDomain, val counter: Counter = Counter.real()) : + ClosedFloatingPointRange by domain.range + + private val bins: TreeMap = TreeMap() + + fun get(value: Double): BinCounter? = bins.getBin(value) + + fun createBin(value: Double): BinCounter { + val binDefinition = binFactory(value) + val newBin = BinCounter(binDefinition) + synchronized(this) { bins[binDefinition.center] = newBin } + return newBin + } + + /** + * Thread safe put operation + */ + override fun putValue(at: Double, value: Double) { + (get(at) ?: createBin(at)).apply { + counter.add(value) + } + } + + override fun putValue(point: Buffer, value: Number) { + require(point.size == 1) { "Only points with single value could be used in univariate histogram" } + putValue(point[0], value.toDouble()) + } + + fun build(): TreeHistogram { + val map = bins.mapValuesTo(TreeMap()) { (_, binCounter) -> + val count = binCounter.counter.value + UnivariateBin(binCounter.domain, count, sqrt(count)) + } + return TreeHistogram(map) + } +} + /** * A space for univariate histograms with variable bin borders based on a tree map */ @UnstableKMathAPI public class TreeHistogramSpace( - public val binFactory: (Double) -> UnivariateDomain, + @PublishedApi internal val binFactory: (Double) -> UnivariateDomain, ) : Group, ScaleOperations { - private class BinCounter(val domain: UnivariateDomain, val counter: Counter = Counter.real()) : - ClosedFloatingPointRange by domain.range - - public fun produce(builder: UnivariateHistogramBuilder.() -> Unit): UnivariateHistogram { - val bins: TreeMap = TreeMap() - val hBuilder = object : UnivariateHistogramBuilder { - - fun get(value: Double): BinCounter? = bins.getBin(value) - - fun createBin(value: Double): BinCounter { - val binDefinition = binFactory(value) - val newBin = BinCounter(binDefinition) - synchronized(this) { bins[binDefinition.center] = newBin } - return newBin - } - - /** - * Thread safe put operation - */ - override fun putValue(at: Double, value: Double) { - (get(at) ?: createBin(at)).apply { - counter.add(value) - } - } - - override fun putValue(point: Buffer, value: Number) { - put(point[0], value.toDouble()) - } - } - hBuilder.apply(builder) - val resBins = TreeMap() - bins.forEach { (key, binCounter) -> - val count = binCounter.counter.value - resBins[key] = UnivariateBin(binCounter.domain, count, sqrt(count)) - } - return TreeHistogram(resBins) - } + public inline fun fill(block: UnivariateHistogramBuilder.() -> Unit): UnivariateHistogram = + TreeHistogramBuilder(binFactory).apply(block).build() override fun add( a: UnivariateHistogram, @@ -89,7 +95,8 @@ public class TreeHistogramSpace( // require(b.context == this) { "Histogram $b does not belong to this context" } val bins = TreeMap().apply { (a.bins.map { it.domain } union b.bins.map { it.domain }).forEach { def -> - put(def.center, + put( + def.center, UnivariateBin( def, value = (a[def.center]?.value ?: 0.0) + (b[def.center]?.value ?: 0.0), @@ -105,11 +112,12 @@ public class TreeHistogramSpace( override fun scale(a: UnivariateHistogram, value: Double): UnivariateHistogram { val bins = TreeMap().apply { a.bins.forEach { bin -> - put(bin.domain.center, + put( + bin.domain.center, UnivariateBin( bin.domain, - value = bin.value * value.toDouble(), - standardDeviation = abs(bin.standardDeviation * value.toDouble()) + value = bin.value * value, + standardDeviation = abs(bin.standardDeviation * value) ) ) } @@ -120,7 +128,7 @@ public class TreeHistogramSpace( override fun UnivariateHistogram.unaryMinus(): UnivariateHistogram = this * (-1) - override val zero: UnivariateHistogram = produce { } + override val zero: UnivariateHistogram by lazy { fill { } } public companion object { /** 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 70125e22e..ca37279c3 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 @@ -13,12 +13,13 @@ import space.kscience.kmath.structures.asSequence @UnstableKMathAPI public val UnivariateDomain.center: Double - get() = (range.endInclusive - range.start) / 2 + get() = (range.endInclusive + range.start) / 2 /** - * A univariate bin based an a range - * @param value The value of histogram including weighting - * @param standardDeviation Standard deviation of the bin value. Zero or negative if not applicable + * A univariate bin based on a range + * + * @property value The value of histogram including weighting + * @property standardDeviation Standard deviation of the bin value. Zero or negative if not applicable */ @UnstableKMathAPI public class UnivariateBin( @@ -27,15 +28,15 @@ public class UnivariateBin( public val standardDeviation: Double, ) : Bin, ClosedFloatingPointRange by domain.range { - public override val dimension: Int get() = 1 + override val dimension: Int get() = 1 - public override fun contains(point: Buffer): Boolean = point.size == 1 && contains(point[0]) + override fun contains(point: Buffer): Boolean = point.size == 1 && contains(point[0]) } @OptIn(UnstableKMathAPI::class) public interface UnivariateHistogram : Histogram{ public operator fun get(value: Double): UnivariateBin? - public override operator fun get(point: Buffer): UnivariateBin? = get(point[0]) + override operator fun get(point: Buffer): UnivariateBin? = get(point[0]) public companion object { /** @@ -45,7 +46,7 @@ public interface UnivariateHistogram : Histogram{ binSize: Double, start: Double = 0.0, builder: UnivariateHistogramBuilder.() -> Unit, - ): UnivariateHistogram = TreeHistogramSpace.uniform(binSize, start).produce(builder) + ): UnivariateHistogram = TreeHistogramSpace.uniform(binSize, start).fill(builder) /** * Build and fill a histogram with custom borders. Returns a read-only histogram. @@ -53,7 +54,7 @@ public interface UnivariateHistogram : Histogram{ public fun custom( borders: DoubleArray, builder: UnivariateHistogramBuilder.() -> Unit, - ): UnivariateHistogram = TreeHistogramSpace.custom(borders).produce(builder) + ): 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 new file mode 100644 index 000000000..28a1b03cb --- /dev/null +++ b/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt @@ -0,0 +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. + */ + +package space.kscience.kmath.histogram + +import org.junit.jupiter.api.Test +import kotlin.random.Random +import kotlin.test.assertTrue + +class TreeHistogramTest { + + @Test + fun normalFill() { + val histogram = UnivariateHistogram.uniform(0.1) { + repeat(100_000) { + putValue(Random.nextDouble()) + } + } + + assertTrue { histogram.bins.count() > 10 } + } +} \ No newline at end of file diff --git a/kmath-jafama/README.md b/kmath-jafama/README.md new file mode 100644 index 000000000..3c5d4e19d --- /dev/null +++ b/kmath-jafama/README.md @@ -0,0 +1,55 @@ +# Module kmath-jafama + +Integration with [Jafama](https://github.com/jeffhain/jafama). + + - [jafama-double](src/main/kotlin/space/kscience/kmath/jafama/) : Double ExtendedField implementations based on Jafama + + +## Artifact: + +The Maven coordinates of this project are `space.kscience:kmath-jafama:0.3.0-dev-14`. + +**Gradle:** +```gradle +repositories { + maven { url 'https://repo.kotlin.link' } + mavenCentral() +} + +dependencies { + implementation 'space.kscience:kmath-jafama:0.3.0-dev-14' +} +``` +**Gradle Kotlin DSL:** +```kotlin +repositories { + maven("https://repo.kotlin.link") + mavenCentral() +} + +dependencies { + implementation("space.kscience:kmath-jafama:0.3.0-dev-14") +} +``` + +## Example usage + +All the `DoubleField` uses can be replaced with `JafamaDoubleField` or `StrictJafamaDoubleField`. + +```kotlin +import space.kscience.kmath.jafama.* +import space.kscience.kmath.operations.* + +fun main() { + val a = 2.0 + val b = StrictJafamaDoubleField { exp(a) } + println(JafamaDoubleField { b + a }) + println(StrictJafamaDoubleField { ln(b) }) +} +``` + +## Performance + +According to KMath benchmarks on GraalVM, Jafama functions are slower than JDK math; however, there are indications that on Hotspot Jafama is a bit faster. + +> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**. diff --git a/kmath-jafama/build.gradle.kts b/kmath-jafama/build.gradle.kts new file mode 100644 index 000000000..9cf328d0b --- /dev/null +++ b/kmath-jafama/build.gradle.kts @@ -0,0 +1,27 @@ +plugins { + id("ru.mipt.npm.gradle.jvm") +} + +description = "Jafama integration module" + +dependencies { + api(project(":kmath-core")) + api("net.jafama:jafama:2.3.2") +} + +repositories { + mavenCentral() +} + +readme { + maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE + propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) + + feature("jafama-double", "src/main/kotlin/space/kscience/kmath/jafama/") { + "Double ExtendedField implementations based on Jafama" + } +} + +kotlin.sourceSets.all { + languageSettings.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") +} diff --git a/kmath-jafama/docs/README-TEMPLATE.md b/kmath-jafama/docs/README-TEMPLATE.md new file mode 100644 index 000000000..54348467b --- /dev/null +++ b/kmath-jafama/docs/README-TEMPLATE.md @@ -0,0 +1,29 @@ +# Module kmath-jafama + +Integration with [Jafama](https://github.com/jeffhain/jafama). + +${features} + +${artifact} + +## Example usage + +All the `DoubleField` uses can be replaced with `JafamaDoubleField` or `StrictJafamaDoubleField`. + +```kotlin +import space.kscience.kmath.jafama.* +import space.kscience.kmath.operations.* + +fun main() { + val a = 2.0 + val b = StrictJafamaDoubleField { exp(a) } + println(JafamaDoubleField { b + a }) + println(StrictJafamaDoubleField { ln(b) }) +} +``` + +## Performance + +According to KMath benchmarks on GraalVM, Jafama functions are slower than JDK math; however, there are indications that on Hotspot Jafama is a bit faster. + +${benchmarkJafamaDouble} 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 new file mode 100644 index 000000000..a30020dff --- /dev/null +++ b/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt @@ -0,0 +1,110 @@ +package space.kscience.kmath.jafama + +import net.jafama.FastMath +import net.jafama.StrictFastMath +import space.kscience.kmath.operations.ExtendedField +import space.kscience.kmath.operations.Norm +import space.kscience.kmath.operations.PowerOperations +import space.kscience.kmath.operations.ScaleOperations + +/** + * A field for [Double] (using FastMath) without boxing. Does not produce appropriate field element. + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +public object JafamaDoubleField : ExtendedField, Norm, ScaleOperations { + override inline val zero: Double get() = 0.0 + override inline val one: Double get() = 1.0 + + override inline fun number(value: Number): Double = value.toDouble() + + override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = + when (operation) { + PowerOperations.POW_OPERATION -> ::power + else -> super.binaryOperationFunction(operation) + } + + override inline fun add(a: Double, b: Double): Double = a + b + + 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 + + override inline fun sin(arg: Double): Double = FastMath.sin(arg) + override inline fun cos(arg: Double): Double = FastMath.cos(arg) + override inline fun tan(arg: Double): Double = FastMath.tan(arg) + override inline fun acos(arg: Double): Double = FastMath.acos(arg) + override inline fun asin(arg: Double): Double = FastMath.asin(arg) + override inline fun atan(arg: Double): Double = FastMath.atan(arg) + + override inline fun sinh(arg: Double): Double = FastMath.sinh(arg) + override inline fun cosh(arg: Double): Double = FastMath.cosh(arg) + override inline fun tanh(arg: Double): Double = FastMath.tanh(arg) + override inline fun asinh(arg: Double): Double = FastMath.asinh(arg) + override inline fun acosh(arg: Double): Double = FastMath.acosh(arg) + override inline fun atanh(arg: Double): Double = FastMath.atanh(arg) + + override inline fun sqrt(arg: Double): Double = FastMath.sqrt(arg) + override inline fun power(arg: Double, pow: Number): Double = FastMath.pow(arg, pow.toDouble()) + override inline fun exp(arg: Double): Double = FastMath.exp(arg) + override inline fun ln(arg: Double): Double = FastMath.log(arg) + + override inline fun norm(arg: Double): Double = FastMath.abs(arg) + + override inline fun Double.unaryMinus(): Double = -this + 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 +} + +/** + * A field for [Double] (using StrictMath) without boxing. Does not produce appropriate field element. + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +public object StrictJafamaDoubleField : ExtendedField, Norm, ScaleOperations { + override inline val zero: Double get() = 0.0 + override inline val one: Double get() = 1.0 + + override inline fun number(value: Number): Double = value.toDouble() + + override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double = + when (operation) { + PowerOperations.POW_OPERATION -> ::power + else -> super.binaryOperationFunction(operation) + } + + override inline fun add(a: Double, b: Double): Double = a + b + + 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 + + override inline fun sin(arg: Double): Double = StrictFastMath.sin(arg) + override inline fun cos(arg: Double): Double = StrictFastMath.cos(arg) + override inline fun tan(arg: Double): Double = StrictFastMath.tan(arg) + override inline fun acos(arg: Double): Double = StrictFastMath.acos(arg) + override inline fun asin(arg: Double): Double = StrictFastMath.asin(arg) + override inline fun atan(arg: Double): Double = StrictFastMath.atan(arg) + + override inline fun sinh(arg: Double): Double = StrictFastMath.sinh(arg) + override inline fun cosh(arg: Double): Double = StrictFastMath.cosh(arg) + override inline fun tanh(arg: Double): Double = StrictFastMath.tanh(arg) + override inline fun asinh(arg: Double): Double = StrictFastMath.asinh(arg) + override inline fun acosh(arg: Double): Double = StrictFastMath.acosh(arg) + override inline fun atanh(arg: Double): Double = StrictFastMath.atanh(arg) + + override inline fun sqrt(arg: Double): Double = StrictFastMath.sqrt(arg) + override inline fun power(arg: Double, pow: Number): Double = StrictFastMath.pow(arg, pow.toDouble()) + override inline fun exp(arg: Double): Double = StrictFastMath.exp(arg) + override inline fun ln(arg: Double): Double = StrictFastMath.log(arg) + + override inline fun norm(arg: Double): Double = StrictFastMath.abs(arg) + + override inline fun Double.unaryMinus(): Double = -this + 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 +} diff --git a/kmath-jupyter/build.gradle.kts b/kmath-jupyter/build.gradle.kts index 83a6a771a..5bd08c485 100644 --- a/kmath-jupyter/build.gradle.kts +++ b/kmath-jupyter/build.gradle.kts @@ -20,3 +20,7 @@ readme { kotlin.sourceSets.all { languageSettings.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") } + +tasks.processJupyterApiResources { + libraryProducers = listOf("space.kscience.kmath.jupyter.KMathJupyter") +} diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md index 4393cbf8c..aeb44ea13 100644 --- a/kmath-kotlingrad/README.md +++ b/kmath-kotlingrad/README.md @@ -1,14 +1,14 @@ # Module kmath-kotlingrad -[Kotlin∇](https://www.htmlsymbols.xyz/unicode/U+2207) integration module. +[Kotlin∇](https://github.com/breandan/kotlingrad) integration module. - - [differentiable-mst-expression](src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt) : MST based DifferentiableExpression. - - [differentiable-mst-expression](src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt) : Conversions between Kotlin∇'s SFun and MST + - [differentiable-mst-expression](src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt) : MST based DifferentiableExpression. + - [scalars-adapters](src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt) : Conversions between Kotlin∇'s SFun and MST ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-kotlingrad:0.3.0-dev-14`. **Gradle:** ```gradle @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-11' + implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-14' } ``` **Gradle Kotlin DSL:** @@ -29,6 +29,6 @@ repositories { } dependencies { - implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-11") + implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-14") } ``` diff --git a/kmath-kotlingrad/build.gradle.kts b/kmath-kotlingrad/build.gradle.kts index 01b42d7ba..d222ed7d6 100644 --- a/kmath-kotlingrad/build.gradle.kts +++ b/kmath-kotlingrad/build.gradle.kts @@ -18,14 +18,14 @@ readme { feature( "differentiable-mst-expression", - "src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt", + "src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt", ) { "MST based DifferentiableExpression." } feature( - "differentiable-mst-expression", - "src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt", + "scalars-adapters", + "src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt", ) { "Conversions between Kotlin∇'s SFun and MST" } diff --git a/kmath-kotlingrad/docs/README-TEMPLATE.md b/kmath-kotlingrad/docs/README-TEMPLATE.md index ac38c849b..bc99bdf5f 100644 --- a/kmath-kotlingrad/docs/README-TEMPLATE.md +++ b/kmath-kotlingrad/docs/README-TEMPLATE.md @@ -1,6 +1,6 @@ # Module kmath-kotlingrad -[Kotlin∇](https://www.htmlsymbols.xyz/unicode/U+2207) integration module. +[Kotlin∇](https://github.com/breandan/kotlingrad) integration module. ${features} diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt index 9c9d07b81..f4386f434 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt @@ -16,15 +16,15 @@ import space.kscience.kmath.operations.NumericAlgebra * @property algebra The algebra. * @property value The value of this number. */ -public class KMathNumber(public val algebra: A, public override val value: T) : +public class KMathNumber(public val algebra: A, override val value: T) : SConst>(value) where T : Number, A : NumericAlgebra { /** * Returns a string representation of the [value]. */ - public override fun toString(): String = value.toString() + override fun toString(): String = value.toString() /** * Wraps [Number] to [KMathNumber]. */ - public override fun wrap(number: Number): KMathNumber = KMathNumber(algebra, algebra.number(number)) + override fun wrap(number: Number): KMathNumber = KMathNumber(algebra, algebra.number(number)) } diff --git a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt index a59c301cf..0d4e457af 100644 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt +++ b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt @@ -25,9 +25,9 @@ public class KotlingradExpression>( public val algebra: A, public val mst: MST, ) : SpecialDifferentiableExpression> { - public override fun invoke(arguments: Map): T = mst.interpret(algebra, arguments) + override fun invoke(arguments: Map): T = mst.interpret(algebra, arguments) - public override fun derivativeOrNull( + override fun derivativeOrNull( symbols: List, ): KotlingradExpression = KotlingradExpression( algebra, @@ -50,7 +50,7 @@ public class KotlingradProcessor>( } /** - * Wraps this [MST] into [KotlingradExpression]. + * Wraps this [MST] into [KotlingradExpression] in the context of [algebra]. */ public fun > MST.toKotlingradExpression(algebra: A): KotlingradExpression = KotlingradExpression(algebra, 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 57fe2411c..9378adfea 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 @@ -20,8 +20,7 @@ import kotlin.test.fail internal class AdaptingTests { @Test fun symbol() { - val c1 = MstNumericAlgebra.bindSymbol(x.identity) - assertEquals(x.identity, c1.toSVar>().name) + assertEquals(x.identity, x.toSVar>().name) val c2 = "kitten".parseMath().toSFun>() if (c2 is SVar) assertTrue(c2.name == "kitten") else fail() } @@ -46,7 +45,7 @@ internal class AdaptingTests { @Test fun simpleFunctionDerivative() { - val xSVar = MstNumericAlgebra.bindSymbol(x.identity).toSVar>() + val xSVar = x.toSVar>() val quadratic = "x^2-4*x-44".parseMath().toSFun>() val actualDerivative = quadratic.d(xSVar).toMst().compileToExpression(DoubleField) val expectedDerivative = "2*x-4".parseMath().compileToExpression(DoubleField) @@ -55,7 +54,7 @@ internal class AdaptingTests { @Test fun moreComplexDerivative() { - val xSVar = MstNumericAlgebra.bindSymbol(x.identity).toSVar>() + val xSVar = x.toSVar>() val composition = "-sqrt(sin(x^2)-cos(x)^2-16*x)".parseMath().toSFun>() val actualDerivative = composition.d(xSVar).toMst().compileToExpression(DoubleField) 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 930b21095..e8e51e9e2 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 @@ -156,6 +156,6 @@ public expect fun Memory.Companion.allocate(length: Int): Memory /** * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently from the resulting [Memory]. + * and could be mutated independently of the resulting [Memory]. */ public expect fun Memory.Companion.wrap(array: ByteArray): 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 9a622ea36..6153743fc 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 @@ -95,7 +95,7 @@ public actual fun Memory.Companion.allocate(length: Int): Memory { /** * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently from the resulting [Memory]. + * and could be mutated independently of the resulting [Memory]. */ public actual fun Memory.Companion.wrap(array: ByteArray): Memory { @Suppress("CAST_NEVER_SUCCEEDS") val int8Array = array as Int8Array 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 944e8455b..aef68fd80 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 @@ -103,7 +103,7 @@ public actual fun Memory.Companion.allocate(length: Int): Memory = /** * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently from the resulting [Memory]. + * and could be mutated independently of the resulting [Memory]. */ public actual fun Memory.Companion.wrap(array: ByteArray): Memory = ByteBufferMemory(checkNotNull(ByteBuffer.wrap(array))) 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 d31c9e8f4..5146d9689 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 @@ -60,7 +60,7 @@ internal class NativeMemory( } override fun writeByte(offset: Int, value: Byte) { - array.set(position(offset), value) + array[position(offset)] = value } override fun writeShort(offset: Int, value: Short) { @@ -85,7 +85,7 @@ internal class NativeMemory( /** * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently from the resulting [Memory]. + * and could be mutated independently of the resulting [Memory]. */ public actual fun Memory.Companion.wrap(array: ByteArray): Memory = NativeMemory(array) diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md index 6408be13b..5cbb31d5a 100644 --- a/kmath-nd4j/README.md +++ b/kmath-nd4j/README.md @@ -9,7 +9,7 @@ ND4J based implementations of KMath abstractions. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-14`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-nd4j:0.3.0-dev-11' + 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-11") + 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 abcc02962..dcb6f1b4a 100644 --- a/kmath-nd4j/build.gradle.kts +++ b/kmath-nd4j/build.gradle.kts @@ -7,10 +7,9 @@ description = "ND4J NDStructure implementation and according NDAlgebra classes" dependencies { api(project(":kmath-tensors")) - api("org.nd4j:nd4j-api:1.0.0-beta7") - testImplementation("org.nd4j:nd4j-native:1.0.0-beta7") - testImplementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") - testImplementation("org.slf4j:slf4j-simple:1.7.30") + 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.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 e94bda12a..f69f831e8 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 @@ -35,24 +35,24 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND /** - * Unwraps to or acquires [INDArray] from [StructureND]. + * Unwraps to or get [INDArray] from [StructureND]. */ public val StructureND.ndArray: INDArray - public override fun produce(initializer: C.(IntArray) -> T): Nd4jArrayStructure { + override fun produce(initializer: C.(IntArray) -> T): Nd4jArrayStructure { val struct = Nd4j.create(*shape)!!.wrap() struct.indicesIterator().forEach { struct[it] = elementContext.initializer(it) } return struct } @PerformancePitfall - public override fun StructureND.map(transform: C.(T) -> T): Nd4jArrayStructure { + override fun StructureND.map(transform: C.(T) -> T): Nd4jArrayStructure { val newStruct = ndArray.dup().wrap() newStruct.elements().forEach { (idx, value) -> newStruct[idx] = elementContext.transform(value) } return newStruct } - public override fun StructureND.mapIndexed( + override fun StructureND.mapIndexed( transform: C.(index: IntArray, T) -> T, ): Nd4jArrayStructure { val new = Nd4j.create(*this@Nd4jArrayAlgebra.shape).wrap() @@ -60,7 +60,7 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND, b: StructureND, transform: C.(T, T) -> T, @@ -79,16 +79,16 @@ public sealed interface Nd4jArrayAlgebra> : AlgebraND> : GroupND, Nd4jArrayAlgebra { - public override val zero: Nd4jArrayStructure + override val zero: Nd4jArrayStructure get() = Nd4j.zeros(*shape).wrap() - public override fun add(a: StructureND, b: StructureND): Nd4jArrayStructure = + override fun add(a: StructureND, b: StructureND): Nd4jArrayStructure = a.ndArray.add(b.ndArray).wrap() - public override operator fun StructureND.minus(b: StructureND): Nd4jArrayStructure = + override operator fun StructureND.minus(b: StructureND): Nd4jArrayStructure = ndArray.sub(b.ndArray).wrap() - public override operator fun StructureND.unaryMinus(): Nd4jArrayStructure = + override operator fun StructureND.unaryMinus(): Nd4jArrayStructure = ndArray.neg().wrap() public fun multiply(a: StructureND, k: Number): Nd4jArrayStructure = @@ -104,23 +104,23 @@ public sealed interface Nd4jArrayGroup> : GroupND, Nd4j @OptIn(UnstableKMathAPI::class) public sealed interface Nd4jArrayRing> : RingND, Nd4jArrayGroup { - public override val one: Nd4jArrayStructure + override val one: Nd4jArrayStructure get() = Nd4j.ones(*shape).wrap() - public override fun multiply(a: StructureND, b: StructureND): Nd4jArrayStructure = + override fun multiply(a: StructureND, b: StructureND): Nd4jArrayStructure = a.ndArray.mul(b.ndArray).wrap() // -// public override operator fun Nd4jArrayStructure.minus(b: Number): Nd4jArrayStructure { +// override operator fun Nd4jArrayStructure.minus(b: Number): Nd4jArrayStructure { // check(this) // return ndArray.sub(b).wrap() // } // -// public override operator fun Nd4jArrayStructure.plus(b: Number): Nd4jArrayStructure { +// override operator fun Nd4jArrayStructure.plus(b: Number): Nd4jArrayStructure { // check(this) // return ndArray.add(b).wrap() // } // -// public override operator fun Number.minus(b: Nd4jArrayStructure): Nd4jArrayStructure { +// override operator fun Number.minus(b: Nd4jArrayStructure): Nd4jArrayStructure { // check(b) // return b.ndArray.rsub(this).wrap() // } @@ -153,7 +153,7 @@ public sealed interface Nd4jArrayRing> : RingND, Nd4jAr * @param F the type field of structure elements. */ public sealed interface Nd4jArrayField> : FieldND, Nd4jArrayRing { - public override fun divide(a: StructureND, b: StructureND): Nd4jArrayStructure = + 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() @@ -194,38 +194,38 @@ public sealed interface Nd4jArrayField> : FieldND, Nd4 */ public sealed interface Nd4jArrayExtendedField> : ExtendedField>, Nd4jArrayField { - public override fun sin(arg: StructureND): StructureND = Transforms.sin(arg.ndArray).wrap() - public override fun cos(arg: StructureND): StructureND = Transforms.cos(arg.ndArray).wrap() - public override fun asin(arg: StructureND): StructureND = Transforms.asin(arg.ndArray).wrap() - public override fun acos(arg: StructureND): StructureND = Transforms.acos(arg.ndArray).wrap() - public override fun atan(arg: StructureND): StructureND = Transforms.atan(arg.ndArray).wrap() + 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() + override fun acos(arg: StructureND): StructureND = Transforms.acos(arg.ndArray).wrap() + override fun atan(arg: StructureND): StructureND = Transforms.atan(arg.ndArray).wrap() - public override fun power(arg: StructureND, pow: Number): StructureND = + override fun power(arg: StructureND, pow: Number): StructureND = Transforms.pow(arg.ndArray, pow).wrap() - public override fun exp(arg: StructureND): StructureND = Transforms.exp(arg.ndArray).wrap() - public override fun ln(arg: StructureND): StructureND = Transforms.log(arg.ndArray).wrap() - public override fun sqrt(arg: StructureND): StructureND = Transforms.sqrt(arg.ndArray).wrap() - public override fun sinh(arg: StructureND): StructureND = Transforms.sinh(arg.ndArray).wrap() - public override fun cosh(arg: StructureND): StructureND = Transforms.cosh(arg.ndArray).wrap() - public override fun tanh(arg: StructureND): StructureND = Transforms.tanh(arg.ndArray).wrap() + override fun exp(arg: StructureND): StructureND = Transforms.exp(arg.ndArray).wrap() + override fun ln(arg: StructureND): StructureND = Transforms.log(arg.ndArray).wrap() + override fun sqrt(arg: StructureND): StructureND = Transforms.sqrt(arg.ndArray).wrap() + override fun sinh(arg: StructureND): StructureND = Transforms.sinh(arg.ndArray).wrap() + override fun cosh(arg: StructureND): StructureND = Transforms.cosh(arg.ndArray).wrap() + override fun tanh(arg: StructureND): StructureND = Transforms.tanh(arg.ndArray).wrap() - public override fun asinh(arg: StructureND): StructureND = + override fun asinh(arg: StructureND): StructureND = Nd4j.getExecutioner().exec(ASinh(arg.ndArray, arg.ndArray.ulike())).wrap() - public override fun acosh(arg: StructureND): StructureND = + override fun acosh(arg: StructureND): StructureND = Nd4j.getExecutioner().exec(ACosh(arg.ndArray, arg.ndArray.ulike())).wrap() - public override fun atanh(arg: StructureND): StructureND = Transforms.atanh(arg.ndArray).wrap() + override fun atanh(arg: StructureND): StructureND = Transforms.atanh(arg.ndArray).wrap() } /** * Represents [FieldND] over [Nd4jArrayDoubleStructure]. */ -public class DoubleNd4jArrayField(public override val shape: IntArray) : Nd4jArrayExtendedField { - public override val elementContext: DoubleField get() = DoubleField +public class DoubleNd4jArrayField(override val shape: IntArray) : Nd4jArrayExtendedField { + override val elementContext: DoubleField get() = DoubleField - public override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asDoubleStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asDoubleStructure() @OptIn(PerformancePitfall::class) override val StructureND.ndArray: INDArray @@ -240,27 +240,27 @@ public class DoubleNd4jArrayField(public override val shape: IntArray) : Nd4jArr return a.ndArray.mul(value).wrap() } - public override operator fun StructureND.div(arg: Double): Nd4jArrayStructure { + override operator fun StructureND.div(arg: Double): Nd4jArrayStructure { return ndArray.div(arg).wrap() } - public override operator fun StructureND.plus(arg: Double): Nd4jArrayStructure { + override operator fun StructureND.plus(arg: Double): Nd4jArrayStructure { return ndArray.add(arg).wrap() } - public override operator fun StructureND.minus(arg: Double): Nd4jArrayStructure { + override operator fun StructureND.minus(arg: Double): Nd4jArrayStructure { return ndArray.sub(arg).wrap() } - public override operator fun StructureND.times(arg: Double): Nd4jArrayStructure { + override operator fun StructureND.times(arg: Double): Nd4jArrayStructure { return ndArray.mul(arg).wrap() } - public override operator fun Double.div(arg: StructureND): Nd4jArrayStructure { + override operator fun Double.div(arg: StructureND): Nd4jArrayStructure { return arg.ndArray.rdiv(this).wrap() } - public override operator fun Double.minus(arg: StructureND): Nd4jArrayStructure { + override operator fun Double.minus(arg: StructureND): Nd4jArrayStructure { return arg.ndArray.rsub(this).wrap() } } @@ -268,13 +268,13 @@ public class DoubleNd4jArrayField(public override val shape: IntArray) : Nd4jArr /** * Represents [FieldND] over [Nd4jArrayStructure] of [Float]. */ -public class FloatNd4jArrayField(public override val shape: IntArray) : Nd4jArrayExtendedField { - public override val elementContext: FloatField get() = FloatField +public class FloatNd4jArrayField(override val shape: IntArray) : Nd4jArrayExtendedField { + override val elementContext: FloatField get() = FloatField - public override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asFloatStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asFloatStructure() @OptIn(PerformancePitfall::class) - public override val StructureND.ndArray: INDArray + override val StructureND.ndArray: INDArray get() = when (this) { is Nd4jArrayStructure -> checkShape(ndArray) else -> Nd4j.zeros(*shape).also { @@ -285,36 +285,36 @@ public class FloatNd4jArrayField(public override val shape: IntArray) : Nd4jArra override fun scale(a: StructureND, value: Double): StructureND = a.ndArray.mul(value).wrap() - public override operator fun StructureND.div(arg: Float): Nd4jArrayStructure = + override operator fun StructureND.div(arg: Float): Nd4jArrayStructure = ndArray.div(arg).wrap() - public override operator fun StructureND.plus(arg: Float): Nd4jArrayStructure = + override operator fun StructureND.plus(arg: Float): Nd4jArrayStructure = ndArray.add(arg).wrap() - public override operator fun StructureND.minus(arg: Float): Nd4jArrayStructure = + override operator fun StructureND.minus(arg: Float): Nd4jArrayStructure = ndArray.sub(arg).wrap() - public override operator fun StructureND.times(arg: Float): Nd4jArrayStructure = + override operator fun StructureND.times(arg: Float): Nd4jArrayStructure = ndArray.mul(arg).wrap() - public override operator fun Float.div(arg: StructureND): Nd4jArrayStructure = + override operator fun Float.div(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rdiv(this).wrap() - public override operator fun Float.minus(arg: StructureND): Nd4jArrayStructure = + override operator fun Float.minus(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rsub(this).wrap() } /** * Represents [RingND] over [Nd4jArrayIntStructure]. */ -public class IntNd4jArrayRing(public override val shape: IntArray) : Nd4jArrayRing { - public override val elementContext: IntRing +public class IntNd4jArrayRing(override val shape: IntArray) : Nd4jArrayRing { + override val elementContext: IntRing get() = IntRing - public override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asIntStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asIntStructure() @OptIn(PerformancePitfall::class) - public override val StructureND.ndArray: INDArray + override val StructureND.ndArray: INDArray get() = when (this) { is Nd4jArrayStructure -> checkShape(ndArray) else -> Nd4j.zeros(*shape).also { @@ -322,15 +322,15 @@ public class IntNd4jArrayRing(public override val shape: IntArray) : Nd4jArrayRi } } - public override operator fun StructureND.plus(arg: Int): Nd4jArrayStructure = + override operator fun StructureND.plus(arg: Int): Nd4jArrayStructure = ndArray.add(arg).wrap() - public override operator fun StructureND.minus(arg: Int): Nd4jArrayStructure = + override operator fun StructureND.minus(arg: Int): Nd4jArrayStructure = ndArray.sub(arg).wrap() - public override operator fun StructureND.times(arg: Int): Nd4jArrayStructure = + override operator fun StructureND.times(arg: Int): Nd4jArrayStructure = ndArray.mul(arg).wrap() - public override operator fun Int.minus(arg: StructureND): Nd4jArrayStructure = + override operator fun Int.minus(arg: StructureND): Nd4jArrayStructure = arg.ndArray.rsub(this).wrap() } 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 140a212f8..d4cad8996 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 @@ -25,7 +25,7 @@ private class Nd4jArrayIndicesIterator(private val iterateOver: INDArray) : Iter internal fun INDArray.indicesIterator(): Iterator = Nd4jArrayIndicesIterator(this) -private sealed class Nd4jArrayIteratorBase(protected val iterateOver: INDArray) : Iterator> { +private sealed class Nd4jArrayIteratorBase(protected val iterateOver: INDArray) : Iterator> { private var i: Int = 0 final override fun hasNext(): Boolean = i < iterateOver.length() 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 ffddcef90..2a0fdc86c 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 @@ -17,18 +17,18 @@ import space.kscience.kmath.nd.StructureND */ public sealed class Nd4jArrayStructure : MutableStructureND { /** - * The wrapped [INDArray]. Since KMath uses [Int] indexes, assuming that the size of [INDArray] is less or equal to + * The wrapped [INDArray]. Since KMath uses [Int] indexes, assuming the size of [INDArray] is less or equal to * [Int.MAX_VALUE]. */ public abstract val ndArray: INDArray - public override val shape: IntArray get() = ndArray.shape().toIntArray() + override val shape: IntArray get() = ndArray.shape().toIntArray() internal abstract fun elementsIterator(): Iterator> internal fun indicesIterator(): Iterator = ndArray.indicesIterator() @PerformancePitfall - public override fun elements(): Sequence> = Sequence(::elementsIterator) + override fun elements(): Sequence> = Sequence(::elementsIterator) } private data class Nd4jArrayIntStructure(override val ndArray: INDArray) : Nd4jArrayStructure() { 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 456f7c2a9..1fdf845a6 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 @@ -29,109 +29,109 @@ public sealed interface Nd4jTensorAlgebra : AnalyticTensorAlgebra public fun INDArray.wrap(): Nd4jArrayStructure /** - * Unwraps to or acquires [INDArray] from [StructureND]. + * Unwraps to or gets [INDArray] from [StructureND]. */ public val StructureND.ndArray: INDArray - public override fun T.plus(other: Tensor): Tensor = other.ndArray.add(this).wrap() - public override fun Tensor.plus(value: T): Tensor = ndArray.add(value).wrap() + override fun T.plus(other: Tensor): Tensor = other.ndArray.add(this).wrap() + override fun Tensor.plus(value: T): Tensor = ndArray.add(value).wrap() - public override fun Tensor.plus(other: Tensor): Tensor = ndArray.add(other.ndArray).wrap() + override fun Tensor.plus(other: Tensor): Tensor = ndArray.add(other.ndArray).wrap() - public override fun Tensor.plusAssign(value: T) { + override fun Tensor.plusAssign(value: T) { ndArray.addi(value) } - public override fun Tensor.plusAssign(other: Tensor) { + override fun Tensor.plusAssign(other: Tensor) { ndArray.addi(other.ndArray) } - public override fun T.minus(other: Tensor): Tensor = other.ndArray.rsub(this).wrap() - public override fun Tensor.minus(value: T): Tensor = ndArray.sub(value).wrap() - public override fun Tensor.minus(other: Tensor): Tensor = ndArray.sub(other.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() - public override fun Tensor.minusAssign(value: T) { + override fun Tensor.minusAssign(value: T) { ndArray.rsubi(value) } - public override fun Tensor.minusAssign(other: Tensor) { + override fun Tensor.minusAssign(other: Tensor) { ndArray.subi(other.ndArray) } - public override fun T.times(other: Tensor): Tensor = other.ndArray.mul(this).wrap() + override fun T.times(other: Tensor): Tensor = other.ndArray.mul(this).wrap() - public override fun Tensor.times(value: T): Tensor = + override fun Tensor.times(value: T): Tensor = ndArray.mul(value).wrap() - public override fun Tensor.times(other: Tensor): Tensor = ndArray.mul(other.ndArray).wrap() + override fun Tensor.times(other: Tensor): Tensor = ndArray.mul(other.ndArray).wrap() - public override fun Tensor.timesAssign(value: T) { + override fun Tensor.timesAssign(value: T) { ndArray.muli(value) } - public override fun Tensor.timesAssign(other: Tensor) { + override fun Tensor.timesAssign(other: Tensor) { ndArray.mmuli(other.ndArray) } - public override fun Tensor.unaryMinus(): Tensor = ndArray.neg().wrap() - public override fun Tensor.get(i: Int): Tensor = ndArray.slice(i.toLong()).wrap() - public override fun Tensor.transpose(i: Int, j: Int): Tensor = ndArray.swapAxes(i, j).wrap() - public override fun Tensor.dot(other: Tensor): Tensor = 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() - public override fun Tensor.min(dim: Int, keepDim: Boolean): Tensor = + override fun Tensor.min(dim: Int, keepDim: Boolean): Tensor = ndArray.min(keepDim, dim).wrap() - public override fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor = + override fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor = ndArray.sum(keepDim, dim).wrap() - public override fun Tensor.max(dim: Int, keepDim: Boolean): Tensor = + override fun Tensor.max(dim: Int, keepDim: Boolean): Tensor = ndArray.max(keepDim, dim).wrap() - public override fun Tensor.view(shape: IntArray): Tensor = ndArray.reshape(shape).wrap() - public override fun Tensor.viewAs(other: Tensor): Tensor = view(other.shape) + override fun Tensor.view(shape: IntArray): Tensor = ndArray.reshape(shape).wrap() + override fun Tensor.viewAs(other: Tensor): Tensor = view(other.shape) - public override fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor = + override fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor = ndBase.get().argmax(ndArray, keepDim, dim).wrap() - public override fun Tensor.mean(dim: Int, keepDim: Boolean): Tensor = ndArray.mean(keepDim, dim).wrap() + override fun Tensor.mean(dim: Int, keepDim: Boolean): Tensor = ndArray.mean(keepDim, dim).wrap() - public override fun Tensor.exp(): Tensor = Transforms.exp(ndArray).wrap() - public override fun Tensor.ln(): Tensor = Transforms.log(ndArray).wrap() - public override fun Tensor.sqrt(): Tensor = Transforms.sqrt(ndArray).wrap() - public override fun Tensor.cos(): Tensor = Transforms.cos(ndArray).wrap() - public override fun Tensor.acos(): Tensor = Transforms.acos(ndArray).wrap() - public override fun Tensor.cosh(): Tensor = 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() - public override fun Tensor.acosh(): Tensor = + override fun Tensor.acosh(): Tensor = Nd4j.getExecutioner().exec(ACosh(ndArray, ndArray.ulike())).wrap() - public override fun Tensor.sin(): Tensor = Transforms.sin(ndArray).wrap() - public override fun Tensor.asin(): Tensor = Transforms.asin(ndArray).wrap() - public override fun Tensor.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() - public override fun Tensor.asinh(): Tensor = + override fun Tensor.asinh(): Tensor = Nd4j.getExecutioner().exec(ASinh(ndArray, ndArray.ulike())).wrap() - public override fun Tensor.tan(): Tensor = Transforms.tan(ndArray).wrap() - public override fun Tensor.atan(): Tensor = Transforms.atan(ndArray).wrap() - public override fun Tensor.tanh(): Tensor = Transforms.tanh(ndArray).wrap() - public override fun Tensor.atanh(): Tensor = Transforms.atanh(ndArray).wrap() - public override fun Tensor.ceil(): Tensor = Transforms.ceil(ndArray).wrap() - public override fun Tensor.floor(): Tensor = Transforms.floor(ndArray).wrap() - public override fun Tensor.std(dim: Int, keepDim: Boolean): Tensor = ndArray.std(true, keepDim, dim).wrap() - public override fun T.div(other: Tensor): Tensor = other.ndArray.rdiv(this).wrap() - public override fun Tensor.div(value: T): Tensor = ndArray.div(value).wrap() - public override fun Tensor.div(other: Tensor): Tensor = ndArray.div(other.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() - public override fun Tensor.divAssign(value: T) { + override fun Tensor.divAssign(value: T) { ndArray.divi(value) } - public override fun Tensor.divAssign(other: Tensor) { + override fun Tensor.divAssign(other: Tensor) { ndArray.divi(other.ndArray) } - public override fun Tensor.variance(dim: Int, keepDim: Boolean): Tensor = + override fun Tensor.variance(dim: Int, keepDim: Boolean): Tensor = Nd4j.getExecutioner().exec(Variance(ndArray, true, true, dim)).wrap() private companion object { @@ -143,10 +143,10 @@ public sealed interface Nd4jTensorAlgebra : AnalyticTensorAlgebra * [Double] specialization of [Nd4jTensorAlgebra]. */ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { - public override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() + override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() @OptIn(PerformancePitfall::class) - public override val StructureND.ndArray: INDArray + override val StructureND.ndArray: INDArray get() = when (this) { is Nd4jArrayStructure -> ndArray else -> Nd4j.zeros(*shape).also { @@ -154,22 +154,22 @@ public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { } } - public override fun Tensor.valueOrNull(): Double? = + override fun Tensor.valueOrNull(): Double? = if (shape contentEquals intArrayOf(1)) ndArray.getDouble(0) else null // TODO rewrite @PerformancePitfall - public override fun diagonalEmbedding( + override fun diagonalEmbedding( diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int, ): Tensor = DoubleTensorAlgebra.diagonalEmbedding(diagonalEntries, offset, dim1, dim2) - public override fun Tensor.sum(): Double = ndArray.sumNumber().toDouble() - public override fun Tensor.min(): Double = ndArray.minNumber().toDouble() - public override fun Tensor.max(): Double = ndArray.maxNumber().toDouble() - public override fun Tensor.mean(): Double = ndArray.meanNumber().toDouble() - public override fun Tensor.std(): Double = ndArray.stdNumber().toDouble() - public override fun Tensor.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 75a334ca7..3ca756600 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 @@ -5,4 +5,6 @@ package space.kscience.kmath.nd4j -internal fun LongArray.toIntArray(): IntArray = IntArray(size) { this[it].toInt() } +import space.kscience.kmath.misc.toIntExact + +internal fun LongArray.toIntArray(): IntArray = IntArray(size) { this[it].toIntExact() } diff --git a/kmath-stat/build.gradle.kts b/kmath-stat/build.gradle.kts index e8f629f7a..e3e396b6f 100644 --- a/kmath-stat/build.gradle.kts +++ b/kmath-stat/build.gradle.kts @@ -1,6 +1,7 @@ plugins { kotlin("multiplatform") id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } kscience { 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 e3adcdc44..3d3f95f8f 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 @@ -19,10 +19,10 @@ public interface Distribution : Sampler { */ public fun probability(arg: T): Double - public override fun sample(generator: RandomGenerator): Chain + override fun sample(generator: RandomGenerator): Chain /** - * An empty companion. Distribution factories should be written as its extensions + * An empty companion. Distribution factories should be written as its extensions. */ public companion object } 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 dde429244..1218f13c5 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 @@ -10,12 +10,12 @@ import space.kscience.kmath.chains.SimpleChain import space.kscience.kmath.stat.RandomGenerator /** - * A multivariate distribution which takes a map of parameters + * A multivariate distribution that takes a map of parameters. */ public interface NamedDistribution : Distribution> /** - * A multivariate distribution that has independent distributions for separate axis + * A multivariate distribution that has independent distributions for separate axis. */ public class FactorizedDistribution(public val distributions: Collection>) : NamedDistribution { 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 04ec8b171..66e041f05 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 @@ -23,14 +23,14 @@ public class NormalDistribution(public val sampler: GaussianSampler) : Univariat normalized: NormalizedGaussianSampler = ZigguratNormalizedGaussianSampler, ) : this(GaussianSampler(mean, standardDeviation, normalized)) - public override fun probability(arg: Double): Double { + override fun probability(arg: Double): Double { val x1 = (arg - sampler.mean) / sampler.standardDeviation return exp(-0.5 * x1 * x1 - (ln(sampler.standardDeviation) + 0.5 * ln(2 * PI))) } - public override fun sample(generator: RandomGenerator): Chain = sampler.sample(generator) + override fun sample(generator: RandomGenerator): Chain = sampler.sample(generator) - public override fun cumulative(arg: Double): Double { + override fun cumulative(arg: Double): Double { val dev = arg - sampler.mean return when { 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 a584af4f9..6e7eb039d 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 @@ -110,7 +110,7 @@ internal object InternalGamma { x <= 8.0 -> { val n = floor(x - 1.5).toInt() - val prod = (1..n).fold(1.0, { prod, i -> prod * (x - i) }) + val prod = (1..n).fold(1.0) { prod, i -> prod * (x - i) } logGamma1p(x - (n + 1)) + ln(prod) } 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 index 4d4f99b71..1af6c4bda 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt @@ -25,35 +25,7 @@ public class FunctionOptimization( public val expression: DifferentiableExpression, ) : OptimizationProblem{ - public companion object{ - /** - * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation - */ - public fun chiSquaredExpression( - 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 - } - } - } + public companion object } public fun FunctionOptimization.withFeatures( @@ -64,7 +36,7 @@ public fun FunctionOptimization.withFeatures( ) /** - * Optimize differentiable expression using specific [optimizer] form given [startingPoint] + * Optimizes differentiable expression using specific [optimizer] form given [startingPoint]. */ public suspend fun DifferentiableExpression.optimizeWith( optimizer: Optimizer>, diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt index acfc7e445..365c58952 100644 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt +++ b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/QowOptimizer.kt @@ -104,7 +104,6 @@ public class QowOptimizer : Optimizer { private fun QoWeight.getEqDerivValues( theta: Map = parameters, ): Matrix = with(linearSpace) { - val fitDim = size //Возвращает производную k-того Eq по l-тому параметру //val res = Array(fitDim) { DoubleArray(fitDim) } val sderiv = buildMatrix(data.size, size) { i, l -> 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 a231842df..77d29981f 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 @@ -24,7 +24,7 @@ public class AhrensDieterExponentialSampler(public val mean: Double) : Sampler 0) { "mean is not strictly positive: $mean" } } - public override fun sample(generator: RandomGenerator): BlockingDoubleChain = object : BlockingDoubleChain { + override fun sample(generator: RandomGenerator): BlockingDoubleChain = object : BlockingDoubleChain { override fun nextBlocking(): Double { // Step 1: var a = 0.0 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 2f32eee85..993215d41 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 @@ -14,9 +14,9 @@ import kotlin.math.* /** * Sampling from the [gamma distribution](http://mathworld.wolfram.com/GammaDistribution.html). - * - For 0 < alpha < 1: + * * For 0 < alpha < 1: * Ahrens, J. H. and Dieter, U., Computer methods for sampling from gamma, beta, Poisson and binomial distributions, Computing, 12, 223-246, 1974. - * - For alpha >= 1: + * * For alpha >= 1: * Marsaglia and Tsang, A Simple Method for Generating Gamma Variables. ACM Transactions on Mathematical Software, Volume 26 Issue 3, September, 2000. * * Based on Commons RNG implementation. @@ -113,8 +113,8 @@ public class AhrensDieterMarsagliaTsangGammaSampler private constructor( } } - public override fun sample(generator: RandomGenerator): Chain = delegate.sample(generator) - public override fun toString(): String = delegate.toString() + override fun sample(generator: RandomGenerator): Chain = delegate.sample(generator) + override fun toString(): String = delegate.toString() public companion object { public fun of( 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 db4f598b7..5390a2e09 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 @@ -20,7 +20,7 @@ import kotlin.math.min * implements Vose's algorithm. * * Vose, M.D., A linear algorithm for generating random numbers with a given distribution, IEEE Transactions on - * Software Engineering, 17, 972-975, 1991. he algorithm will sample values in O(1) time after a pre-processing step + * Software Engineering, 17, 972-975, 1991. The algorithm will sample values in O(1) time after a pre-processing step * of O(n) time. * * The alias tables are constructed using fraction probabilities with an assumed denominator of 253. In the generic @@ -76,8 +76,8 @@ public open class AliasMethodDiscreteSampler private constructor( } } - public override fun sample(generator: RandomGenerator): Chain = generator.chain { - // This implements the algorithm as per Vose (1991): + override fun sample(generator: RandomGenerator): Chain = generator.chain { + // This implements the algorithm in accordance with Vose (1991): // v = uniform() in [0, 1) // j = uniform(n) in [0, n) // if v < prob[j] then @@ -95,7 +95,7 @@ public open class AliasMethodDiscreteSampler private constructor( // p(j) == 1 => j // However it is assumed these edge cases are rare: // - // The probability table will be 1 for approximately 1/n samples, i.e. only the + // The probability table will be 1 for approximately 1/n samples i.e., only the // last unpaired probability. This is only worth checking for when the table size (n) // is small. But in that case the user should zero-pad the table for performance. // @@ -107,7 +107,7 @@ public open class AliasMethodDiscreteSampler private constructor( if (generator.nextLong() ushr 11 < probability[j]) j else alias[j] } - public override fun toString(): String = "Alias method" + override fun toString(): String = "Alias method" public companion object { private const val DEFAULT_ALPHA = 0 @@ -211,7 +211,7 @@ public open class AliasMethodDiscreteSampler private constructor( // c: 2=2/3; 6=1/3 (6 is the alias) // d: 1=1/3; 6=2/3 (6 is the alias) // - // The sample is obtained by randomly selecting a section, then choosing which category + // The sample is obtained by randomly selecting a section, then choosing, which category // from the pair based on a uniform random deviate. val sumProb = InternalUtils.validateProbabilities(probabilities) // Allow zero-padding @@ -241,9 +241,9 @@ public open class AliasMethodDiscreteSampler private constructor( val alias = IntArray(n) // This loop uses each large in turn to fill the alias table for small probabilities that - // do not reach the requirement to fill an entire section alone (i.e. p < mean). + // do not reach the requirement to fill an entire section alone (i.e., p < mean). // Since the sum of the small should be less than the sum of the large it should use up - // all the small first. However floating point round-off can result in + // all the small first. However, floating point round-off can result in // misclassification of items as small or large. The Vose algorithm handles this using // a while loop conditioned on the size of both sets and a subsequent loop to use // unpaired items. diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ConstantSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ConstantSampler.kt deleted file mode 100644 index 0d38fe19b..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ConstantSampler.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.samplers - -import space.kscience.kmath.chains.BlockingBufferChain -import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.stat.Sampler -import space.kscience.kmath.structures.Buffer - -public class ConstantSampler(public val const: T) : Sampler { - override fun sample(generator: RandomGenerator): BlockingBufferChain = object : BlockingBufferChain { - override fun nextBufferBlocking(size: Int): Buffer = Buffer.boxing(size) { const } - override suspend fun fork(): BlockingBufferChain = this - } -} \ No newline at end of file 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 d7d8e87b7..9219df43e 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 @@ -28,7 +28,7 @@ public class GaussianSampler( require(standardDeviation > 0.0) { "standard deviation is not strictly positive: $standardDeviation" } } - public override fun sample(generator: RandomGenerator): BlockingDoubleChain = normalized + override fun sample(generator: RandomGenerator): BlockingDoubleChain = normalized .sample(generator) .map { standardDeviation * it + mean } 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 9bb48fe4e..0105731c4 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 @@ -13,7 +13,7 @@ import kotlin.math.exp /** * Sampler for the Poisson distribution. - * - Kemp, A, W, (1981) Efficient Generation of Logarithmically Distributed Pseudo-Random Variables. Journal of the Royal Statistical Society. Vol. 30, No. 3, pp. 249-253. + * * Kemp, A, W, (1981) Efficient Generation of Logarithmically Distributed Pseudo-Random Variables. Journal of the Royal Statistical Society. Vol. 30, No. 3, pp. 249-253. * This sampler is suitable for mean < 40. For large means, LargeMeanPoissonSampler should be used instead. * * Note: The algorithm uses a recurrence relation to compute the Poisson probability and a rolling summation for the cumulative probability. When the mean is large the initial probability (Math.exp(-mean)) is zero and an exception is raised by the constructor. @@ -27,7 +27,7 @@ public class KempSmallMeanPoissonSampler internal constructor( private val p0: Double, private val mean: Double, ) : Sampler { - public override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { + override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { override fun nextBlocking(): Int { //TODO move to nextBufferBlocking // Note on the algorithm: @@ -60,14 +60,13 @@ public class KempSmallMeanPoissonSampler internal constructor( override suspend fun fork(): BlockingIntChain = sample(generator.fork()) } - public override fun toString(): String = "Kemp Small Mean Poisson deviate" + override fun toString(): String = "Kemp Small Mean Poisson deviate" } public fun KempSmallMeanPoissonSampler(mean: Double): KempSmallMeanPoissonSampler { require(mean > 0) { "Mean is not strictly positive: $mean" } val p0 = exp(-mean) - // Probability must be positive. As mean increases then p(0) decreases. + // Probability must be positive. As mean increases, p(0) decreases. require(p0 > 0) { "No probability for mean: $mean" } return KempSmallMeanPoissonSampler(p0, mean) } - 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 e95778b9e..f0f94900e 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 @@ -7,6 +7,7 @@ package space.kscience.kmath.samplers import space.kscience.kmath.chains.BlockingIntChain import space.kscience.kmath.internal.InternalUtils +import space.kscience.kmath.misc.toIntExact import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.stat.Sampler import space.kscience.kmath.structures.IntBuffer @@ -17,11 +18,11 @@ private const val PIVOT = 40.0 /** * Sampler for the Poisson distribution. - * - For small means, a Poisson process is simulated using uniform deviates, as described in + * * For small means, a Poisson process is simulated using uniform deviates, as described in * Knuth (1969). Seminumerical Algorithms. The Art of Computer Programming, Volume 2. Chapter 3.4.1.F.3 * Important integer-valued distributions: The Poisson distribution. Addison Wesley. * The Poisson process (and hence, the returned value) is bounded by 1000 * mean. - * - For large means, we use the rejection algorithm described in + * * For large means, we use the rejection algorithm described in * Devroye, Luc. (1981). The Computer Generation of Poisson Random Variables Computing vol. 26 pp. 197-207. * * Based on Commons RNG implementation. @@ -34,10 +35,10 @@ public fun PoissonSampler(mean: Double): Sampler { /** * Sampler for the Poisson distribution. - * - For small means, a Poisson process is simulated using uniform deviates, as described in + * * For small means, a Poisson process is simulated using uniform deviates, as described in * Knuth (1969). Seminumerical Algorithms. The Art of Computer Programming, Volume 2. Chapter 3.4.1.F.3 Important * integer-valued distributions: The Poisson distribution. Addison Wesley. - * - The Poisson process (and hence, the returned value) is bounded by 1000 * mean. + * * The Poisson process (and hence, the returned value) is bounded by 1000 * mean. * This sampler is suitable for mean < 40. For large means, [LargeMeanPoissonSampler] should be used instead. * * Based on Commons RNG implementation. @@ -58,7 +59,7 @@ public class SmallMeanPoissonSampler(public val mean: Double) : Sampler { throw IllegalArgumentException("No p(x=0) probability for mean: $mean") }.toInt() - public override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { + override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { override fun nextBlocking(): Int { var n = 0 var r = 1.0 @@ -76,7 +77,7 @@ public class SmallMeanPoissonSampler(public val mean: Double) : Sampler { override suspend fun fork(): BlockingIntChain = sample(generator.fork()) } - public override fun toString(): String = "Small Mean Poisson deviate" + override fun toString(): String = "Small Mean Poisson deviate" } @@ -113,13 +114,13 @@ public class LargeMeanPoissonSampler(public val mean: Double) : Sampler { private val p1: Double = a1 / aSum private val p2: Double = a2 / aSum - public override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { + override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { override fun nextBlocking(): Int { val exponential = AhrensDieterExponentialSampler(1.0).sample(generator) val gaussian = ZigguratNormalizedGaussianSampler.sample(generator) val smallMeanPoissonSampler = if (mean - lambda < Double.MIN_VALUE) { - null + null } else { KempSmallMeanPoissonSampler(mean - lambda).sample(generator) } @@ -188,7 +189,7 @@ public class LargeMeanPoissonSampler(public val mean: Double) : Sampler { } } - return min(y2 + y.toLong(), Int.MAX_VALUE.toLong()).toInt() + return min(y2 + y.toLong(), Int.MAX_VALUE.toLong()).toIntExact() } override fun nextBufferBlocking(size: Int): IntBuffer = IntBuffer(size) { nextBlocking() } @@ -197,7 +198,7 @@ public class LargeMeanPoissonSampler(public val mean: Double) : Sampler { } private fun getFactorialLog(n: Int): Double = factorialLog.value(n) - public override fun toString(): String = "Large Mean Poisson deviate" + override fun toString(): String = "Large Mean Poisson deviate" public companion object { private const val MAX_MEAN: Double = 0.5 * Int.MAX_VALUE 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 24148271d..81b8c3d4b 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 @@ -6,6 +6,7 @@ package space.kscience.kmath.samplers import space.kscience.kmath.chains.BlockingDoubleChain +import space.kscience.kmath.misc.toIntExact import space.kscience.kmath.stat.RandomGenerator import space.kscience.kmath.structures.DoubleBuffer import kotlin.math.* @@ -58,7 +59,7 @@ public object ZigguratNormalizedGaussianSampler : NormalizedGaussianSampler { private fun sampleOne(generator: RandomGenerator): Double { val j = generator.nextLong() - val i = (j and LAST.toLong()).toInt() + val i = (j and LAST.toLong()).toIntExact() return if (abs(j) < K[i]) j * W[i] else fix(generator, j, i) } 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 9e5c70a26..0e06fa162 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 @@ -6,6 +6,8 @@ package space.kscience.kmath.stat import kotlinx.coroutines.* +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.coroutineContext @@ -23,14 +25,18 @@ public class MCScope( /** * Launches a supervised Monte-Carlo scope */ -public suspend inline fun mcScope(generator: RandomGenerator, block: MCScope.() -> T): T = - MCScope(coroutineContext, generator).block() +public suspend inline fun mcScope(generator: RandomGenerator, block: MCScope.() -> T): T { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return MCScope(coroutineContext, generator).block() +} /** * Launch mc scope with a given seed */ -public suspend inline fun mcScope(seed: Long, block: MCScope.() -> T): T = - mcScope(RandomGenerator.default(seed), block) +public suspend inline fun mcScope(seed: Long, block: MCScope.() -> T): T { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + return mcScope(RandomGenerator.default(seed), block) +} /** * Specialized launch for [MCScope]. Behaves the same way as regular [CoroutineScope.launch], but also stores the generator fork. 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 9769146fb..ac2c2098f 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 @@ -27,13 +27,13 @@ public class Mean( override suspend fun evaluate(data: Buffer): T = super.evaluate(data) - public override suspend fun computeIntermediate(data: Buffer): Pair = + override suspend fun computeIntermediate(data: Buffer): Pair = evaluateBlocking(data) to data.size - public override suspend fun composeIntermediate(first: Pair, second: Pair): Pair = + override suspend fun composeIntermediate(first: Pair, second: Pair): Pair = group { first.first + second.first } to (first.second + second.second) - public override suspend fun toResult(intermediate: Pair): T = group { + override suspend fun toResult(intermediate: Pair): T = group { division(intermediate.first, intermediate.second) } 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 70754eab7..2cc867fb2 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 @@ -12,7 +12,7 @@ import space.kscience.kmath.structures.asSequence * Non-composable median */ public class Median(private val comparator: Comparator) : BlockingStatistic { - public override fun evaluateBlocking(data: Buffer): T = + override fun evaluateBlocking(data: Buffer): T = data.asSequence().sortedWith(comparator).toList()[data.size / 2] //TODO check if this is correct public companion object { 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 5041e7359..d4bc36b5b 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 @@ -31,7 +31,7 @@ public fun RandomGenerator.chain(generator: suspend RandomGenerator.() -> R) * A type-specific double chunk random chain */ public class UniformDoubleChain(public val generator: RandomGenerator) : BlockingDoubleChain { - public override fun nextBufferBlocking(size: Int): DoubleBuffer = generator.nextDoubleBuffer(size) + override fun nextBufferBlocking(size: Int): DoubleBuffer = generator.nextDoubleBuffer(size) override suspend fun nextBuffer(size: Int): DoubleBuffer = nextBufferBlocking(size) override suspend fun fork(): UniformDoubleChain = UniformDoubleChain(generator.fork()) 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 3ff12f383..f280a78aa 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 @@ -23,7 +23,7 @@ public interface RandomGenerator { public fun nextDouble(): Double /** - * A chunk of doubles of given [size] + * A chunk of doubles of given [size]. */ public fun nextDoubleBuffer(size: Int): DoubleBuffer = DoubleBuffer(size) { nextDouble() } @@ -57,7 +57,7 @@ public interface RandomGenerator { public fun nextLong(until: Long): Long /** - * Fills a subrange of the specified byte [array] starting from [fromIndex] inclusive and ending [toIndex] exclusive + * Fills a subrange with the specified byte [array] starting from [fromIndex] inclusive and ending [toIndex] exclusive * with random bytes. * * @return [array] with the subrange filled with random bytes. @@ -70,7 +70,7 @@ public interface RandomGenerator { public fun nextBytes(size: Int): ByteArray = ByteArray(size).also { fillBytes(it) } /** - * Create a new generator which is independent from current generator (operations on new generator do not affect this one + * Create a new generator that is independent of current generator (operations on new generator do not affect this one * and vise versa). The statistical properties of new generator should be the same as for this one. * For pseudo-random generator, the fork is keeping the same sequence of numbers for given call order for each run. * @@ -97,17 +97,17 @@ public interface RandomGenerator { * @property random the underlying [Random] object. */ public class DefaultGenerator(public val random: Random = Random) : RandomGenerator { - public override fun nextBoolean(): Boolean = random.nextBoolean() - public override fun nextDouble(): Double = random.nextDouble() - public override fun nextInt(): Int = random.nextInt() - public override fun nextInt(until: Int): Int = random.nextInt(until) - public override fun nextLong(): Long = random.nextLong() - public override fun nextLong(until: Long): Long = random.nextLong(until) + override fun nextBoolean(): Boolean = random.nextBoolean() + override fun nextDouble(): Double = random.nextDouble() + override fun nextInt(): Int = random.nextInt() + override fun nextInt(until: Int): Int = random.nextInt(until) + override fun nextLong(): Long = random.nextLong() + override fun nextLong(until: Long): Long = random.nextLong(until) - public override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { + override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { random.nextBytes(array, fromIndex, toIndex) } - public override fun nextBytes(size: Int): ByteArray = random.nextBytes(size) - public override fun fork(): RandomGenerator = RandomGenerator.default(random.nextLong()) + override fun nextBytes(size: Int): ByteArray = random.nextBytes(size) + override fun fork(): RandomGenerator = RandomGenerator.default(random.nextLong()) } 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 51ae78d3d..4c11fdd65 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 @@ -12,7 +12,7 @@ import space.kscience.kmath.structures.* import kotlin.jvm.JvmName /** - * Sampler that generates chains of values of type [T] in a chain of type [C]. + * Sampler that generates chains of values of type [T]. */ public fun interface Sampler { /** 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 b3d607ab0..044e489b2 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 @@ -18,8 +18,8 @@ import space.kscience.kmath.operations.invoke * * @property value the value to sample. */ -public class ConstantSampler(public val value: T) : Sampler { - public override fun sample(generator: RandomGenerator): Chain = ConstantChain(value) +public class ConstantSampler(public val value: T) : Sampler { + override fun sample(generator: RandomGenerator): Chain = ConstantChain(value) } /** @@ -27,29 +27,29 @@ public class ConstantSampler(public val value: T) : Sampler { * * @property chainBuilder the provider of [Chain]. */ -public class BasicSampler(public val chainBuilder: (RandomGenerator) -> Chain) : Sampler { - public override fun sample(generator: RandomGenerator): Chain = chainBuilder(generator) +public class BasicSampler(public val chainBuilder: (RandomGenerator) -> Chain) : Sampler { + override fun sample(generator: RandomGenerator): Chain = chainBuilder(generator) } /** - * A space of samplers. Allows to perform simple operations on distributions. + * A space of samplers. Allows performing simple operations on distributions. * * @property algebra the space to provide addition and scalar multiplication for [T]. */ -public class SamplerSpace(public val algebra: S) : Group>, +public class SamplerSpace(public val algebra: S) : Group>, ScaleOperations> where S : Group, S : ScaleOperations { - public override val zero: Sampler = ConstantSampler(algebra.zero) + override val zero: Sampler = ConstantSampler(algebra.zero) - public override fun add(a: Sampler, b: Sampler): Sampler = BasicSampler { generator -> + override fun add(a: Sampler, b: Sampler): Sampler = BasicSampler { generator -> a.sample(generator).zip(b.sample(generator)) { aValue, bValue -> algebra { aValue + bValue } } } - public override fun scale(a: Sampler, value: Double): Sampler = BasicSampler { generator -> + override fun scale(a: Sampler, value: Double): Sampler = BasicSampler { generator -> a.sample(generator).map { a -> algebra { a * value } } } - public override fun Sampler.unaryMinus(): Sampler = scale(this, -1.0) + override fun Sampler.unaryMinus(): Sampler = scale(this, -1.0) } 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 1b05aa9cd..0af901fc9 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 @@ -18,23 +18,24 @@ import space.kscience.kmath.structures.Buffer /** * A function, that transforms a buffer of random quantities to some resulting value */ -public interface Statistic { +public interface Statistic { public suspend fun evaluate(data: Buffer): R } -public interface BlockingStatistic: Statistic{ +public interface BlockingStatistic : Statistic { public fun evaluateBlocking(data: Buffer): R - override suspend fun evaluate(data: Buffer): R = evaluateBlocking(data) + override suspend fun evaluate(data: Buffer): R = evaluateBlocking(data) } /** * A statistic tha could be computed separately on different blocks of data and then composed - * @param T - source type - * @param I - intermediate block type - * @param R - result type + * + * @param T the source type. + * @param I the intermediate block type. + * @param R the result type. */ -public interface ComposableStatistic : Statistic { +public interface ComposableStatistic : Statistic { //compute statistic on a single block public suspend fun computeIntermediate(data: Buffer): I @@ -44,7 +45,7 @@ public interface ComposableStatistic : Statistic { //Transform block to result public suspend fun toResult(intermediate: I): R - public override suspend fun evaluate(data: Buffer): R = toResult(computeIntermediate(data)) + override suspend fun evaluate(data: Buffer): R = toResult(computeIntermediate(data)) } @FlowPreview 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 1ff6481ac..202a1c8dd 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 @@ -17,19 +17,19 @@ public class RandomSourceGenerator internal constructor(public val source: Rando internal val random: UniformRandomProvider = seed?.let { RandomSource.create(source, seed) } ?: RandomSource.create(source) - public override fun nextBoolean(): Boolean = random.nextBoolean() - public override fun nextDouble(): Double = random.nextDouble() - public override fun nextInt(): Int = random.nextInt() - public override fun nextInt(until: Int): Int = random.nextInt(until) - public override fun nextLong(): Long = random.nextLong() - public override fun nextLong(until: Long): Long = random.nextLong(until) + override fun nextBoolean(): Boolean = random.nextBoolean() + override fun nextDouble(): Double = random.nextDouble() + override fun nextInt(): Int = random.nextInt() + override fun nextInt(until: Int): Int = random.nextInt(until) + override fun nextLong(): Long = random.nextLong() + override fun nextLong(until: Long): Long = random.nextLong(until) - public override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { + override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { require(toIndex > fromIndex) random.nextBytes(array, fromIndex, toIndex - fromIndex) } - public override fun fork(): RandomGenerator = RandomSourceGenerator(source, nextLong()) + override fun fork(): RandomGenerator = RandomSourceGenerator(source, nextLong()) } /** @@ -43,23 +43,23 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * * @return the next random value. */ - public override fun nextBoolean(): Boolean = generator.nextBoolean() + override fun nextBoolean(): Boolean = generator.nextBoolean() /** * Generates a [Float] value between 0 and 1. * * @return the next random value between 0 and 1. */ - public override fun nextFloat(): Float = generator.nextDouble().toFloat() + override fun nextFloat(): Float = generator.nextDouble().toFloat() /** * Generates [Byte] values and places them into a user-supplied array. * - * The number of random bytes produced is equal to the length of the the byte array. + * The number of random bytes produced is equal to the length of the byte array. * * @param bytes byte array in which to put the random bytes. */ - public override fun nextBytes(bytes: ByteArray): Unit = generator.fillBytes(bytes) + override fun nextBytes(bytes: ByteArray): Unit = generator.fillBytes(bytes) /** * Generates [Byte] values and places them into a user-supplied array. @@ -71,7 +71,7 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * @param start the index at which to start inserting the generated bytes. * @param len the number of bytes to insert. */ - public override fun nextBytes(bytes: ByteArray, start: Int, len: Int) { + override fun nextBytes(bytes: ByteArray, start: Int, len: Int) { generator.fillBytes(bytes, start, start + len) } @@ -80,7 +80,7 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * * @return the next random value. */ - public override fun nextInt(): Int = generator.nextInt() + override fun nextInt(): Int = generator.nextInt() /** * Generates an [Int] value between 0 (inclusive) and the specified value (exclusive). @@ -88,21 +88,21 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * @param n the bound on the random number to be returned. Must be positive. * @return a random integer between 0 (inclusive) and [n] (exclusive). */ - public override fun nextInt(n: Int): Int = generator.nextInt(n) + override fun nextInt(n: Int): Int = generator.nextInt(n) /** * Generates a [Double] value between 0 and 1. * * @return the next random value between 0 and 1. */ - public override fun nextDouble(): Double = generator.nextDouble() + override fun nextDouble(): Double = generator.nextDouble() /** * Generates a [Long] value. * * @return the next random value. */ - public override fun nextLong(): Long = generator.nextLong() + override fun nextLong(): Long = generator.nextLong() /** * Generates a [Long] value between 0 (inclusive) and the specified value (exclusive). @@ -110,7 +110,7 @@ public class RandomGeneratorProvider(public val generator: RandomGenerator) : Un * @param n Bound on the random number to be returned. Must be positive. * @return a random long value between 0 (inclusive) and [n] (exclusive). */ - public override fun nextLong(n: Long): Long = generator.nextLong(n) + override fun nextLong(n: Long): Long = generator.nextLong(n) } /** diff --git a/kmath-symja/build.gradle.kts b/kmath-symja/build.gradle.kts new file mode 100644 index 000000000..65c329d52 --- /dev/null +++ b/kmath-symja/build.gradle.kts @@ -0,0 +1,42 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +plugins { + kotlin("jvm") + id("ru.mipt.npm.gradle.common") +} + +description = "Symja integration module" + +dependencies { + api("org.matheclipse:matheclipse-core:2.0.0-SNAPSHOT") { + // Incorrect transitive dependencies + exclude("org.apfloat", "apfloat") + exclude("org.hipparchus", "hipparchus-clustering") + exclude("org.hipparchus", "hipparchus-core") + exclude("org.hipparchus", "hipparchus-fft") + exclude("org.hipparchus", "hipparchus-fitting") + exclude("org.hipparchus", "hipparchus-ode") + exclude("org.hipparchus", "hipparchus-optim") + exclude("org.hipparchus", "hipparchus-stat") + } + + // Replaces for incorrect transitive dependencies + api("org.apfloat:apfloat:1.10.0") + api("org.hipparchus:hipparchus-clustering:1.8") + api("org.hipparchus:hipparchus-core:1.8") + api("org.hipparchus:hipparchus-fft:1.8") + api("org.hipparchus:hipparchus-fitting:1.8") + api("org.hipparchus:hipparchus-ode:1.8") + api("org.hipparchus:hipparchus-optim:1.8") + api("org.hipparchus:hipparchus-stat:1.8") + + api(project(":kmath-core")) + testImplementation("org.slf4j:slf4j-simple:1.7.31") +} + +readme { + maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE +} 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 new file mode 100644 index 000000000..3067b5efb --- /dev/null +++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2018-2021 KMath contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package space.kscience.kmath.symja + +import org.matheclipse.core.eval.ExprEvaluator +import org.matheclipse.core.expression.F +import space.kscience.kmath.expressions.SpecialDifferentiableExpression +import space.kscience.kmath.expressions.MST +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.expressions.interpret +import space.kscience.kmath.operations.NumericAlgebra + +/** + * Represents [MST] based [space.kscience.kmath.expressions.DifferentiableExpression] relying on + * [Symja](https://github.com/axkr/symja_android_library). + * + * The principle of this API is converting the [mst] to an [org.matheclipse.core.interfaces.IExpr], differentiating it + * with Symja's [F.D], then converting [org.matheclipse.core.interfaces.IExpr] back to [MST]. + * + * @param T The type of number. + * @param A The [NumericAlgebra] of [T]. + * @property algebra The [A] instance. + * @property mst The [MST] node. + */ +public class SymjaExpression>( + public val algebra: A, + public val mst: MST, + public val evaluator: ExprEvaluator = DEFAULT_EVALUATOR, +) : SpecialDifferentiableExpression> { + override fun invoke(arguments: Map): T = mst.interpret(algebra, arguments) + + override fun derivativeOrNull(symbols: List): SymjaExpression = SymjaExpression( + algebra, + symbols.map(Symbol::toIExpr).fold(mst.toIExpr(), F::D).toMst(evaluator), + evaluator, + ) +} + +/** + * Wraps this [MST] into [SymjaExpression] in the context of [algebra]. + */ +public fun > MST.toSymjaExpression(algebra: A): SymjaExpression = + SymjaExpression(algebra, this) 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 new file mode 100644 index 000000000..95dd1ebbf --- /dev/null +++ b/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt @@ -0,0 +1,95 @@ +/* + * Copyright 2018-2021 KMath 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.symja + +import org.matheclipse.core.eval.ExprEvaluator +import org.matheclipse.core.expression.ComplexNum +import org.matheclipse.core.expression.F +import org.matheclipse.core.interfaces.IExpr +import org.matheclipse.core.interfaces.ISymbol +import space.kscience.kmath.expressions.MST +import space.kscience.kmath.expressions.MstExtendedField +import space.kscience.kmath.expressions.Symbol +import space.kscience.kmath.operations.* + +internal val DEFAULT_EVALUATOR = ExprEvaluator(false, 100) + +/** + * Matches the given [IExpr] instance to appropriate [MST] node or evaluates it with [evaluator]. + */ +public fun IExpr.toMst(evaluator: ExprEvaluator = DEFAULT_EVALUATOR): MST = MstExtendedField { + when { + isPlus -> first().toMst(evaluator) + second().toMst(evaluator) + isSin -> sin(first().toMst(evaluator)) + isSinh -> sinh(first().toMst(evaluator)) + isCos -> cos(first().toMst(evaluator)) + isCosh -> cosh(first().toMst(evaluator)) + isTan -> tan(first().toMst(evaluator)) + isTanh -> tanh(first().toMst(evaluator)) + isArcSin -> asin(first().toMst(evaluator)) + isArcCos -> acos(first().toMst(evaluator)) + isArcTan -> atan(first().toMst(evaluator)) + isArcTanh -> atanh(first().toMst(evaluator)) + isE -> bindSymbol("e") + isPi -> bindSymbol("pi") + isTimes -> first().toMst(evaluator) * second().toMst(evaluator) + isOne -> one + isZero -> zero + isImaginaryUnit -> bindSymbol("i") + isMinusOne -> -one + this@toMst is ISymbol -> bindSymbol(symbolName) + isPower -> power(first().toMst(evaluator), evaluator.evalf(second())) + isExp -> exp(first().toMst(evaluator)) + isNumber -> number(evaluator.evalf(this@toMst)) + this@toMst === F.NIL -> error("NIL cannot be converted to MST") + else -> evaluator.eval(this@toMst.toString()).toMst(evaluator) + } +} + +/** + * Matches the given [MST] instance to appropriate [IExpr] node, only standard operations and symbols (which are + * present in, say, [MstExtendedField]) are supported. + */ +public fun MST.toIExpr(): IExpr = when (this) { + is MST.Numeric -> F.symjify(value) + + is Symbol -> when (identity) { + "e" -> F.E + "pi" -> F.Pi + "i" -> ComplexNum.I + else -> F.Dummy(identity) + } + + is MST.Unary -> when (operation) { + 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()) + TrigonometricOperations.ASIN_OPERATION -> F.ArcSin(value.toIExpr()) + TrigonometricOperations.ACOS_OPERATION -> F.ArcCos(value.toIExpr()) + TrigonometricOperations.ATAN_OPERATION -> F.ArcTan(value.toIExpr()) + ExponentialOperations.SINH_OPERATION -> F.Sinh(value.toIExpr()) + ExponentialOperations.COSH_OPERATION -> F.Cosh(value.toIExpr()) + ExponentialOperations.TANH_OPERATION -> F.Tanh(value.toIExpr()) + ExponentialOperations.ASINH_OPERATION -> F.ArcSinh(value.toIExpr()) + ExponentialOperations.ACOSH_OPERATION -> F.ArcCosh(value.toIExpr()) + ExponentialOperations.ATANH_OPERATION -> F.ArcTanh(value.toIExpr()) + PowerOperations.SQRT_OPERATION -> F.Sqrt(value.toIExpr()) + ExponentialOperations.EXP_OPERATION -> F.Exp(value.toIExpr()) + ExponentialOperations.LN_OPERATION -> F.Log(value.toIExpr()) + else -> error("Unary operation $operation not defined in $this") + } + + is MST.Binary -> when (operation) { + 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-tensors/README.md b/kmath-tensors/README.md index 75de2bf35..b19a55381 100644 --- a/kmath-tensors/README.md +++ b/kmath-tensors/README.md @@ -3,13 +3,13 @@ Common linear algebra operations on tensors. - [tensor algebra](src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt) : Basic linear algebra operations on tensors (plus, dot, etc.) - - [tensor algebra with broadcasting](src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt) : Basic linear algebra operations implemented with broadcasting. + - [tensor algebra with broadcasting](src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt) : Basic linear algebra operations implemented with broadcasting. - [linear algebra operations](src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt) : Advanced linear algebra operations like LU decomposition, SVD, etc. ## Artifact: -The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-11`. +The Maven coordinates of this project are `space.kscience:kmath-tensors:0.3.0-dev-14`. **Gradle:** ```gradle @@ -19,7 +19,7 @@ repositories { } dependencies { - implementation 'space.kscience:kmath-tensors:0.3.0-dev-11' + 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-11") + 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 b7f24dc6a..d084878ea 100644 --- a/kmath-tensors/build.gradle.kts +++ b/kmath-tensors/build.gradle.kts @@ -1,11 +1,14 @@ plugins { - id("ru.mipt.npm.gradle.mpp") + kotlin("multiplatform") + id("ru.mipt.npm.gradle.common") + id("ru.mipt.npm.gradle.native") } kotlin.sourceSets { all { languageSettings.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") } + commonMain { dependencies { api(project(":kmath-core")) @@ -14,30 +17,22 @@ kotlin.sourceSets { } } -tasks.dokkaHtml { - dependsOn(tasks.build) -} - readme { maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) feature( id = "tensor algebra", - description = "Basic linear algebra operations on tensors (plus, dot, etc.)", ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt" - ) + ) { "Basic linear algebra operations on tensors (plus, dot, etc.)" } feature( id = "tensor algebra with broadcasting", - description = "Basic linear algebra operations implemented with broadcasting.", - ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/core/algebras/BroadcastDoubleTensorAlgebra.kt" - ) + ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt" + ) { "Basic linear algebra operations implemented with broadcasting." } feature( id = "linear algebra operations", - description = "Advanced linear algebra operations like LU decomposition, SVD, etc.", ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt" - ) - -} \ No newline at end of file + ) { "Advanced linear algebra operations like LU decomposition, SVD, etc." } +} 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 6bdecfa85..af4ae8239 100644 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt @@ -23,7 +23,7 @@ public interface LinearOpsTensorAlgebra : TensorPartialDivisionAlgebra { /** * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input. * Given a square matrix `A`, return the matrix `AInv` satisfying - * `A dot AInv = AInv dot A = eye(a.shape[0])`. + * `A dot AInv == AInv dot A == eye(a.shape[0])`. * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.inv * * @return the multiplicative inverse of a matrix. @@ -36,25 +36,27 @@ public interface LinearOpsTensorAlgebra : TensorPartialDivisionAlgebra { * Computes the Cholesky decomposition of a Hermitian (or symmetric for real-valued matrices) * positive-definite matrix or the Cholesky decompositions for a batch of such matrices. * Each decomposition has the form: - * Given a tensor `input`, return the tensor `L` satisfying `input = L dot L.H`, - * where L is a lower-triangular matrix and L.H is the conjugate transpose of L, + * Given a tensor `input`, return the tensor `L` satisfying `input = L dot LH`, + * where `L` is a lower-triangular matrix and `LH` is the conjugate transpose of `L`, * which is just a transpose for the case of real-valued input matrices. * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.cholesky * - * @return the batch of L matrices. + * @receiver the `input`. + * @return the batch of `L` matrices. */ public fun Tensor.cholesky(): Tensor /** * QR decomposition. * - * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `(Q, R)` of tensors. - * Given a tensor `input`, return tensors (Q, R) satisfying ``input = Q dot R``, + * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `Q to R` of tensors. + * Given a tensor `input`, return tensors `Q to R` satisfying `input == Q dot R`, * with `Q` being an orthogonal matrix or batch of orthogonal matrices * and `R` being an upper triangular matrix or batch of upper triangular matrices. * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.qr * - * @return pair of Q and R tensors. + * @receiver the `input`. + * @return pair of `Q` and `R` tensors. */ public fun Tensor.qr(): Pair, Tensor> @@ -67,7 +69,8 @@ public interface LinearOpsTensorAlgebra : TensorPartialDivisionAlgebra { * `L` being a lower triangular matrix or batch of matrices, * `U` being an upper triangular matrix or batch of matrices. * - * * @return triple of P, L and U tensors + * @receiver the `input`. + * @return triple of P, L and U tensors */ public fun Tensor.lu(): Triple, Tensor, Tensor> @@ -75,22 +78,25 @@ public interface LinearOpsTensorAlgebra : TensorPartialDivisionAlgebra { * Singular Value Decomposition. * * Computes the singular value decomposition of either a matrix or batch of matrices `input`. - * The singular value decomposition is represented as a triple `(U, S, V)`, - * such that `input = U dot diagonalEmbedding(S) dot V.H`, - * where V.H is the conjugate transpose of V. - * If input is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as input. + * The singular value decomposition is represented as a triple `Triple(U, S, V)`, + * such that `input = U dot diagonalEmbedding(S) dot VH`, + * where `VH` is the conjugate transpose of V. + * If `input` is a batch of tensors, then `U`, `S`, and `VH` are also batched with the same batch dimensions as + * `input`. * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.svd * - * @return triple `(U, S, V)`. + * @receiver the `input`. + * @return triple `Triple(U, S, V)`. */ public fun Tensor.svd(): Triple, Tensor, Tensor> /** - * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, - * represented by a pair (eigenvalues, eigenvectors). + * Returns eigenvalues and eigenvectors of a real symmetric matrix `input` or a batch of real symmetric matrices, + * represented by a pair `eigenvalues to eigenvectors`. * For more information: https://pytorch.org/docs/stable/generated/torch.symeig.html * - * @return a pair (eigenvalues, eigenvectors) + * @receiver the `input`. + * @return a pair `eigenvalues to eigenvectors` */ public fun Tensor.symEig(): Pair, Tensor> diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt index 62b8ef046..d48e7b1c9 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 @@ -14,7 +14,6 @@ import space.kscience.kmath.operations.Algebra * @param T the type of items in the tensors. */ public interface TensorAlgebra : Algebra> { - /** * Returns a single tensor value of unit dimension if tensor shape equals to [1]. * @@ -189,7 +188,7 @@ public interface TensorAlgebra : Algebra> { /** * View this tensor as the same size as [other]. - * ``this.viewAs(other) is equivalent to this.view(other.shape)``. + * `this.viewAs(other)` is equivalent to `this.view(other.shape)`. * For more information: https://pytorch.org/cppdocs/notes/tensor_indexing.html * * @param other the result tensor has the same size as other. @@ -217,14 +216,14 @@ public interface TensorAlgebra : Algebra> { * a 1 is prepended to its dimension for the purpose of the batched matrix multiply and removed after. * If the second argument is 1-dimensional, a 1 is appended to its dimension for the purpose of the batched matrix * multiple and removed after. - * The non-matrix (i.e. batch) dimensions are broadcast (and thus must be broadcastable). + * The non-matrix (i.e., batch) dimensions are broadcast (and thus must be broadcastable). * For example, if `input` is a (j × 1 × n × n) tensor and `other` is a * (k × n × n) tensor, out will be a (j × k × n × n) tensor. * * For more information: https://pytorch.org/docs/stable/generated/torch.matmul.html * - * @param other tensor to be multiplied - * @return mathematical product of two tensors + * @param other tensor to be multiplied. + * @return a mathematical product of two tensors. */ public infix fun Tensor.dot(other: Tensor): Tensor @@ -234,7 +233,7 @@ public interface TensorAlgebra : Algebra> { * To facilitate creating batched diagonal matrices, * the 2D planes formed by the last two dimensions of the returned tensor are chosen by default. * - * The argument [offset] controls which diagonal to consider: + * The argument [offset] controls, which diagonal to consider: * 1. If [offset] = 0, it is the main diagonal. * 1. If [offset] > 0, it is above the main diagonal. * 1. If [offset] < 0, it is below the main diagonal. @@ -321,7 +320,7 @@ public interface TensorAlgebra : Algebra> { * * @param dim the dimension to reduce. * @param keepDim whether the output tensor has [dim] retained or not. - * @return the the index of maximum value of each row of the input tensor in the given dimension [dim]. + * @return the index of maximum value of each row of the input tensor in the given dimension [dim]. */ public fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt index 02bf5415d..867d4b26e 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 @@ -49,7 +49,7 @@ public interface TensorPartialDivisionAlgebra : TensorAlgebra { /** * Each element of this tensor is divided by each element of the [other] tensor. * - * @param other tensor to be divide by. + * @param other tensor to be divided by. */ public operator fun Tensor.divAssign(other: Tensor) } diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt index 315dc4505..87ac2fdf6 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 @@ -11,8 +11,8 @@ import space.kscience.kmath.tensors.core.internal.TensorLinearStructure */ public open class BufferedTensor internal constructor( override val shape: IntArray, - internal val mutableBuffer: MutableBuffer, - internal val bufferStart: Int + @PublishedApi internal val mutableBuffer: MutableBuffer, + @PublishedApi internal val bufferStart: Int, ) : Tensor { /** 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 41df50cba..8e5116336 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 @@ -11,7 +11,7 @@ import space.kscience.kmath.tensors.core.internal.toPrettyString /** * Default [BufferedTensor] implementation for [Double] values */ -public class DoubleTensor internal constructor( +public class DoubleTensor @PublishedApi internal constructor( shape: IntArray, buffer: DoubleArray, offset: Int = 0 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 f854beb29..79a254909 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 @@ -92,37 +92,37 @@ public open class DoubleTensorAlgebra : } /** - * Returns a tensor filled with the scalar value 0.0, with the shape defined by the variable argument [shape]. + * Returns a tensor filled with the scalar value `0.0`, with the shape defined by the variable argument [shape]. * * @param shape array of integers defining the shape of the output tensor. - * @return tensor filled with the scalar value 0.0, with the [shape] shape. + * @return tensor filled with the scalar value `0.0`, with the [shape] shape. */ public fun zeros(shape: IntArray): DoubleTensor = full(0.0, shape) /** - * Returns a tensor filled with the scalar value 0.0, with the same shape as a given array. + * Returns a tensor filled with the scalar value `0.0`, with the same shape as a given array. * - * @return tensor filled with the scalar value 0.0, with the same shape as `input` tensor. + * @return tensor filled with the scalar value `0.0`, with the same shape as `input` tensor. */ public fun Tensor.zeroesLike(): DoubleTensor = tensor.fullLike(0.0) /** - * Returns a tensor filled with the scalar value 1.0, with the shape defined by the variable argument [shape]. + * Returns a tensor filled with the scalar value `1.0`, with the shape defined by the variable argument [shape]. * * @param shape array of integers defining the shape of the output tensor. - * @return tensor filled with the scalar value 1.0, with the [shape] shape. + * @return tensor filled with the scalar value `1.0`, with the [shape] shape. */ public fun ones(shape: IntArray): DoubleTensor = full(1.0, shape) /** - * Returns a tensor filled with the scalar value 1.0, with the same shape as a given array. + * Returns a tensor filled with the scalar value `1.0`, with the same shape as a given array. * - * @return tensor filled with the scalar value 1.0, with the same shape as `input` tensor. + * @return tensor filled with the scalar value `1.0`, with the same shape as `input` tensor. */ public fun Tensor.onesLike(): DoubleTensor = tensor.fullLike(1.0) /** - * Returns a 2-D tensor with shape ([n], [n]), with ones on the diagonal and zeros elsewhere. + * Returns a 2D tensor with shape ([n], [n]), with ones on the diagonal and zeros elsewhere. * * @param n the number of rows and columns * @return a 2-D tensor with ones on the diagonal and zeros elsewhere. @@ -313,7 +313,6 @@ public open class DoubleTensorAlgebra : return resTensor } - override fun Tensor.view(shape: IntArray): DoubleTensor { checkView(tensor, shape) return DoubleTensor(shape, tensor.mutableBuffer.array(), tensor.bufferStart) @@ -428,13 +427,11 @@ public open class DoubleTensorAlgebra : * @param transform the function to be applied to each element of the tensor. * @return the resulting tensor after applying the function. */ - public fun Tensor.map(transform: (Double) -> Double): DoubleTensor { - return DoubleTensor( - tensor.shape, - tensor.mutableBuffer.array().map { transform(it) }.toDoubleArray(), - tensor.bufferStart - ) - } + 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. @@ -448,7 +445,7 @@ public open class DoubleTensorAlgebra : /** * Compares element-wise two tensors. - * Comparison of two Double values occurs with 1e-5 precision. + * Comparison of two Double values occurs with `1e-5` precision. * * @param other the tensor to compare with `input` tensor. * @return true if two tensors have the same shape and elements, false otherwise. @@ -477,23 +474,24 @@ public open class DoubleTensorAlgebra : } /** - * Returns a tensor of random numbers drawn from normal distributions with 0.0 mean and 1.0 standard deviation. + * Returns a tensor of random numbers drawn from normal distributions with `0.0` mean and `1.0` standard deviation. * * @param shape the desired shape for the output tensor. * @param seed the random seed of the pseudo-random number generator. * @return tensor of a given shape filled with numbers from the normal distribution - * with 0.0 mean and 1.0 standard deviation. + * with `0.0` mean and `1.0` standard deviation. */ public fun randomNormal(shape: IntArray, seed: Long = 0): DoubleTensor = DoubleTensor(shape, getRandomNormals(shape.reduce(Int::times), seed)) /** * Returns a tensor with the same shape as `input` of random numbers drawn from normal distributions - * with 0.0 mean and 1.0 standard deviation. + * with `0.0` mean and `1.0` standard deviation. * + * @receiver the `input`. * @param seed the random seed of the pseudo-random number generator. - * @return tensor with the same shape as `input` filled with numbers from the normal distribution - * with 0.0 mean and 1.0 standard deviation. + * @return a tensor with the same shape as `input` filled with numbers from the normal distribution + * with `0.0` mean and `1.0` standard deviation. */ public fun Tensor.randomNormalLike(seed: Long = 0): DoubleTensor = DoubleTensor(tensor.shape, getRandomNormals(tensor.shape.reduce(Int::times), seed)) @@ -516,19 +514,17 @@ public open class DoubleTensorAlgebra : } /** - * Builds tensor from rows of input tensor + * Builds tensor from rows of the input tensor. * * @param indices the [IntArray] of 1-dimensional indices - * @return tensor with rows corresponding to rows by [indices] + * @return tensor with rows corresponding to row by [indices] */ - public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor { - return stack(indices.map { this[it] }) - } + public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { this[it] }) - internal fun Tensor.fold(foldFunction: (DoubleArray) -> Double): Double = + internal inline fun Tensor.fold(foldFunction: (DoubleArray) -> Double): Double = foldFunction(tensor.toDoubleArray()) - internal fun Tensor.foldDim( + internal inline fun Tensor.foldDim( foldFunction: (DoubleArray) -> Double, dim: Int, keepDim: Boolean, @@ -621,12 +617,12 @@ public open class DoubleTensorAlgebra : } /** - * Returns the covariance matrix M of given vectors. + * Returns the covariance matrix `M` of given vectors. * - * M[i, j] contains covariance of i-th and j-th given vectors + * `M[i, j]` contains covariance of `i`-th and `j`-th given vectors * * @param tensors the [List] of 1-dimensional tensors with same shape - * @return the covariance matrix + * @return `M`. */ public fun cov(tensors: List>): DoubleTensor { check(tensors.isNotEmpty()) { "List must have at least 1 element" } @@ -709,14 +705,14 @@ public open class DoubleTensorAlgebra : /** * Unpacks the data and pivots from a LU factorization of a tensor. - * Given a tensor [luTensor], return tensors (P, L, U) satisfying ``P * luTensor = L * U``, + * Given a tensor [luTensor], return tensors `Triple(P, L, U)` satisfying `P dot luTensor = L dot U`, * with `P` being a permutation matrix or batch of matrices, * `L` being a lower triangular matrix or batch of matrices, * `U` being an upper triangular matrix or batch of matrices. * * @param luTensor the packed LU factorization data * @param pivotsTensor the packed LU factorization pivots - * @return triple of P, L and U tensors + * @return triple of `P`, `L` and `U` tensors */ public fun luPivot( luTensor: Tensor, @@ -752,14 +748,15 @@ public open class DoubleTensorAlgebra : /** * QR decomposition. * - * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `(Q, R)` of tensors. - * Given a tensor `input`, return tensors (Q, R) satisfying ``input = Q * R``, + * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `Q to R` of tensors. + * Given a tensor `input`, return tensors `Q to R` satisfying `input == Q dot R`, * with `Q` being an orthogonal matrix or batch of orthogonal matrices * and `R` being an upper triangular matrix or batch of upper triangular matrices. * - * @param epsilon permissible error when comparing tensors for equality. + * @receiver the `input`. + * @param epsilon the permissible error when comparing tensors for equality. * Used when checking the positive definiteness of the input matrix or matrices. - * @return pair of Q and R tensors. + * @return a pair of `Q` and `R` tensors. */ public fun Tensor.cholesky(epsilon: Double): DoubleTensor { checkSquareMatrix(shape) @@ -799,13 +796,14 @@ public open class DoubleTensorAlgebra : * Singular Value Decomposition. * * Computes the singular value decomposition of either a matrix or batch of matrices `input`. - * The singular value decomposition is represented as a triple `(U, S, V)`, - * such that ``input = U.dot(diagonalEmbedding(S).dot(V.T))``. - * If input is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as input. + * The singular value decomposition is represented as a triple `Triple(U, S, V)`, + * such that `input == U dot diagonalEmbedding(S) dot V.transpose()`. + * If `input` is a batch of tensors, then U, S, and Vh are also batched with the same batch dimensions as `input. * - * @param epsilon permissible error when calculating the dot product of vectors, - * i.e. the precision with which the cosine approaches 1 in an iterative algorithm. - * @return triple `(U, S, V)`. + * @receiver the `input`. + * @param epsilon permissible error when calculating the dot product of vectors + * i.e., the precision with which the cosine approaches 1 in an iterative algorithm. + * @return a triple `Triple(U, S, V)`. */ public fun Tensor.svd(epsilon: Double): Triple { val size = tensor.dimension @@ -844,11 +842,11 @@ public open class DoubleTensorAlgebra : /** * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, - * represented by a pair (eigenvalues, eigenvectors). + * represented by a pair `eigenvalues to eigenvectors`. * - * @param epsilon permissible error when comparing tensors for equality + * @param epsilon the permissible error when comparing tensors for equality * and when the cosine approaches 1 in the SVD algorithm. - * @return a pair (eigenvalues, eigenvectors) + * @return a pair `eigenvalues to eigenvectors`. */ public fun Tensor.symEig(epsilon: Double): Pair { checkSymmetric(tensor, epsilon) @@ -881,11 +879,11 @@ public open class DoubleTensorAlgebra : * Computes the determinant of a square matrix input, or of each square matrix in a batched input * using LU factorization algorithm. * - * @param epsilon error in the LU algorithm - permissible error when comparing the determinant of a matrix with zero + * @param epsilon the error in the LU algorithm—permissible error when comparing the determinant of a matrix + * with zero. * @return the determinant. */ public fun Tensor.detLU(epsilon: Double = 1e-9): DoubleTensor { - checkSquareMatrix(tensor.shape) val luTensor = tensor.copy() val pivotsTensor = tensor.setUpPivots() @@ -913,9 +911,9 @@ public open class DoubleTensorAlgebra : * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input * using LU factorization algorithm. * Given a square matrix `a`, return the matrix `aInv` satisfying - * ``a.dot(aInv) = aInv.dot(a) = eye(a.shape[0])``. + * `a dot aInv == aInv dot a == eye(a.shape[0])`. * - * @param epsilon error in the LU algorithm - permissible error when comparing the determinant of a matrix with zero + * @param epsilon error in the LU algorithm—permissible error when comparing the determinant of a matrix with zero * @return the multiplicative inverse of a matrix. */ public fun Tensor.invLU(epsilon: Double = 1e-9): DoubleTensor { @@ -932,16 +930,16 @@ public open class DoubleTensorAlgebra : } /** - * LUP decomposition + * LUP decomposition. * * Computes the LUP decomposition of a matrix or a batch of matrices. - * Given a tensor `input`, return tensors (P, L, U) satisfying ``P * input = L * U``, + * Given a tensor `input`, return tensors `Triple(P, L, U)` satisfying `P dot input == L dot U`, * with `P` being a permutation matrix or batch of matrices, * `L` being a lower triangular matrix or batch of matrices, * `U` being an upper triangular matrix or batch of matrices. * - * @param epsilon permissible error when comparing the determinant of a matrix with zero - * @return triple of P, L and U tensors + * @param epsilon permissible error when comparing the determinant of a matrix with zero. + * @return triple of `P`, `L` and `U` tensors. */ public fun Tensor.lu(epsilon: Double = 1e-9): Triple { val (lu, pivots) = tensor.luFactor(epsilon) 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 d965b6bcd..77264ff92 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 @@ -31,6 +31,7 @@ internal fun Tensor.toBufferedTensor(): BufferedTensor = when (this) { else -> this.copyToBufferedTensor() } +@PublishedApi internal val Tensor.tensor: DoubleTensor get() = when (this) { is DoubleTensor -> this 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 0ffaf39e7..ff89568ea 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 @@ -14,7 +14,7 @@ import space.kscience.kmath.tensors.core.DoubleTensor import kotlin.math.* /** - * Returns a reference to [IntArray] containing all of the elements of this [Buffer] or copy the data. + * Returns a reference to [IntArray] containing all the elements of this [Buffer] or copy the data. */ internal fun Buffer.array(): IntArray = when (this) { is IntBuffer -> array @@ -22,8 +22,9 @@ internal fun Buffer.array(): IntArray = when (this) { } /** - * Returns a reference to [DoubleArray] containing all of the elements of this [Buffer] or copy the data. + * Returns a reference to [DoubleArray] containing all the elements of this [Buffer] or copy the data. */ +@PublishedApi internal fun Buffer.array(): DoubleArray = when (this) { is DoubleBuffer -> array else -> this.toDoubleArray() 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 347bb683f..c525d5c83 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 @@ -183,7 +183,7 @@ internal class TestDoubleLinearOpsTensorAlgebra { } -private fun DoubleTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double = 1e-10): Unit { +private fun DoubleTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double = 1e-10) { val svd = tensor.svd() val tensorSVD = svd.first 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 e7e898008..85c3e74e3 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 @@ -17,7 +17,7 @@ internal class TestDoubleTensorAlgebra { } @Test - fun TestDoubleDiv() = DoubleTensorAlgebra { + fun testDoubleDiv() = DoubleTensorAlgebra { val tensor = fromArray(intArrayOf(2), doubleArrayOf(2.0, 4.0)) val res = 2.0/tensor assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 0.5)) 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 bbf502faf..c7f45c6da 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 @@ -10,15 +10,15 @@ import space.kscience.kmath.structures.MutableBuffer @Suppress("NOTHING_TO_INLINE", "OVERRIDE_BY_INLINE") public class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuffer { - public override val size: Int + override val size: Int get() = flatArray.size - public override inline fun get(index: Int): Double = flatArray[index] + override inline fun get(index: Int): Double = flatArray[index] - public override inline fun set(index: Int, value: Double) { + override inline fun set(index: Int, value: Double) { flatArray[index] = value } - public override fun copy(): MutableBuffer = ViktorBuffer(flatArray.copy().flatten()) - public override operator fun iterator(): Iterator = flatArray.data.iterator() + override fun copy(): MutableBuffer = ViktorBuffer(flatArray.copy().flatten()) + override operator fun iterator(): Iterator = flatArray.data.iterator() } 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 b7abf4304..2be964017 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 @@ -16,16 +16,16 @@ import space.kscience.kmath.operations.ScaleOperations @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") public class ViktorStructureND(public val f64Buffer: F64Array) : MutableStructureND { - public override val shape: IntArray get() = f64Buffer.shape + override val shape: IntArray get() = f64Buffer.shape - public override inline fun get(index: IntArray): Double = f64Buffer.get(*index) + override inline fun get(index: IntArray): Double = f64Buffer.get(*index) - public override inline fun set(index: IntArray, value: Double) { + override inline fun set(index: IntArray, value: Double) { f64Buffer.set(*index, value = value) } @PerformancePitfall - public override fun elements(): Sequence> = + override fun elements(): Sequence> = DefaultStrides(shape).indices().map { it to get(it) } } @@ -33,7 +33,7 @@ public fun F64Array.asStructure(): ViktorStructureND = ViktorStructureND(this) @OptIn(UnstableKMathAPI::class) @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public class ViktorFieldND(public override val shape: IntArray) : FieldND, +public class ViktorFieldND(override val shape: IntArray) : FieldND, NumbersAddOperations>, ExtendedField>, ScaleOperations> { @@ -47,30 +47,30 @@ public class ViktorFieldND(public override val shape: IntArray) : FieldND produce { this@f64Buffer[it] }.f64Buffer } - public override val zero: ViktorStructureND by lazy { F64Array.full(init = 0.0, shape = shape).asStructure() } - public override val one: ViktorStructureND by lazy { F64Array.full(init = 1.0, shape = shape).asStructure() } + 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) - public override val elementContext: DoubleField get() = DoubleField + override val elementContext: DoubleField get() = DoubleField - public override fun produce(initializer: DoubleField.(IntArray) -> Double): ViktorStructureND = + 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() - public override fun StructureND.unaryMinus(): StructureND = -1 * this + override fun StructureND.unaryMinus(): StructureND = -1 * this - public override fun StructureND.map(transform: DoubleField.(Double) -> Double): ViktorStructureND = + 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() - public override fun StructureND.mapIndexed( + override fun StructureND.mapIndexed( transform: DoubleField.(index: IntArray, Double) -> Double, ): ViktorStructureND = F64Array(*this@ViktorFieldND.shape).apply { this@ViktorFieldND.strides.indices().forEach { index -> @@ -78,7 +78,7 @@ public class ViktorFieldND(public override val shape: IntArray) : FieldND, b: StructureND, transform: DoubleField.(Double, Double) -> Double, @@ -88,39 +88,39 @@ public class ViktorFieldND(public override val shape: IntArray) : FieldND, b: StructureND): ViktorStructureND = + override fun add(a: StructureND, b: StructureND): ViktorStructureND = (a.f64Buffer + b.f64Buffer).asStructure() - public override fun scale(a: StructureND, value: Double): ViktorStructureND = - (a.f64Buffer * value.toDouble()).asStructure() + override fun scale(a: StructureND, value: Double): ViktorStructureND = + (a.f64Buffer * value).asStructure() - public override inline fun StructureND.plus(b: StructureND): ViktorStructureND = + override inline fun StructureND.plus(b: StructureND): ViktorStructureND = (f64Buffer + b.f64Buffer).asStructure() - public override inline fun StructureND.minus(b: StructureND): ViktorStructureND = + override inline fun StructureND.minus(b: StructureND): ViktorStructureND = (f64Buffer - b.f64Buffer).asStructure() - public override inline fun StructureND.times(k: Number): ViktorStructureND = + override inline fun StructureND.times(k: Number): ViktorStructureND = (f64Buffer * k.toDouble()).asStructure() - public override inline fun StructureND.plus(arg: Double): ViktorStructureND = + override inline fun StructureND.plus(arg: Double): ViktorStructureND = (f64Buffer.plus(arg)).asStructure() - public override fun number(value: Number): ViktorStructureND = + override fun number(value: Number): ViktorStructureND = F64Array.full(init = value.toDouble(), shape = shape).asStructure() - public override fun sin(arg: StructureND): ViktorStructureND = arg.map { sin(it) } - public override fun cos(arg: StructureND): ViktorStructureND = arg.map { cos(it) } - public override fun tan(arg: StructureND): ViktorStructureND = arg.map { tan(it) } - public override fun asin(arg: StructureND): ViktorStructureND = arg.map { asin(it) } - public override fun acos(arg: StructureND): ViktorStructureND = arg.map { acos(it) } - public override fun atan(arg: StructureND): ViktorStructureND = arg.map { atan(it) } + 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) } - public override fun power(arg: StructureND, pow: Number): ViktorStructureND = arg.map { it.pow(pow) } + override fun power(arg: StructureND, pow: Number): ViktorStructureND = arg.map { it.pow(pow) } - public override fun exp(arg: StructureND): ViktorStructureND = arg.f64Buffer.exp().asStructure() + override fun exp(arg: StructureND): ViktorStructureND = arg.f64Buffer.exp().asStructure() - public override fun ln(arg: StructureND): ViktorStructureND = arg.f64Buffer.log().asStructure() + override fun ln(arg: StructureND): ViktorStructureND = arg.f64Buffer.log().asStructure() } public fun ViktorNDField(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape) diff --git a/settings.gradle.kts b/settings.gradle.kts index 065dd3ac4..f05092bb1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -5,19 +5,13 @@ pluginManagement { gradlePluginPortal() } - val toolsVersion = "0.9.9" - val kotlinVersion = "1.5.0" + val kotlinVersion = "1.5.21" plugins { - id("ru.mipt.npm.gradle.project") version toolsVersion - id("ru.mipt.npm.gradle.mpp") version toolsVersion - id("ru.mipt.npm.gradle.jvm") version toolsVersion - kotlin("multiplatform") version kotlinVersion - kotlin("jvm") version kotlinVersion - kotlin("plugin.allopen") version kotlinVersion id("org.jetbrains.kotlinx.benchmark") version "0.3.1" - kotlin("jupyter.api") version "0.10.0-25" - + id("ru.mipt.npm.gradle.project") version "0.10.2" + kotlin("multiplatform") version kotlinVersion + kotlin("plugin.allopen") version kotlinVersion } } @@ -42,6 +36,8 @@ include( ":kmath-kotlingrad", ":kmath-tensors", ":kmath-jupyter", + ":kmath-symja", + ":kmath-jafama", ":examples", - ":benchmarks" + ":benchmarks", )