diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index cde58b6d6..000000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Gradle build - -on: - push: - branches: [ dev, master ] - pull_request: - -jobs: - build: - strategy: - matrix: - os: [ macOS-latest, windows-latest ] - runs-on: ${{matrix.os}} - 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.2.0 - java: java11 - arch: amd64 - - name: Cache gradle - uses: actions/cache@v2 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache konan - uses: actions/cache@v2 - with: - path: ~/.konan - key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Build - run: ./gradlew build --build-cache --no-daemon --stacktrace diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 000000000..adc74adfe --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,17 @@ +name: Gradle build + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Build with Gradle + run: ./gradlew build diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml deleted file mode 100644 index 23ed54357..000000000 --- a/.github/workflows/pages.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Dokka publication - -on: - push: - branches: [ master ] - -jobs: - build: - runs-on: ubuntu-20.04 - timeout-minutes: 40 - steps: - - uses: actions/checkout@v2 - - uses: DeLaGuardo/setup-graalvm@4.0 - with: - 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 deleted file mode 100644 index c5075cb0f..000000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Gradle publish - -on: - workflow_dispatch: - release: - types: [ created ] - -jobs: - publish: - environment: - name: publish - strategy: - matrix: - os: [ macOS-latest, windows-latest ] - runs-on: ${{matrix.os}} - steps: - - name: Checkout the repo - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: DeLaGuardo/setup-graalvm@4.0 - with: - graalvm: 21.2.0 - java: java11 - arch: amd64 - - name: Cache gradle - uses: actions/cache@v2 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Cache konan - uses: actions/cache@v2 - with: - path: ~/.konan - key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }} - restore-keys: | - ${{ runner.os }}-gradle- - - name: Publish Windows Artifacts - if: matrix.os == 'windows-latest' - shell: cmd - run: > - ./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true - -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} - -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} - - name: Publish Mac Artifacts - if: matrix.os == 'macOS-latest' - run: > - ./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true -Ppublishing.platform=macosX64 - -Ppublishing.space.user=${{ secrets.SPACE_APP_ID }} - -Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }} diff --git a/.gitignore b/.gitignore index d6c4af4e3..a9294eff9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,12 @@ .gradle build/ out/ - .idea/ -!.idea/copyright/ -!.idea/scopes/ - -.vscode/ - # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) !gradle-wrapper.jar # Cache of project .gradletasknamecache -# Generated by javac -h and runtime -*.class -*.log +gradle.properties \ No newline at end of file diff --git a/.idea/copyright/kmath.xml b/.idea/copyright/kmath.xml deleted file mode 100644 index 1070e5d33..000000000 --- a/.idea/copyright/kmath.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml deleted file mode 100644 index b538bdf41..000000000 --- a/.idea/copyright/profiles_settings.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/scopes/Apply_copyright.xml b/.idea/scopes/Apply_copyright.xml deleted file mode 100644 index 0eb589133..000000000 --- a/.idea/scopes/Apply_copyright.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/.space.kts b/.space.kts deleted file mode 100644 index d70ad6d59..000000000 --- a/.space.kts +++ /dev/null @@ -1,3 +0,0 @@ -job("Build") { - gradlew("openjdk:11", "build") -} diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 12540821e..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,151 +0,0 @@ -# KMath - -## [Unreleased] -### Added -- `ScaleOperations` interface -- `Field` extends `ScaleOperations` -- Basic integration API -- Basic MPP distributions and samplers -- `bindSymbolOrNull` -- Blocking chains and Statistics -- Multiplatform integration -- Integration for any Field element -- Extended operations for ND4J fields -- Jupyter Notebook integration module (kmath-jupyter) -- `@PerformancePitfall` annotation to mark possibly slow API -- `BigInt` operation performance improvement and fixes by @zhelenskiy (#328) -- Integration between `MST` and Symja `IExpr` - -### Changed -- Exponential operations merged with hyperbolic functions -- Space is replaced by Group. Space is reserved for vector spaces. -- VectorSpace is now a vector space -- Buffer factories for primitives moved to MutableBuffer.Companion -- Rename `NDStructure` and `NDAlgebra` to `StructureND` and `AlgebraND` respectively -- `Real` -> `Double` -- DataSets are moved from functions to core -- Redesign advanced Chain API -- Redesign `MST`. Remove `MstExpression`. -- Move `MST` to core -- Separated benchmarks and examples -- Rewrite `kmath-ejml` without `ejml-simple` artifact, support sparse matrices -- Promote stability of kmath-ast and kmath-kotlingrad to EXPERIMENTAL. -- ColumnarData returns nullable column -- `MST` is made sealed interface -- Replace `MST.Symbolic` by `Symbol`, `Symbol` now implements MST -- Remove Any restriction on polynomials -- Add `out` variance to type parameters of `StructureND` and its implementations where possible -- Rename `DifferentiableMstExpression` to `KotlingradExpression` - -### Deprecated - -### Removed -- Nearest in Domain. To be implemented in geometry package. -- Number multiplication and division in main Algebra chain -- `contentEquals` from Buffer. It moved to the companion. -- MSTExpression -- Expression algebra builders -- Complex and Quaternion no longer are elements. -- Second generic from DifferentiableExpression - -### Fixed -- Ring inherits RingOperations, not GroupOperations -- Univariate histogram filling - -### Security - -## [0.2.0] -### Added -- `fun` annotation for SAM interfaces in library -- Explicit `public` visibility for all public APIs -- Better trigonometric and hyperbolic functions for `AutoDiffField` (https://github.com/mipt-npm/kmath/pull/140) -- Automatic README generation for features (#139) -- Native support for `memory`, `core` and `dimensions` -- `kmath-ejml` to supply EJML SimpleMatrix wrapper (https://github.com/mipt-npm/kmath/pull/136) -- A separate `Symbol` entity, which is used for global unbound symbol. -- A `Symbol` indexing scope. -- Basic optimization API for Commons-math. -- Chi squared optimization for array-like data in CM -- `Fitting` utility object in prob/stat -- ND4J support module submitting `NDStructure` and `NDAlgebra` over `INDArray` -- Coroutine-deterministic Monte-Carlo scope with a random number generator -- Some minor utilities to `kmath-for-real` -- Generic operation result parameter to `MatrixContext` -- New `MatrixFeature` interfaces for matrix decompositions -- Basic Quaternion vector support in `kmath-complex`. - -### Changed -- Package changed from `scientifik` to `space.kscience` -- Gradle version: 6.6 -> 6.8.2 -- Minor exceptions refactor (throwing `IllegalArgumentException` by argument checks instead of `IllegalStateException`) -- `Polynomial` secondary constructor made function -- Kotlin version: 1.3.72 -> 1.4.30 -- `kmath-ast` doesn't depend on heavy `kotlin-reflect` library -- Full autodiff refactoring based on `Symbol` -- `kmath-prob` renamed to `kmath-stat` -- Grid generators moved to `kmath-for-real` -- Use `Point` instead of specialized type in `kmath-for-real` -- Optimized dot product for buffer matrices moved to `kmath-for-real` -- EjmlMatrix context is an object -- Matrix LUP `inverse` renamed to `inverseWithLup` -- `NumericAlgebra` moved outside of regular algebra chain (`Ring` no longer implements it). -- Features moved to NDStructure and became transparent. -- Capitalization of LUP in many names changed to Lup. -- Refactored `NDStructure` algebra to be more simple, preferring under-the-hood conversion to explicit NDStructure types -- Refactor histograms. They are marked as prototype -- `Complex` and related features moved to a separate module `kmath-complex` -- Refactor AlgebraElement -- `symbol` method in `Algebra` renamed to `bindSymbol` to avoid ambiguity -- Add `out` projection to `Buffer` generic - -### Deprecated - -### Removed -- `kmath-koma` module because it doesn't support Kotlin 1.4. -- Support of `legacy` JS backend (we will support only IR) -- `toGrid` method. -- Public visibility of `BufferAccessor2D` -- `Real` class -- StructureND identity and equals - -### Fixed -- `symbol` method in `MstExtendedField` (https://github.com/mipt-npm/kmath/pull/140) - -### Security - -## [0.1.4] - -### Added -- Functional Expressions API -- Mathematical Syntax Tree, its interpreter and API -- String to MST parser (https://github.com/mipt-npm/kmath/pull/120) -- MST to JVM bytecode translator (https://github.com/mipt-npm/kmath/pull/94) -- FloatBuffer (specialized MutableBuffer over FloatArray) -- FlaggedBuffer to associate primitive numbers buffer with flags (to mark values infinite or missing, etc.) -- Specialized builder functions for all primitive buffers like `IntBuffer(25) { it + 1 }` (https://github.com/mipt-npm/kmath/pull/125) -- Interface `NumericAlgebra` where `number` operation is available to convert numbers to algebraic elements -- Inverse trigonometric functions support in ExtendedField (`asin`, `acos`, `atan`) (https://github.com/mipt-npm/kmath/pull/114) -- New space extensions: `average` and `averageWith` -- Local coding conventions -- Geometric Domains API in `kmath-core` -- Blocking chains in `kmath-coroutines` -- Full hyperbolic functions support and default implementations within `ExtendedField` -- Norm support for `Complex` - -### Changed -- `readAsMemory` now has `throws IOException` in JVM signature. -- Several functions taking functional types were made `inline`. -- Several functions taking functional types now have `callsInPlace` contracts. -- BigInteger and BigDecimal algebra: JBigDecimalField has companion object with default math context; minor optimizations -- `power(T, Int)` extension function has preconditions and supports `Field` -- Memory objects have more preconditions (overflow checking) -- `tg` function is renamed to `tan` (https://github.com/mipt-npm/kmath/pull/114) -- Gradle version: 6.3 -> 6.6 -- Moved probability distributions to commons-rng and to `kmath-prob` - -### Fixed -- Missing copy method in Memory implementation on JS (https://github.com/mipt-npm/kmath/pull/106) -- D3.dim value in `kmath-dimensions` -- Multiplication in integer rings in `kmath-core` (https://github.com/mipt-npm/kmath/pull/101) -- Commons RNG compatibility (https://github.com/mipt-npm/kmath/issues/93) -- Multiplication of BigInt by scalar diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index db069d4e0..34761e838 100644 --- a/README.md +++ b/README.md @@ -1,334 +1,104 @@ [![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) [![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/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/) + +Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/scientifik/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/scientifik/kmath-core/_latestVersion) + +Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/scientifik/kmath-core/_latestVersion) # 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. - -[Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/) - -## Publications and talks - -* [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2) -* [Another article about context-oriented design](https://proandroiddev.com/diving-deeper-into-context-oriented-programming-in-kotlin-3ecb4ec38814) -* [ACAT 2019 conference paper](https://aip.scitation.org/doi/abs/10.1063/1.5130103) +Could be pronounced as `key-math`. +The Kotlin MATHematics library is intended as a Kotlin-based analog to Python's `numpy` library. In contrast to `numpy` and `scipy` it is modular and has a lightweight core. # 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 and JS for now and Native in future). * 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 API. -* Provide the best performance out of the box. We have specialized libraries for that. Need only API wrappers for them. +* Be like Numpy. It was the idea at the beginning, but we decided that we can do better in terms of API. +* Provide 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 `for-real`, which will give better experience for those, who want to work with specific types. -## Features and stability +## Features -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: +Actual feature list is [here](doc/features.md) -* **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. +* **Algebra** + * Algebraic structures like rings, spaces and field (**TODO** add example to wiki) + * Basic linear algebra operations (sums, products, etc.), backed by the `Space` API. + * Complex numbers backed by the `Field` API (meaning that they will be usable in any structure like vectors and N-dimensional arrays). + * Advanced linear algebra operations like matrix inversion and LU decomposition. - +* **Array-like structures** Full support of many-dimensional array-like structures +including mixed arithmetic operations and function operations over arrays and numbers (with the added benefit of static type checking). +* **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. - - +* **Histograms** Fast multi-dimensional histograms. - +* **Streaming** Streaming operations on mathematical objects and objects buffers. - +* **Type-safe dimensions** Type-safe dimensions for matrix operations. - +* **Commons-math wrapper** It is planned to gradually wrap most parts of [Apache commons-math](http://commons.apache.org/proper/commons-math/) + library in Kotlin code and maybe rewrite some parts to better suit the Kotlin programming paradigm, however there is no fixed roadmap for that. Feel free + to submit a feature request if you want something to be done first. + +* **Koma wrapper** [Koma](https://github.com/kyonifer/koma) is a well established numerics library in Kotlin, specifically linear algebra. +The plan is to have wrappers for koma implementations for compatibility with kmath API. - - - - - - +## Planned features - +* **Messaging** A mathematical notation to support multi-language and multi-node communication for mathematical tasks. - +* **Array statistics** - +* **Integration** Univariate and multivariate integration framework. - - - - -## Modules - -
- -* ### [benchmarks](benchmarks) -> -> -> **Maturity**: EXPERIMENTAL -
- -* ### [examples](examples) -> -> -> **Maturity**: EXPERIMENTAL -
- -* ### [kmath-ast](kmath-ast) -> -> -> **Maturity**: EXPERIMENTAL -> -> **Features:** -> - [expression-language](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser -> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler -> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler -> - [rendering](kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt) : Extendable MST rendering - -
- -* ### [kmath-commons](kmath-commons) -> -> -> **Maturity**: EXPERIMENTAL -
- -* ### [kmath-complex](kmath-complex) -> Complex numbers and quaternions. -> -> **Maturity**: PROTOTYPE -> -> **Features:** -> - [complex](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers -> - [quaternion](kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions - -
- -* ### [kmath-core](kmath-core) -> Core classes, algebra definitions, basic linear algebra -> -> **Maturity**: DEVELOPMENT -> -> **Features:** -> - [algebras](kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields. -> - [nd](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt) : Many-dimensional structures and operations on them. -> - [linear](kmath-core/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. -> - [buffers](kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt) : One-dimensional structure -> - [expressions](kmath-core/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. -> - [domains](kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains) : Domains -> - [autodiff](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation - -
- -* ### [kmath-coroutines](kmath-coroutines) -> -> -> **Maturity**: EXPERIMENTAL -
- -* ### [kmath-dimensions](kmath-dimensions) -> -> -> **Maturity**: PROTOTYPE -
- -* ### [kmath-ejml](kmath-ejml) -> -> -> **Maturity**: PROTOTYPE -> -> **Features:** -> - [ejml-vector](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt) : Point implementations. -> - [ejml-matrix](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt) : Matrix implementation. -> - [ejml-linear-space](kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt) : LinearSpace implementations. - -
- -* ### [kmath-for-real](kmath-for-real) -> 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. -> -> **Maturity**: EXPERIMENTAL -> -> **Features:** -> - [DoubleVector](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt) : Numpy-like operations for Buffers/Points -> - [DoubleMatrix](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt) : Numpy-like operations for 2d real structures -> - [grids](kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt) : Uniform grid generators - -
- -* ### [kmath-functions](kmath-functions) -> -> -> **Maturity**: EXPERIMENTAL -> -> **Features:** -> - [piecewise](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt) : Piecewise functions. -> - [polynomials](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt) : Polynomial functions. -> - [linear interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt) : Linear XY interpolator. -> - [spline interpolation](kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt) : Cubic spline XY interpolator. -> - [integration](kmath-functions/#) : Univariate and multivariate quadratures - -
- -* ### [kmath-geometry](kmath-geometry) -> -> -> **Maturity**: PROTOTYPE -
- -* ### [kmath-histograms](kmath-histograms) -> -> -> **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) -> -> -> **Maturity**: PROTOTYPE -
- -* ### [kmath-kotlingrad](kmath-kotlingrad) -> -> -> **Maturity**: EXPERIMENTAL -> -> **Features:** -> - [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 continuous memory block. -> -> **Maturity**: DEVELOPMENT -
- -* ### [kmath-nd4j](kmath-nd4j) -> -> -> **Maturity**: EXPERIMENTAL -> -> **Features:** -> - [nd4jarraystructure](kmath-nd4j/#) : NDStructure wrapper for INDArray -> - [nd4jarrayrings](kmath-nd4j/#) : Rings over Nd4jArrayStructure of Int and Long -> - [nd4jarrayfields](kmath-nd4j/#) : Fields over Nd4jArrayStructure of Float and Double - -
- -* ### [kmath-stat](kmath-stat) -> -> -> **Maturity**: EXPERIMENTAL -
- -* ### [kmath-symja](kmath-symja) -> -> -> **Maturity**: PROTOTYPE -
- -* ### [kmath-tensors](kmath-tensors) -> -> -> **Maturity**: PROTOTYPE -> -> **Features:** -> - [tensor algebra](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt) : Basic linear algebra operations on tensors (plus, dot, etc.) -> - [tensor algebra with broadcasting](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt) : Basic linear algebra operations implemented with broadcasting. -> - [linear algebra operations](kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt) : Advanced linear algebra operations like LU decomposition, SVD, etc. - -
- -* ### [kmath-viktor](kmath-viktor) -> -> -> **Maturity**: DEVELOPMENT -
+* **Probability and distributions** +* **Fitting** Non-linear curve fitting facilities ## 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 -feedback are also welcome. +KMath is developed as a multi-platform library, which means that most of interfaces are declared in the [common module](kmath-core/src/commonMain). Implementation is also done in the common module wherever possible. In some cases, features are delegated to platform-specific implementations even if they could be done in the common module for performance reasons. Currently, the JVM is the main focus of development, however Kotlin/Native and Kotlin/JS contributions 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 not possible 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 better than SciPy. -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. +### Dependency -## Requirements - -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 artifacts are accessible from bintray with following configuration (see documentation for [kotlin-multiplatform](https://kotlinlang.org/docs/reference/multiplatform.html) form more details): ```kotlin -repositories { - maven("https://repo.kotlin.link") +repositories{ + maven("https://dl.bintray.com/mipt-npm/scientifik") } -dependencies { - 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 +dependencies{ + api("scientifik:kmath-core:${kmathVersion}") + //api("scientifik:kmath-core-jvm:${kmathVersion}") for jvm-specific version } ``` -Gradle `6.0+` is required for multiplatform artifacts. +Gradle `5.2+` is required for multiplatform artifacts. + +### Development + +Development builds are accessible from the reposirtory +```kotlin +repositories{ + maven("https://dl.bintray.com/mipt-npm/dev") +} +``` +with the same artifact names. ## 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 -[waiting for a hero](https://github.com/mipt-npm/kmath/labels/waiting%20for%20a%20hero) label. +The project requires a lot of additional work. Please feel free to contribute in any way and propose new features. diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts deleted file mode 100644 index d96c5a8b6..000000000 --- a/benchmarks/build.gradle.kts +++ /dev/null @@ -1,138 +0,0 @@ -@file:Suppress("UNUSED_VARIABLE") - -import space.kscience.kmath.benchmarks.addBenchmarkProperties - -plugins { - kotlin("multiplatform") - kotlin("plugin.allopen") - id("org.jetbrains.kotlinx.benchmark") -} - -allOpen.annotation("org.openjdk.jmh.annotations.State") -sourceSets.register("benchmarks") - -repositories { - mavenCentral() - maven("https://repo.kotlin.link") - maven("https://clojars.org/repo") - maven("https://jitpack.io") - - maven("http://logicrunch.research.it.uu.se/maven") { - isAllowInsecureProtocol = true - } -} - -kotlin { - jvm() - - sourceSets { - val commonMain by getting { - dependencies { - implementation(project(":kmath-ast")) - implementation(project(":kmath-core")) - implementation(project(":kmath-coroutines")) - implementation(project(":kmath-complex")) - implementation(project(":kmath-stat")) - implementation(project(":kmath-dimensions")) - implementation(project(":kmath-for-real")) - implementation(project(":kmath-jafama")) - implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.3.1") - } - } - - val jvmMain by getting { - dependencies { - implementation(project(":kmath-commons")) - implementation(project(":kmath-ejml")) - implementation(project(":kmath-nd4j")) - implementation(project(":kmath-kotlingrad")) - implementation(project(":kmath-viktor")) - implementation("org.nd4j:nd4j-native:1.0.0-M1") - // uncomment if your system supports AVX2 - // val os = System.getProperty("os.name") - // - // if (System.getProperty("os.arch") in arrayOf("x86_64", "amd64")) when { - // os.startsWith("Windows") -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:windows-x86_64-avx2") - // os == "Linux" -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:linux-x86_64-avx2") - // os == "Mac OS X" -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:macosx-x86_64-avx2") - // } else - // implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") - } - } - } -} - -// Configure benchmark -benchmark { - // Setup configurations - targets { - register("jvm") - } - - fun kotlinx.benchmark.gradle.BenchmarkConfiguration.commonConfiguration() { - warmups = 1 - iterations = 5 - iterationTime = 1000 - iterationTimeUnit = "ms" - } - - configurations.register("buffer") { - commonConfiguration() - include("BufferBenchmark") - } - - configurations.register("dot") { - commonConfiguration() - include("DotBenchmark") - } - - configurations.register("expressions") { - commonConfiguration() - include("ExpressionsInterpretersBenchmark") - } - - configurations.register("matrixInverse") { - commonConfiguration() - include("MatrixInverseBenchmark") - } - - configurations.register("bigInt") { - commonConfiguration() - include("BigIntBenchmark") - } - - configurations.register("jafamaDouble") { - commonConfiguration() - include("JafamaBenchmark") - } -} - -// Fix kotlinx-benchmarks bug -afterEvaluate { - val jvmBenchmarkJar by tasks.getting(org.gradle.jvm.tasks.Jar::class) { - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - } -} - - -kotlin.sourceSets.all { - with(languageSettings) { - useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") - useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") - useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") - } -} - -tasks.withType { - kotlinOptions { - jvmTarget = "11" - freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" - } -} - - -readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL -} - -addBenchmarkProperties() diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt deleted file mode 100644 index 17983e88c..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import java.nio.IntBuffer - -@State(Scope.Benchmark) -internal class ArrayBenchmark { - @Benchmark - fun benchmarkArrayRead(blackhole: Blackhole) { - var res = 0 - for (i in 1..size) res += array[size - i] - blackhole.consume(res) - } - - @Benchmark - fun benchmarkBufferRead(blackhole: Blackhole) { - var res = 0 - for (i in 1..size) res += arrayBuffer[size - i] - blackhole.consume(res) - } - - @Benchmark - fun nativeBufferRead(blackhole: Blackhole) { - var res = 0 - for (i in 1..size) res += nativeBuffer[size - i] - blackhole.consume(res) - } - - private companion object { - private const val size = 1000 - private val array = IntArray(size) { it } - private val arrayBuffer = IntBuffer.wrap(array) - private val nativeBuffer = IntBuffer.allocate(size).also { for (i in 0 until size) it.put(i, i) } - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt deleted file mode 100644 index 6f501dedb..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE 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.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import java.math.BigInteger - - -@UnstableKMathAPI -@State(Scope.Benchmark) -internal class BigIntBenchmark { - - val kmNumber = BigIntField.number(Int.MAX_VALUE) - val jvmNumber = JBigIntegerField.number(Int.MAX_VALUE) - val largeKmNumber = BigIntField { number(11).pow(100_000U) } - val largeJvmNumber: BigInteger = JBigIntegerField { number(11).pow(100_000) } - val bigExponent = 50_000 - - @Benchmark - fun kmAdd(blackhole: Blackhole) = BigIntField { - blackhole.consume(kmNumber + kmNumber + kmNumber) - } - - @Benchmark - fun jvmAdd(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(jvmNumber + jvmNumber + jvmNumber) - } - - @Benchmark - fun kmAddLarge(blackhole: Blackhole) = BigIntField { - blackhole.consume(largeKmNumber + largeKmNumber + largeKmNumber) - } - - @Benchmark - fun jvmAddLarge(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(largeJvmNumber + largeJvmNumber + largeJvmNumber) - } - - @Benchmark - fun kmMultiply(blackhole: Blackhole) = BigIntField { - blackhole.consume(kmNumber * kmNumber * kmNumber) - } - - @Benchmark - fun kmMultiplyLarge(blackhole: Blackhole) = BigIntField { - blackhole.consume(largeKmNumber*largeKmNumber) - } - - @Benchmark - fun jvmMultiply(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(jvmNumber * jvmNumber * jvmNumber) - } - - @Benchmark - fun jvmMultiplyLarge(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(largeJvmNumber*largeJvmNumber) - } - - @Benchmark - fun kmPower(blackhole: Blackhole) = BigIntField { - blackhole.consume(kmNumber.pow(bigExponent.toUInt())) - } - - @Benchmark - fun jvmPower(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume(jvmNumber.pow(bigExponent)) - } - - @Benchmark - fun kmParsing16(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume("0x7f57ed8b89c29a3b9a85c7a5b84ca3929c7b7488593".parseBigInteger()) - } - - @Benchmark - fun kmParsing10(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume("236656783929183747565738292847574838922010".parseBigInteger()) - } - - @Benchmark - fun jvmParsing10(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume("236656783929183747565738292847574838922010".toBigInteger(10)) - } - - @Benchmark - fun jvmParsing16(blackhole: Blackhole) = JBigIntegerField { - blackhole.consume("7f57ed8b89c29a3b9a85c7a5b84ca3929c7b7488593".toBigInteger(16)) - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt deleted file mode 100644 index 5cf194b67..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import space.kscience.kmath.complex.Complex -import space.kscience.kmath.complex.complex -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.MutableBuffer - -@State(Scope.Benchmark) -internal class BufferBenchmark { - @Benchmark - fun genericDoubleBufferReadWrite() { - val buffer = DoubleBuffer(size) { it.toDouble() } - - (0 until size).forEach { - buffer[it] - } - } - - @Benchmark - fun complexBufferReadWrite() { - val buffer = MutableBuffer.complex(size / 2) { Complex(it.toDouble(), -it.toDouble()) } - - (0 until size / 2).forEach { - buffer[it] - } - } - - private companion object { - private const val size = 100 - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt deleted file mode 100644 index 629408479..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import space.kscience.kmath.commons.linear.CMLinearSpace -import space.kscience.kmath.ejml.EjmlLinearSpaceDDRM -import space.kscience.kmath.linear.LinearSpace -import space.kscience.kmath.linear.invoke -import space.kscience.kmath.operations.DoubleField -import kotlin.random.Random - -@State(Scope.Benchmark) -internal class DotBenchmark { - companion object { - val random = Random(12224) - const val dim = 1000 - - //creating invertible matrix - val matrix1 = LinearSpace.real.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } - val matrix2 = LinearSpace.real.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } - - val cmMatrix1 = CMLinearSpace { matrix1.toCM() } - val cmMatrix2 = CMLinearSpace { matrix2.toCM() } - - val ejmlMatrix1 = EjmlLinearSpaceDDRM { matrix1.toEjml() } - val ejmlMatrix2 = EjmlLinearSpaceDDRM { matrix2.toEjml() } - } - - @Benchmark - fun cmDot(blackhole: Blackhole) { - CMLinearSpace.run { - blackhole.consume(cmMatrix1 dot cmMatrix2) - } - } - - @Benchmark - fun ejmlDot(blackhole: Blackhole) { - EjmlLinearSpaceDDRM { - blackhole.consume(ejmlMatrix1 dot ejmlMatrix2) - } - } - - @Benchmark - fun ejmlDotWithConversion(blackhole: Blackhole) { - EjmlLinearSpaceDDRM { - blackhole.consume(matrix1 dot matrix2) - } - } - - @Benchmark - fun bufferedDot(blackhole: Blackhole) { - LinearSpace.auto(DoubleField).invoke { - blackhole.consume(matrix1 dot matrix2) - } - } - - @Benchmark - fun realDot(blackhole: Blackhole) { - LinearSpace.real { - blackhole.consume(matrix1 dot matrix2) - } - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt deleted file mode 100644 index 8c3c8ec2b..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import space.kscience.kmath.asm.compileToExpression -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 - - repeat(times) { - sum += expr(x to random.nextDouble()) - } - - blackhole.consume(sum) - } - - private companion object { - private val x by symbol - private val algebra = DoubleField - private const val times = 1_000_000 - - 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 { - x * 2.0 + number(2.0) / x - number(16.0) / sin(x) - } - - private val mst = node.toExpression(DoubleField) - private val asm = node.compileToExpression(DoubleField) - - private val raw = Expression { args -> - val x = args[x]!! - x * 2.0 + 2.0 / x - 16.0 / sin(x) - } - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt deleted file mode 100644 index 9c6551302..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.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 deleted file mode 100644 index 1072a55c3..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import space.kscience.kmath.commons.linear.CMLinearSpace -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.nd.getFeature -import kotlin.random.Random - -@State(Scope.Benchmark) -internal class MatrixInverseBenchmark { - private companion object { - private val random = Random(1224) - private const val dim = 100 - - private val space = LinearSpace.real - - //creating invertible matrix - private val u = space.buildMatrix(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } - private val l = space.buildMatrix(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 } - private val matrix = space { l dot u } - } - - @Benchmark - fun kmathLupInversion(blackhole: Blackhole) { - blackhole.consume(LinearSpace.real.inverseWithLup(matrix)) - } - - @Benchmark - fun cmLUPInversion(blackhole: Blackhole) { - CMLinearSpace { - blackhole.consume(inverse(matrix)) - } - } - - @Benchmark - fun ejmlInverse(blackhole: Blackhole) { - EjmlLinearSpaceDDRM { - blackhole.consume(matrix.getFeature>()?.inverse) - } - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt deleted file mode 100644 index 0cd9a46ab..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.Buffer - -@State(Scope.Benchmark) -internal class NDFieldBenchmark { - @Benchmark - fun autoFieldAdd(blackhole: Blackhole) { - with(autoField) { - var res: StructureND = one - repeat(n) { res += one } - blackhole.consume(res) - } - } - - @Benchmark - fun specializedFieldAdd(blackhole: Blackhole) { - with(specializedField) { - var res: StructureND = one - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - } - - - @Benchmark - fun boxingFieldAdd(blackhole: Blackhole) { - with(genericField) { - var res: StructureND = one - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - } - - private companion object { - private const val dim = 1000 - private const val n = 100 - private val autoField = AlgebraND.auto(DoubleField, dim, dim) - private val specializedField = AlgebraND.real(dim, dim) - private val genericField = AlgebraND.field(DoubleField, Buffer.Companion::boxing, dim, dim) - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt deleted file mode 100644 index 1ddc79cf8..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.nd.AlgebraND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.auto -import space.kscience.kmath.nd.real -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.viktor.ViktorNDField - -@State(Scope.Benchmark) -internal class ViktorBenchmark { - @Benchmark - fun automaticFieldAddition(blackhole: Blackhole) { - with(autoField) { - var res: StructureND = one - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - } - - @Benchmark - fun realFieldAddition(blackhole: Blackhole) { - with(realField) { - var res: StructureND = one - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - } - - @Benchmark - fun viktorFieldAddition(blackhole: Blackhole) { - with(viktorField) { - var res = one - repeat(n) { res += 1.0 } - blackhole.consume(res) - } - } - - @Benchmark - fun rawViktor(blackhole: Blackhole) { - val one = F64Array.full(init = 1.0, shape = intArrayOf(dim, dim)) - var res = one - repeat(n) { res = res + one } - blackhole.consume(res) - } - - private companion object { - private const val dim = 1000 - private const val n = 100 - - // automatically build context most suited for given type. - private val autoField = AlgebraND.auto(DoubleField, dim, dim) - private val realField = AlgebraND.real(dim, dim) - private val viktorField = ViktorNDField(dim, dim) - } -} diff --git a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt deleted file mode 100644 index 8622e8f30..000000000 --- a/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.benchmarks - -import kotlinx.benchmark.Benchmark -import kotlinx.benchmark.Blackhole -import kotlinx.benchmark.Scope -import kotlinx.benchmark.State -import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.nd.AlgebraND -import space.kscience.kmath.nd.auto -import space.kscience.kmath.nd.real -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.viktor.ViktorFieldND - -@State(Scope.Benchmark) -internal class ViktorLogBenchmark { - @Benchmark - fun realFieldLog(blackhole: Blackhole) { - with(realNdField) { - val fortyTwo = produce { 42.0 } - var res = one - repeat(n) { res = ln(fortyTwo) } - blackhole.consume(res) - } - } - - @Benchmark - fun viktorFieldLog(blackhole: Blackhole) { - with(viktorField) { - val fortyTwo = produce { 42.0 } - var res = one - repeat(n) { res = ln(fortyTwo) } - blackhole.consume(res) - } - } - - @Benchmark - fun rawViktorLog(blackhole: Blackhole) { - val fortyTwo = F64Array.full(dim, dim, init = 42.0) - lateinit var res: F64Array - repeat(n) { res = fortyTwo.log() } - blackhole.consume(res) - } - - private companion object { - private const val dim = 1000 - private const val n = 100 - - // automatically build context most suited for given type. - private val autoField = AlgebraND.auto(DoubleField, dim, dim) - private val realNdField = AlgebraND.real(dim, dim) - private val viktorField = ViktorFieldND(intArrayOf(dim, dim)) - } -} diff --git a/build.gradle.kts b/build.gradle.kts index 6bb19cd35..6d102a77a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,72 +1,24 @@ -import java.net.URL - plugins { - id("ru.mipt.npm.gradle.project") - kotlin("jupyter.api") apply false + id("scientifik.publish") apply false } +val kmathVersion by extra("0.1.4-dev-7") + +val bintrayRepo by extra("scientifik") +val githubProject by extra("kmath") + 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() + jcenter() + maven("https://dl.bintray.com/kotlin/kotlinx") } - group = "space.kscience" - version = "0.3.0-dev-14" + group = "scientifik" + version = kmathVersion } subprojects { - if (name.startsWith("kmath")) apply() - - afterEvaluate { - tasks.withType { - dependsOn(tasks["assemble"]) - - dokkaSourceSets.all { - 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://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", - ) - } - } + if (name.startsWith("kmath")) { + apply(plugin = "scientifik.publish") } -} - -readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md") - -ksciencePublish { - vcs("https://github.com/mipt-npm/kmath") - space(publish = true) - sonatype(publish = true) -} - -apiValidation.nonPublicMarkers.add("space.kscience.kmath.misc.UnstableKMathAPI") +} \ No newline at end of file diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts deleted file mode 100644 index 36a1ffd9e..000000000 --- a/buildSrc/build.gradle.kts +++ /dev/null @@ -1,20 +0,0 @@ -plugins { - `kotlin-dsl` - kotlin("plugin.serialization") version "1.4.31" -} - -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 deleted file mode 100644 index 6859de845..000000000 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE 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 deleted file mode 100644 index 72c9ff0ad..000000000 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.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 deleted file mode 100644 index 68bb10428..000000000 --- a/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -@file:Suppress("KDocUnresolvedReference") - -package space.kscience.kmath.ejml.codegen - -import org.intellij.lang.annotations.Language -import java.io.File - -private fun Appendable.appendEjmlVector(type: String, ejmlMatrixType: String) { - @Language("kotlin") val text = """/** - * [EjmlVector] specialization for [$type]. - */ -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" } - } - - override operator fun get(index: Int): $type = origin[0, index] -}""" - appendLine(text) - appendLine() -} - -private fun Appendable.appendEjmlMatrix(type: String, ejmlMatrixType: String) { - val text = """/** - * [EjmlMatrix] specialization for [$type]. - */ -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() -} - -private fun Appendable.appendEjmlLinearSpace( - type: String, - kmathAlgebra: String, - ejmlMatrixParentTypeMatrix: String, - ejmlMatrixType: String, - ejmlMatrixDenseType: String, - ops: String, - denseOps: String, - isDense: Boolean, -) { - @Language("kotlin") val text = """/** - * [EjmlLinearSpace] implementation based on [CommonOps_$ops], [DecompositionFactory_${ops}] operations and - * [${ejmlMatrixType}] matrices. - */ -public object EjmlLinearSpace${ops} : EjmlLinearSpace<${type}, ${kmathAlgebra}, $ejmlMatrixType>() { - /** - * The [${kmathAlgebra}] reference. - */ - override val elementAlgebra: $kmathAlgebra get() = $kmathAlgebra - - @Suppress("UNCHECKED_CAST") - 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") - 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) } - }) - } - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: ${kmathAlgebra}.(i: Int, j: Int) -> ${type}, - ): Ejml${type}Matrix<${ejmlMatrixType}> = ${ejmlMatrixType}(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - override fun buildVector( - size: Int, - initializer: ${kmathAlgebra}.(Int) -> ${type}, - ): Ejml${type}Vector<${ejmlMatrixType}> = Ejml${type}Vector(${ejmlMatrixType}(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = Ejml${type}Matrix(this) - private fun T.wrapVector() = Ejml${type}Vector(this) - - override fun Matrix<${type}>.unaryMinus(): Matrix<${type}> = this * elementAlgebra { -one } - - 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() - } - - 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() - } - - override operator fun Matrix<${type}>.minus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { - val out = ${ejmlMatrixType}(1, 1) - - CommonOps_${ops}.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out,${ - if (isDense) "" else - """ - null, - null,""" - } - ) - - return out.wrapMatrix() - } - - 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() - } - - override fun Point<${type}>.unaryMinus(): Ejml${type}Vector<${ejmlMatrixType}> { - val res = ${ejmlMatrixType}(1, 1) - CommonOps_${ops}.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - override fun Matrix<${type}>.plus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { - val out = ${ejmlMatrixType}(1, 1) - - CommonOps_${ops}.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out,${ - if (isDense) "" else - """ - null, - null,""" - } - ) - - return out.wrapMatrix() - } - - override fun Point<${type}>.plus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { - val out = ${ejmlMatrixType}(1, 1) - - CommonOps_${ops}.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out,${ - if (isDense) "" else - """ - null, - null,""" - } - ) - - return out.wrapVector() - } - - override fun Point<${type}>.minus(other: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { - val out = ${ejmlMatrixType}(1, 1) - - CommonOps_${ops}.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out,${ - if (isDense) "" else - """ - null, - null,""" - } - ) - - return out.wrapVector() - } - - override fun ${type}.times(m: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> = m * this - - 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() - } - - override fun ${type}.times(v: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> = v * this - - @UnstableKMathAPI - override fun getFeature(structure: Matrix<${type}>, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - ${ - if (isDense) - """ InverseMatrixFeature::class -> object : InverseMatrixFeature<${type}> { - override val inverse: Matrix<${type}> by lazy { - val res = origin.copy() - CommonOps_${ops}.invert(res) - res.wrapMatrix() - } - } - - DeterminantFeature::class -> object : DeterminantFeature<${type}> { - override val determinant: $type by lazy { CommonOps_${ops}.det(origin) } - } - - SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature<${type}> { - private val svd by lazy { - DecompositionFactory_${ops}.svd(origin.numRows, origin.numCols, true, true, false) - .apply { decompose(origin.copy()) } - } - - override val u: Matrix<${type}> by lazy { svd.getU(null, false).wrapMatrix() } - override val s: Matrix<${type}> by lazy { svd.getW(null).wrapMatrix() } - override val v: Matrix<${type}> by lazy { svd.getV(null, false).wrapMatrix() } - override val singularValues: Point<${type}> by lazy { ${type}Buffer(svd.singularValues) } - } - - QRDecompositionFeature::class -> object : QRDecompositionFeature<${type}> { - private val qr by lazy { - DecompositionFactory_${ops}.qr().apply { decompose(origin.copy()) } - } - - override val q: Matrix<${type}> by lazy { - qr.getQ(null, false).wrapMatrix() + OrthogonalFeature - } - - override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix() + UFeature } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<${type}> { - override val l: Matrix<${type}> by lazy { - val cholesky = - DecompositionFactory_${ops}.chol(structure.rowNum, true).apply { decompose(origin.copy()) } - - cholesky.getT(null).wrapMatrix() + LFeature - } - } - - LupDecompositionFeature::class -> object : LupDecompositionFeature<${type}> { - private val lup by lazy { - DecompositionFactory_${ops}.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } - } - - override val l: Matrix<${type}> by lazy { - lup.getLower(null).wrapMatrix() + LFeature - } - - override val u: Matrix<${type}> by lazy { - lup.getUpper(null).wrapMatrix() + UFeature - } - - override val p: Matrix<${type}> by lazy { lup.getRowPivot(null).wrapMatrix() } - }""" else """ QRDecompositionFeature::class -> object : QRDecompositionFeature<$type> { - private val qr by lazy { - DecompositionFactory_${ops}.qr(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val q: Matrix<${type}> by lazy { - qr.getQ(null, false).wrapMatrix() + OrthogonalFeature - } - - override val r: Matrix<${type}> by lazy { qr.getR(null, false).wrapMatrix() + UFeature } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature<${type}> { - override val l: Matrix<${type}> by lazy { - val cholesky = - DecompositionFactory_${ops}.cholesky().apply { decompose(origin.copy()) } - - (cholesky.getT(null) as ${ejmlMatrixParentTypeMatrix}).wrapMatrix() + LFeature - } - } - - LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : - LUDecompositionFeature<${type}>, DeterminantFeature<${type}>, InverseMatrixFeature<${type}> { - private val lu by lazy { - DecompositionFactory_${ops}.lu(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val l: Matrix<${type}> by lazy { - lu.getLower(null).wrapMatrix() + LFeature - } - - override val u: Matrix<${type}> by lazy { - lu.getUpper(null).wrapMatrix() + UFeature - } - - override val inverse: Matrix<${type}> by lazy { - var a = origin - val inverse = ${ejmlMatrixDenseType}(1, 1) - val solver = LinearSolverFactory_${ops}.lu(FillReducing.NONE) - if (solver.modifiesA()) a = a.copy() - val i = CommonOps_${denseOps}.identity(a.numRows) - solver.solve(i, inverse) - inverse.wrapMatrix() - } - - override val determinant: $type by lazy { elementAlgebra.number(lu.computeDeterminant().real) } - }""" - } - - else -> null - }?.let(type::cast) - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix<${type}>, b: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> { - val res = ${ejmlMatrixType}(1, 1) - CommonOps_${ops}.solve(${ejmlMatrixType}(a.toEjml().origin), ${ejmlMatrixType}(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix<${type}>, b: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> { - val res = ${ejmlMatrixType}(1, 1) - CommonOps_${ops}.solve(${ejmlMatrixType}(a.toEjml().origin), ${ejmlMatrixType}(b.toEjml().origin), res) - return Ejml${type}Vector(res) - } -}""" - appendLine(text) - appendLine() -} - - -/** - * Generates routine EJML classes. - */ -fun ejmlCodegen(outputFile: String): Unit = File(outputFile).run { - parentFile.mkdirs() - - writer().use { - it.appendLine("/*") - it.appendLine(" * Copyright 2018-2021 KMath contributors.") - it.appendLine(" * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.") - it.appendLine(" */") - it.appendLine() - it.appendLine("/* This file is generated with buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt */") - it.appendLine() - it.appendLine("package space.kscience.kmath.ejml") - it.appendLine() - it.appendLine("""import org.ejml.data.* -import org.ejml.dense.row.CommonOps_DDRM -import org.ejml.dense.row.CommonOps_FDRM -import org.ejml.dense.row.factory.DecompositionFactory_DDRM -import org.ejml.dense.row.factory.DecompositionFactory_FDRM -import org.ejml.sparse.FillReducing -import org.ejml.sparse.csc.CommonOps_DSCC -import org.ejml.sparse.csc.CommonOps_FSCC -import org.ejml.sparse.csc.factory.DecompositionFactory_DSCC -import org.ejml.sparse.csc.factory.DecompositionFactory_FSCC -import org.ejml.sparse.csc.factory.LinearSolverFactory_DSCC -import org.ejml.sparse.csc.factory.LinearSolverFactory_FSCC -import space.kscience.kmath.linear.* -import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.StructureFeature -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.FloatField -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.FloatBuffer -import kotlin.reflect.KClass -import kotlin.reflect.cast""") - it.appendLine() - it.appendEjmlVector("Double", "DMatrix") - it.appendEjmlVector("Float", "FMatrix") - it.appendEjmlMatrix("Double", "DMatrix") - it.appendEjmlMatrix("Float", "FMatrix") - it.appendEjmlLinearSpace("Double", "DoubleField", "DMatrix", "DMatrixRMaj", "DMatrixRMaj", "DDRM", "DDRM", true) - it.appendEjmlLinearSpace("Float", "FloatField", "FMatrix", "FMatrixRMaj", "FMatrixRMaj", "FDRM", "FDRM", true) - - it.appendEjmlLinearSpace( - type = "Double", - kmathAlgebra = "DoubleField", - ejmlMatrixParentTypeMatrix = "DMatrix", - ejmlMatrixType = "DMatrixSparseCSC", - ejmlMatrixDenseType = "DMatrixRMaj", - ops = "DSCC", - denseOps = "DDRM", - isDense = false, - ) - - it.appendEjmlLinearSpace( - type = "Float", - kmathAlgebra = "FloatField", - ejmlMatrixParentTypeMatrix = "FMatrix", - ejmlMatrixType = "FMatrixSparseCSC", - ejmlMatrixDenseType = "FMatrixRMaj", - ops = "FSCC", - denseOps = "FDRM", - isDense = false, - ) - } -} diff --git a/doc/algebra.md b/doc/algebra.md new file mode 100644 index 000000000..015f4fc82 --- /dev/null +++ b/doc/algebra.md @@ -0,0 +1,111 @@ +# Algebra and algebra elements + +The mathematical operations in `kmath` are generally separated from mathematical objects. +This means that in order to perform an operation, say `+`, one needs two objects of a type `T` and +and algebra context which defines appropriate operation, say `Space`. Next one needs to run actual operation +in the context: + +```kotlin +val a: T +val b: T +val space: Space + +val c = space.run{a + b} +``` + +From the first glance, this distinction seems to be a needless complication, but in fact one needs +to remember that in mathematics, one could define different operations on the same objects. For example, +one could use different types of geometry for vectors. + +## Algebra hierarchy + +Mathematical contexts have the following hierarchy: + +**Space** <- **Ring** <- **Field** + +All classes follow abstract mathematical constructs. +[Space](http://mathworld.wolfram.com/Space.html) defines `zero` element, addition operation and multiplication by constant, +[Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and unit `one` element, +[Field](http://mathworld.wolfram.com/Field.html) adds division operation. + +Typical case of `Field` is the `RealField` which works on doubles. And typical case of `Space` is a `VectorSpace`. + +In some cases algebra context could hold additional operation like `exp` or `sin`, in this case it inherits appropriate +interface. Also a context could have an operation which produces an element outside of its context. For example +`Matrix` `dot` operation produces a matrix with new dimensions which can be incompatible with initial matrix in +terms of linear operations. + +## Algebra element + +In order to achieve more familiar behavior (where you apply operations directly to mathematical objects), without involving contexts +`kmath` introduces 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 to perform direct operations on `Complex` +numbers without explicit involving the context like: + +```kotlin + val c1 = Complex(1.0, 1.0) + val c2 = Complex(1.0, -1.0) + val c3 = c1 + c2 + 3.0.toComplex() + //or with field notation: + val c4 = ComplexField.run{c1 + i - 2.0} +``` + +Both notations have their pros and cons. + +The hierarchy for algebra elements follows the hierarchy for the corresponding algebra. + +**MathElement** <- **SpaceElement** <- **RingElement** <- **FieldElement** + +**MathElement** is the generic common ancestor of the class with context. + +One important distinction between algebra elements and algebra contexts is that algebra element has three type parameters: + +1. The type of elements, field operates on. +2. The self-type of the element returned from operation (must be algebra element). +3. The type of the algebra over first type-parameter. + +The middle type is needed in case algebra members do not store context. For example, it is not possible to add +a context to regular `Double`. The element performs automatic conversions from context types and back. +One should used context operations in all important places. The performance of element operations is not guaranteed. + +## Spaces and fields + +An obvious first choice of mathematical objects to implement in a context-oriented style are algebraic elements like spaces, +rings and fields. Those are located in the `scientifik.kmath.operations.Algebra.kt` file. Alongside common contexts, the file includes definitions for algebra elements like `FieldElement`. A `FieldElement` object +stores a reference to the `Field` which contains additive and multiplicative operations, meaning +it has one fixed context attached and does not require explicit external context. So those `MathElements` can be operated without context: + +```kotlin +val c1 = Complex(1.0, 2.0) +val c2 = ComplexField.i +val c3 = c1 + c2 +``` + +`ComplexField` also features special operations to mix complex and real numbers, for example: + +```kotlin +val c1 = Complex(1.0, 2.0) +val c2 = ComplexField.run{ c1 - 1.0} // Returns: [re:0.0, im: 2.0] +val c3 = ComplexField.run{ c1 - i*2.0} +``` + +**Note**: In theory it is possible to add behaviors directly to the context, but currently kotlin syntax 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 elements like so: + +```kotlin +val element = NDElement.complex(shape = intArrayOf(2,2)){ index: IntArray -> + Complex(index[0].toDouble() - index[1].toDouble(), index[0].toDouble() + index[1].toDouble()) +} +``` + +The `element` in this example is a member of the `Field` of 2-d structures, each element of which is a member of its own +`ComplexField`. The important thing is 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 +`MemorySpec`. diff --git a/docs/buffers.md b/doc/buffers.md similarity index 58% rename from docs/buffers.md rename to doc/buffers.md index e7573497e..b0b7489b3 100644 --- a/docs/buffers.md +++ b/doc/buffers.md @@ -1,20 +1,15 @@ # 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 `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 \ No newline at end of file diff --git a/doc/contexts.md b/doc/contexts.md new file mode 100644 index 000000000..58b198046 --- /dev/null +++ b/doc/contexts.md @@ -0,0 +1,73 @@ +# Context-oriented mathematics + +## 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. + +## 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: + +```kotlin +data class Complex(val re: Double, val im: Double) +``` + +And then to define a separate class or singleton, representing an operation on those complex numbers: + +```kotlin +object ComplexOperations { + operator fun Complex.plus(other: Complex) = Complex(re + other.re, im + other.im) + operator fun Complex.minus(other: Complex) = Complex(re - other.re, im - other.im) +} +``` + +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: + +```kotlin +with(ComplexOperations) { c1 + c2 - c3 } +``` + +Kotlin also allows the creation of functions with receivers: + +```kotlin +fun ComplexOperations.doSomethingWithComplex(c1: Complex, c2: Complex, c3: Complex) = c1 + c2 - c3 + +ComplexOperations.doComethingWithComplex(c1, c2, c3) +``` + +In fact, whole parts of a program may be run within a mathematical context or even multiple nested contexts. + +In KMath, contexts are not only responsible for operations, but also for raw object creation and advanced features. + +## Other possibilities + +### 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 +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. + +### 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: + +``` +import context.complex.op1 +import context.quaternion.op2 +``` diff --git a/doc/expressions.md b/doc/expressions.md new file mode 100644 index 000000000..1e05e5340 --- /dev/null +++ b/doc/expressions.md @@ -0,0 +1,26 @@ +# 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. + +The potential use-cases for it (so far) are following: + +* 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 + +* 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. + +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` +from commons-math. **TODO: add example** diff --git a/doc/features.md b/doc/features.md new file mode 100644 index 000000000..e6a820c1e --- /dev/null +++ b/doc/features.md @@ -0,0 +1,17 @@ +# 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 + +* Koma integration + diff --git a/docs/histograms.md b/doc/histograms.md similarity index 100% rename from docs/histograms.md rename to doc/histograms.md diff --git a/doc/linear.md b/doc/linear.md new file mode 100644 index 000000000..bbcc435ba --- /dev/null +++ b/doc/linear.md @@ -0,0 +1,19 @@ +## 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. + +Two major contexts used for linear algebra and hyper-geometry: + +* `VectorSpace` forms a mathematical space on top of array-like structure (`Buffer` and its typealias `Point` used for geometry). + +* `MatrixContext` forms a space-like context for 2d-structures. It does not store matrix size and therefore does not implement +`Space` interface (it is not possible to create zero element without knowing the matrix size). + +## Vector spaces + + +## Matrix operations + +## Back-end overview \ No newline at end of file diff --git a/docs/nd-structure.md b/doc/nd-structure.md similarity index 81% rename from docs/nd-structure.md rename to doc/nd-structure.md index 3e9203ec0..cf13c6a29 100644 --- a/docs/nd-structure.md +++ b/doc/nd-structure.md @@ -1,4 +1,4 @@ -# ND-structure generation and operations +# Nd-structure generation and operations **TODO** @@ -10,17 +10,17 @@ structures. In `kmath` performance depends on which particular context was used 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. + val autoField = NDField.auto(RealField, dim, dim) + // 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) + val genericField = NDField.buffered(RealField, 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 -To test performance we will take 2d-structures with `dim = 1000` and add a structure filled with `1.0` +In order 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 specifying type -from the beginning. Everyone does 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 to specify type +from the beginning. Everyone do 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. To get the full result +The result will be calculated almost immediately but the result will be empty. In order 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 } } ``` -is the slowest one, because it requires boxing and unboxing the `double` on each operation. It takes about +obviously is the slowest one, because it requires to box and unbox 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,14 +115,12 @@ 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 different case, because numpy overrides `+=` with in-place operations. In-place operations are +but it would be differenc 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/algebra.md b/docs/algebra.md deleted file mode 100644 index 20158a125..000000000 --- a/docs/algebra.md +++ /dev/null @@ -1,86 +0,0 @@ -# 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 `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 group: Group = ... - -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 -geometry for vectors. - -## Algebraic Structures - -Primary mathematical contexts have the following hierarchy: - -`Field <: Ring <: Group <: Algebra` - -These interfaces follow real algebraic structures: - -- [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 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 introduces contexts for builtin algebraic structures: - -```kotlin -import space.kscience.kmath.operations.* - -val c1 = Complex(1.0, 2.0) -val c2 = ComplexField.i - -val c3 = c1 + c2 -// or -val c3 = ComplexField { c1 + c2 } -``` - -Also, `ComplexField` features special operations to mix complex and real numbers, for example: - -```kotlin -import space.kscience.kmath.operations.* - -val c1 = Complex(1.0, 2.0) -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 -[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 -elements like so: - -```kotlin -val element = NDElement.complex(shape = intArrayOf(2, 2)) { index: IntArray -> - Complex(index[0].toDouble() - index[1].toDouble(), index[0].toDouble() + index[1].toDouble()) -} -``` - -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. - -**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/codestyle.md b/docs/codestyle.md index 73ba5f754..53789f7b2 100644 --- a/docs/codestyle.md +++ b/docs/codestyle.md @@ -1,27 +1,22 @@ -# Coding Conventions +# Local coding conventions -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. +Kmath and other `scientifik` projects use general [kotlin code conventions](https://kotlinlang.org/docs/reference/coding-conventions.html), but with a number of small changes and clarifications. -## Utility Class Naming +## Utility class names +File name 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 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 clearly visually separate those files. This convention could be changed in future in a non-breaking way. -## Private Variable Naming +## Private variable names +Private variable names could start with underscore `_` in case 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. +Code convention do not permit underscores in names, but is is sometimes useful to "underscore" the fact that public and private versions define the same entity. It is allowed only for private variables. This convention could be changed in future in a non-breaking way. -## Functions and Properties One-liners +## Functions and properties one-liners +Use one-liners when they occupy single code window line both for functions and properties with getters like `val b: String get() = "fff"`. The same should be done with multiline expressions when they could be cleanly separated. -Use one-liners when they occupy single code window line both for functions and properties with getters like -`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 not general consensus whenever use `fun a() = {}` or `fun a(){return}`. Yet from reader perspective one-lines seem to better show that the property or function is easily calculated. \ No newline at end of file diff --git a/docs/contexts.md b/docs/contexts.md deleted file mode 100644 index c26333860..000000000 --- a/docs/contexts.md +++ /dev/null @@ -1,73 +0,0 @@ -# Context-oriented mathematics - -## 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. - -## 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 representing some entity without any operations, ex. a complex number: - -```kotlin -data class Complex(val re: Double, val im: Double) -``` - -And then to define a separate class or singleton, representing an operation on those complex numbers: - -```kotlin -object ComplexOperations { - operator fun Complex.plus(other: Complex) = Complex(re + other.re, im + other.im) - operator fun Complex.minus(other: Complex) = Complex(re - other.re, im - other.im) -} -``` - -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 } -``` - -Kotlin also allows the creation of functions with receivers: - -```kotlin -fun ComplexOperations.doSomethingWithComplex(c1: Complex, c2: Complex, c3: Complex) = c1 + c2 - c3 - -ComplexOperations.doComethingWithComplex(c1, c2, c3) -``` - -In fact, whole parts of a program may be run within a mathematical context or even multiple nested contexts. - -In KMath, contexts are not only responsible for operations, but also for raw object creation and advanced features. - -## Other possibilities - -### 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 -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. - -### 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 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 -import context.quaternion.op2 -``` diff --git a/docs/expressions.md b/docs/expressions.md deleted file mode 100644 index e6250110c..000000000 --- a/docs/expressions.md +++ /dev/null @@ -1,21 +0,0 @@ -# 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); -* 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`. - -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 using full power of `DerivativeStructure` -from commons-math. **TODO: add example** diff --git a/docs/images/KM.svg b/docs/images/KM.svg deleted file mode 100644 index f5ec452c7..000000000 --- a/docs/images/KM.svg +++ /dev/null @@ -1,67 +0,0 @@ - - - -image/svg+xml - - - \ No newline at end of file diff --git a/docs/images/KM_mono.svg b/docs/images/KM_mono.svg deleted file mode 100644 index e583324d7..000000000 --- a/docs/images/KM_mono.svg +++ /dev/null @@ -1,62 +0,0 @@ - - - -image/svg+xml - - \ No newline at end of file diff --git a/docs/images/KMath.svg b/docs/images/KMath.svg deleted file mode 100644 index e99464a17..000000000 --- a/docs/images/KMath.svg +++ /dev/null @@ -1,101 +0,0 @@ - - - -image/svg+xml - - - - - \ No newline at end of file diff --git a/docs/images/KMath_mono.svg b/docs/images/KMath_mono.svg deleted file mode 100644 index 3ef61bbf1..000000000 --- a/docs/images/KMath_mono.svg +++ /dev/null @@ -1,397 +0,0 @@ - - - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/linear.md b/docs/linear.md deleted file mode 100644 index 2a05499ef..000000000 --- a/docs/linear.md +++ /dev/null @@ -1,31 +0,0 @@ -## Basic linear algebra layout - -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. - -The main context for linear algebra over matrices and vectors is `LinearSpace`, which defines addition and dot products of matrices and vectors: - -```kotlin -import space.kscience.kmath.linear.* - -LinearSpace.Companion.real { - val vec = buildVector(10) { i -> i.toDouble() } - val mat = buildMatrix(10, 10) { i, j -> i.toDouble() + j } - - // Addition - vec + vec - mat + mat - - // Multiplication by scalar - vec * 2.0 - mat * 2.0 - - // Dot product - mat dot vec - mat dot mat -} -``` - -## Backends overview - -### EJML -### Commons Math diff --git a/docs/readme.md b/docs/readme.md deleted file mode 100644 index 2953b7113..000000000 --- a/docs/readme.md +++ /dev/null @@ -1,14 +0,0 @@ -# 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/ARTIFACT-TEMPLATE.md b/docs/templates/ARTIFACT-TEMPLATE.md deleted file mode 100644 index 1bac2a8ff..000000000 --- a/docs/templates/ARTIFACT-TEMPLATE.md +++ /dev/null @@ -1,26 +0,0 @@ -## Artifact: - -The Maven coordinates of this project are `${group}:${name}:${version}`. - -**Gradle:** -```gradle -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation '${group}:${name}:${version}' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("${group}:${name}:${version}") -} -``` \ No newline at end of file diff --git a/docs/templates/README-TEMPLATE.md b/docs/templates/README-TEMPLATE.md deleted file mode 100644 index e75d4c5ed..000000000 --- a/docs/templates/README-TEMPLATE.md +++ /dev/null @@ -1,134 +0,0 @@ -[![JetBrains Research](https://jb.gg/badges/research.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub) -[![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/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. - -[Documentation site (**WIP**)](https://mipt-npm.github.io/kmath/) - -## Publications and talks - -* [A conceptual article about context-oriented design](https://proandroiddev.com/an-introduction-context-oriented-programming-in-kotlin-2e79d316b0a2) -* [Another article about context-oriented design](https://proandroiddev.com/diving-deeper-into-context-oriented-programming-in-kotlin-3ecb4ec38814) -* [ACAT 2019 conference paper](https://aip.scitation.org/doi/abs/10.1063/1.5130103) - -# Goal - -* 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 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. - -## 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 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. -* **STABLE**. The API stabilized. Breaking changes are allowed only in major releases. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -## Modules - -$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 -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. - -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 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: - -```kotlin -repositories { - maven("https://repo.kotlin.link") -} - -dependencies { - api("${group}:kmath-core:$version") - // api("${group}:kmath-core-jvm:$version") for jvm-specific version -} -``` - -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 -[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 4cc6fecc0..2fab47ac0 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -1,68 +1,63 @@ +import org.jetbrains.kotlin.allopen.gradle.AllOpenExtension +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + plugins { + java kotlin("jvm") + kotlin("plugin.allopen") version "1.3.71" + id("kotlinx.benchmark") version "0.2.0-dev-7" +} + +configure { + annotation("org.openjdk.jmh.annotations.State") } repositories { + maven("http://dl.bintray.com/kyonifer/maven") + maven("https://dl.bintray.com/mipt-npm/scientifik") + maven("https://dl.bintray.com/mipt-npm/dev") mavenCentral() - maven("https://repo.kotlin.link") - maven("https://clojars.org/repo") - maven("https://jitpack.io") - maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-js-wrappers") - maven("http://logicrunch.research.it.uu.se/maven") { - isAllowInsecureProtocol = true - } +} + +sourceSets { + register("benchmarks") } dependencies { - implementation(project(":kmath-ast")) - implementation(project(":kmath-kotlingrad")) implementation(project(":kmath-core")) implementation(project(":kmath-coroutines")) implementation(project(":kmath-commons")) - implementation(project(":kmath-complex")) - implementation(project(":kmath-stat")) + implementation(project(":kmath-prob")) + implementation(project(":kmath-koma")) implementation(project(":kmath-viktor")) implementation(project(":kmath-dimensions")) - 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") - -// uncomment if your system supports AVX2 -// val os = System.getProperty("os.name") -// -// if (System.getProperty("os.arch") in arrayOf("x86_64", "amd64")) when { -// os.startsWith("Windows") -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:windows-x86_64-avx2") -// os == "Linux" -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:linux-x86_64-avx2") -// os == "Mac OS X" -> implementation("org.nd4j:nd4j-native:1.0.0-beta7:macosx-x86_64-avx2") -// } else - implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7") - - implementation("org.slf4j:slf4j-simple:1.7.31") - // plotting - implementation("space.kscience:plotlykt-server:0.4.2") - //jafama - implementation(project(":kmath-jafama")) + implementation("com.kyonifer:koma-core-ejml:0.12") + implementation("org.jetbrains.kotlinx:kotlinx-io-jvm:0.2.0-npm-dev-6") + implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-7") + "benchmarksCompile"(sourceSets.main.get().compileClasspath) } -kotlin.sourceSets.all { - with(languageSettings) { - useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts") - useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes") - useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") +// Configure benchmark +benchmark { + // Setup configurations + targets { + // This one matches sourceSet name above + register("benchmarks") + } + + configurations { + register("fast") { + warmups = 5 // number of warmup iterations + iterations = 3 // number of iterations + iterationTime = 500 // time in seconds per iteration + iterationTimeUnit = "ms" // time unity for iterationTime, default is seconds + } } } -tasks.withType { - kotlinOptions{ - jvmTarget = "11" - freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn" - } -} -readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL -} +tasks.withType { + kotlinOptions { + jvmTarget = Scientifik.JVM_TARGET.toString() + } +} \ No newline at end of file diff --git a/examples/src/benchmarks/kotlin/scientifik/kmath/structures/ArrayBenchmark.kt b/examples/src/benchmarks/kotlin/scientifik/kmath/structures/ArrayBenchmark.kt new file mode 100644 index 000000000..d605e1b9c --- /dev/null +++ b/examples/src/benchmarks/kotlin/scientifik/kmath/structures/ArrayBenchmark.kt @@ -0,0 +1,48 @@ +package scientifik.kmath.structures + +import org.openjdk.jmh.annotations.Benchmark +import org.openjdk.jmh.annotations.Scope +import org.openjdk.jmh.annotations.State +import java.nio.IntBuffer + + +@State(Scope.Benchmark) +class ArrayBenchmark { + + @Benchmark + fun benchmarkArrayRead() { + var res = 0 + for (i in 1..size) { + res += array[size - i] + } + } + + @Benchmark + fun benchmarkBufferRead() { + var res = 0 + for (i in 1..size) { + res += arrayBuffer.get(size - i) + } + } + + @Benchmark + fun nativeBufferRead() { + var res = 0 + for (i in 1..size) { + res += nativeBuffer.get(size - i) + } + } + + companion object { + val size = 1000 + + val array = IntArray(size) { it } + val arrayBuffer = IntBuffer.wrap(array) + val nativeBuffer = IntBuffer.allocate(size).also { + for (i in 0 until size) { + it.put(i, i) + } + + } + } +} \ No newline at end of file diff --git a/examples/src/benchmarks/kotlin/scientifik/kmath/structures/BufferBenchmark.kt b/examples/src/benchmarks/kotlin/scientifik/kmath/structures/BufferBenchmark.kt new file mode 100644 index 000000000..9676b5e4a --- /dev/null +++ b/examples/src/benchmarks/kotlin/scientifik/kmath/structures/BufferBenchmark.kt @@ -0,0 +1,33 @@ +package scientifik.kmath.structures + +import org.openjdk.jmh.annotations.Benchmark +import org.openjdk.jmh.annotations.Scope +import org.openjdk.jmh.annotations.State +import scientifik.kmath.operations.Complex +import scientifik.kmath.operations.complex + +@State(Scope.Benchmark) +class BufferBenchmark { + + @Benchmark + fun genericDoubleBufferReadWrite() { + val buffer = DoubleBuffer(size){it.toDouble()} + + (0 until size).forEach { + buffer[it] + } + } + + @Benchmark + fun complexBufferReadWrite() { + val buffer = MutableBuffer.complex(size / 2){Complex(it.toDouble(), -it.toDouble())} + + (0 until size / 2).forEach { + buffer[it] + } + } + + companion object { + const val size = 100 + } +} \ No newline at end of file diff --git a/examples/src/benchmarks/kotlin/scientifik/kmath/structures/NDFieldBenchmark.kt b/examples/src/benchmarks/kotlin/scientifik/kmath/structures/NDFieldBenchmark.kt new file mode 100644 index 000000000..ae27620f7 --- /dev/null +++ b/examples/src/benchmarks/kotlin/scientifik/kmath/structures/NDFieldBenchmark.kt @@ -0,0 +1,58 @@ +package scientifik.kmath.structures + +import org.openjdk.jmh.annotations.Benchmark +import org.openjdk.jmh.annotations.Scope +import org.openjdk.jmh.annotations.State +import scientifik.kmath.operations.RealField + +@State(Scope.Benchmark) +class NDFieldBenchmark { + + @Benchmark + fun autoFieldAdd() { + bufferedField.run { + var res: NDBuffer = one + repeat(n) { + res += one + } + } + } + + @Benchmark + fun autoElementAdd() { + var res = genericField.one + repeat(n) { + res += 1.0 + } + } + + @Benchmark + fun specializedFieldAdd() { + specializedField.run { + var res: NDBuffer = one + repeat(n) { + res += 1.0 + } + } + } + + + @Benchmark + fun boxingFieldAdd() { + genericField.run { + var res: NDBuffer = one + repeat(n) { + res += one + } + } + } + + companion object { + val dim = 1000 + val n = 100 + + val bufferedField = NDField.auto(RealField, dim, dim) + val specializedField = NDField.real(dim, dim) + val genericField = NDField.boxing(RealField, dim, dim) + } +} \ No newline at end of file diff --git a/examples/src/benchmarks/kotlin/scientifik/kmath/structures/ViktorBenchmark.kt b/examples/src/benchmarks/kotlin/scientifik/kmath/structures/ViktorBenchmark.kt new file mode 100644 index 000000000..be4115d81 --- /dev/null +++ b/examples/src/benchmarks/kotlin/scientifik/kmath/structures/ViktorBenchmark.kt @@ -0,0 +1,71 @@ +package scientifik.kmath.structures + +import org.jetbrains.bio.viktor.F64Array +import org.openjdk.jmh.annotations.Benchmark +import org.openjdk.jmh.annotations.Scope +import org.openjdk.jmh.annotations.State +import scientifik.kmath.operations.RealField +import scientifik.kmath.viktor.ViktorNDField + + +@State(Scope.Benchmark) +class ViktorBenchmark { + final val dim = 1000 + final val n = 100 + + // automatically build context most suited for given type. + final val autoField = NDField.auto(RealField, dim, dim) + final val realField = NDField.real(dim, dim) + + final val viktorField = ViktorNDField(intArrayOf(dim, dim)) + + @Benchmark + fun `Automatic field addition`() { + autoField.run { + var res = one + repeat(n) { + res += 1.0 + } + } + } + + @Benchmark + fun `Viktor field addition`() { + viktorField.run { + var res = one + repeat(n) { + res += one + } + } + } + + @Benchmark + fun `Raw Viktor`() { + val one = F64Array.full(init = 1.0, shape = *intArrayOf(dim, dim)) + var res = one + repeat(n) { + res = res + one + } + } + + @Benchmark + fun `Real field log`() { + realField.run { + val fortyTwo = produce { 42.0 } + var res = one + + repeat(n) { + res = ln(fortyTwo) + } + } + } + + @Benchmark + fun `Raw Viktor log`() { + val fortyTwo = F64Array.full(dim, dim, init = 42.0) + var res: F64Array + repeat(n) { + res = fortyTwo.log() + } + } +} \ No newline at end of file diff --git a/examples/src/benchmarks/kotlin/scientifik/kmath/utils/utils.kt b/examples/src/benchmarks/kotlin/scientifik/kmath/utils/utils.kt new file mode 100644 index 000000000..6ec9e9c17 --- /dev/null +++ b/examples/src/benchmarks/kotlin/scientifik/kmath/utils/utils.kt @@ -0,0 +1,8 @@ +package scientifik.kmath.utils + +import kotlin.system.measureTimeMillis + +internal inline fun measureAndPrint(title: String, block: () -> Unit) { + val time = measureTimeMillis(block) + println("$title completed in $time millis") +} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt b/examples/src/main/kotlin/scientifik/kmath/commons/prob/DistributionBenchmark.kt similarity index 53% rename from examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt rename to examples/src/main/kotlin/scientifik/kmath/commons/prob/DistributionBenchmark.kt index 732c9a8e3..b060cddb6 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt +++ b/examples/src/main/kotlin/scientifik/kmath/commons/prob/DistributionBenchmark.kt @@ -1,29 +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 file. - */ - -package space.kscience.kmath.stat +package scientifik.kmath.commons.prob import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.runBlocking -import org.apache.commons.rng.sampling.distribution.BoxMullerNormalizedGaussianSampler +import org.apache.commons.rng.sampling.distribution.ZigguratNormalizedGaussianSampler import org.apache.commons.rng.simple.RandomSource -import space.kscience.kmath.samplers.GaussianSampler +import scientifik.kmath.chains.BlockingRealChain +import scientifik.kmath.prob.* import java.time.Duration import java.time.Instant -import org.apache.commons.rng.sampling.distribution.GaussianSampler as CMGaussianSampler -private suspend fun runKMathChained(): Duration { + +private suspend fun runChain(): Duration { val generator = RandomGenerator.fromSource(RandomSource.MT, 123L) - val normal = GaussianSampler(7.0, 2.0) - val chain = normal.sample(generator) + + val normal = Distribution.normal(NormalSamplerMethod.Ziggurat) + val chain = normal.sample(generator) as BlockingRealChain + val startTime = Instant.now() var sum = 0.0 - repeat(10000001) { counter -> - sum += chain.next() + + sum += chain.nextDouble() if (counter % 100000 == 0) { val duration = Duration.between(startTime, Instant.now()) @@ -31,23 +29,17 @@ private suspend fun runKMathChained(): Duration { println("Chain sampler completed $counter elements in $duration: $meanValue") } } - return Duration.between(startTime, Instant.now()) } -private fun runApacheDirect(): Duration { - val rng = RandomSource.create(RandomSource.MT, 123L) - - val sampler = CMGaussianSampler.of( - BoxMullerNormalizedGaussianSampler.of(rng), - 7.0, - 2.0 - ) - +private fun runDirect(): Duration { + val provider = RandomSource.create(RandomSource.MT, 123L) + val sampler = ZigguratNormalizedGaussianSampler(provider) val startTime = Instant.now() - var sum = 0.0 + var sum = 0.0 repeat(10000001) { counter -> + sum += sampler.sample() if (counter % 100000 == 0) { @@ -56,16 +48,24 @@ private fun runApacheDirect(): Duration { println("Direct sampler completed $counter elements in $duration: $meanValue") } } - return Duration.between(startTime, Instant.now()) } /** * Comparing chain sampling performance with direct sampling performance */ -fun main(): Unit = runBlocking(Dispatchers.Default) { - val directJob = async { runApacheDirect() } - val chainJob = async { runKMathChained() } - println("KMath Chained: ${chainJob.await()}") - println("Apache Direct: ${directJob.await()}") -} +fun main() { + runBlocking(Dispatchers.Default) { + val chainJob = async { + runChain() + } + + val directJob = async { + runDirect() + } + + println("Chain: ${chainJob.await()}") + println("Direct: ${directJob.await()}") + } + +} \ No newline at end of file diff --git a/examples/src/main/kotlin/scientifik/kmath/commons/prob/DistributionDemo.kt b/examples/src/main/kotlin/scientifik/kmath/commons/prob/DistributionDemo.kt new file mode 100644 index 000000000..e059415dc --- /dev/null +++ b/examples/src/main/kotlin/scientifik/kmath/commons/prob/DistributionDemo.kt @@ -0,0 +1,32 @@ +package scientifik.kmath.commons.prob + +import kotlinx.coroutines.runBlocking +import scientifik.kmath.chains.Chain +import scientifik.kmath.chains.collectWithState +import scientifik.kmath.prob.Distribution +import scientifik.kmath.prob.RandomGenerator +import scientifik.kmath.prob.normal + +data class AveragingChainState(var num: Int = 0, var value: Double = 0.0) + +fun Chain.mean(): Chain = collectWithState(AveragingChainState(), { it.copy() }) { chain -> + val next = chain.next() + num++ + value += next + return@collectWithState value / num +} + + +fun main() { + val normal = Distribution.normal() + val chain = normal.sample(RandomGenerator.default).mean() + + runBlocking { + repeat(10001) { counter -> + val mean = chain.next() + if (counter % 1000 == 0) { + println("[$counter] Average value is $mean") + } + } + } +} \ No newline at end of file diff --git a/examples/src/main/kotlin/scientifik/kmath/linear/LinearAlgebraBenchmark.kt b/examples/src/main/kotlin/scientifik/kmath/linear/LinearAlgebraBenchmark.kt new file mode 100644 index 000000000..960f03de3 --- /dev/null +++ b/examples/src/main/kotlin/scientifik/kmath/linear/LinearAlgebraBenchmark.kt @@ -0,0 +1,65 @@ +package scientifik.kmath.linear + +import koma.matrix.ejml.EJMLMatrixFactory +import scientifik.kmath.commons.linear.CMMatrixContext +import scientifik.kmath.commons.linear.inverse +import scientifik.kmath.commons.linear.toCM +import scientifik.kmath.operations.RealField +import scientifik.kmath.structures.Matrix +import kotlin.contracts.ExperimentalContracts +import kotlin.random.Random +import kotlin.system.measureTimeMillis + +@ExperimentalContracts +fun main() { + val random = Random(1224) + val dim = 100 + //creating invertible matrix + val u = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } + val l = Matrix.real(dim, dim) { i, j -> if (i >= j) random.nextDouble() else 0.0 } + val matrix = l dot u + + val n = 5000 // iterations + + MatrixContext.real.run { + + repeat(50) { + val res = inverse(matrix) + } + + val inverseTime = measureTimeMillis { + repeat(n) { + val res = inverse(matrix) + } + } + + println("[kmath] Inversion of $n matrices $dim x $dim finished in $inverseTime millis") + } + + //commons-math + + val commonsTime = measureTimeMillis { + CMMatrixContext.run { + val cm = matrix.toCM() //avoid overhead on conversion + repeat(n) { + val res = inverse(cm) + } + } + } + + + println("[commons-math] Inversion of $n matrices $dim x $dim finished in $commonsTime millis") + + //koma-ejml + + val komaTime = measureTimeMillis { + KomaMatrixContext(EJMLMatrixFactory(), RealField).run { + val km = matrix.toKoma() //avoid overhead on conversion + repeat(n) { + val res = inverse(km) + } + } + } + + println("[koma-ejml] Inversion of $n matrices $dim x $dim finished in $komaTime millis") +} \ No newline at end of file diff --git a/examples/src/main/kotlin/scientifik/kmath/linear/MultiplicationBenchmark.kt b/examples/src/main/kotlin/scientifik/kmath/linear/MultiplicationBenchmark.kt new file mode 100644 index 000000000..03bd0001c --- /dev/null +++ b/examples/src/main/kotlin/scientifik/kmath/linear/MultiplicationBenchmark.kt @@ -0,0 +1,49 @@ +package scientifik.kmath.linear + +import koma.matrix.ejml.EJMLMatrixFactory +import scientifik.kmath.commons.linear.CMMatrixContext +import scientifik.kmath.commons.linear.toCM +import scientifik.kmath.operations.RealField +import scientifik.kmath.structures.Matrix +import kotlin.random.Random +import kotlin.system.measureTimeMillis + +fun main() { + val random = Random(12224) + val dim = 1000 + //creating invertible matrix + val matrix1 = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } + val matrix2 = Matrix.real(dim, dim) { i, j -> if (i <= j) random.nextDouble() else 0.0 } + +// //warmup +// matrix1 dot matrix2 + + CMMatrixContext.run { + val cmMatrix1 = matrix1.toCM() + val cmMatrix2 = matrix2.toCM() + + val cmTime = measureTimeMillis { + cmMatrix1 dot cmMatrix2 + } + + println("CM implementation time: $cmTime") + } + + + KomaMatrixContext(EJMLMatrixFactory(), RealField).run { + val komaMatrix1 = matrix1.toKoma() + val komaMatrix2 = matrix2.toKoma() + + val komaTime = measureTimeMillis { + komaMatrix1 dot komaMatrix2 + } + + println("Koma-ejml implementation time: $komaTime") + } + + val genericTime = measureTimeMillis { + val res = matrix1 dot matrix2 + } + + println("Generic implementation time: $genericTime") +} \ No newline at end of file diff --git a/examples/src/main/kotlin/scientifik/kmath/operations/ComplexDemo.kt b/examples/src/main/kotlin/scientifik/kmath/operations/ComplexDemo.kt new file mode 100644 index 000000000..4841f9dd8 --- /dev/null +++ b/examples/src/main/kotlin/scientifik/kmath/operations/ComplexDemo.kt @@ -0,0 +1,21 @@ +package scientifik.kmath.operations + +import scientifik.kmath.structures.NDElement +import scientifik.kmath.structures.NDField +import scientifik.kmath.structures.complex + +fun main() { + val element = NDElement.complex(2, 2) { index: IntArray -> + Complex(index[0].toDouble() - index[1].toDouble(), index[0].toDouble() + index[1].toDouble()) + } + + + val compute = NDField.complex(8).run { + val a = produce { (it) -> i * it - it.toDouble() } + val b = 3 + val c = Complex(1.0, 1.0) + + (a pow b) + c + } + +} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt b/examples/src/main/kotlin/scientifik/kmath/structures/ComplexND.kt similarity index 55% rename from examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt rename to examples/src/main/kotlin/scientifik/kmath/structures/ComplexND.kt index 752e00bdf..cc8b68d85 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt +++ b/examples/src/main/kotlin/scientifik/kmath/structures/ComplexND.kt @@ -1,31 +1,22 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +package scientifik.kmath.structures -@file:Suppress("unused") - -package space.kscience.kmath.structures - -import space.kscience.kmath.complex.* -import space.kscience.kmath.linear.transpose -import space.kscience.kmath.nd.AlgebraND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.as2D -import space.kscience.kmath.nd.real -import space.kscience.kmath.operations.invoke +import scientifik.kmath.linear.transpose +import scientifik.kmath.operations.Complex +import scientifik.kmath.operations.ComplexField +import scientifik.kmath.operations.invoke import kotlin.system.measureTimeMillis fun main() { val dim = 1000 val n = 1000 - val realField = AlgebraND.real(dim, dim) - val complexField: ComplexFieldND = AlgebraND.complex(dim, dim) + val realField = NDField.real(dim, dim) + val complexField = NDField.complex(dim, dim) + val realTime = measureTimeMillis { - realField { - var res: StructureND = one + realField.run { + var res: NDBuffer = one repeat(n) { res += 1.0 } @@ -35,8 +26,8 @@ fun main() { println("Real addition completed in $realTime millis") val complexTime = measureTimeMillis { - complexField { - var res: StructureND = one + complexField.run { + var res = one repeat(n) { res += 1.0 } @@ -46,6 +37,7 @@ fun main() { println("Complex addition completed in $complexTime millis") } + fun complexExample() { //Create a context for 2-d structure with complex values ComplexField { @@ -54,7 +46,10 @@ fun complexExample() { val x = one * 2.5 operator fun Number.plus(other: Complex) = Complex(this.toDouble() + other.re, other.im) //a structure generator specific to this context - val matrix = produce { (k, l) -> k + l * i } + val matrix = produce { (k, l) -> + k + l * i + } + //Perform sum val sum = matrix + x + 1.0 diff --git a/examples/src/main/kotlin/scientifik/kmath/structures/NDField.kt b/examples/src/main/kotlin/scientifik/kmath/structures/NDField.kt new file mode 100644 index 000000000..cfd1206ff --- /dev/null +++ b/examples/src/main/kotlin/scientifik/kmath/structures/NDField.kt @@ -0,0 +1,71 @@ +package scientifik.kmath.structures + +import kotlinx.coroutines.GlobalScope +import scientifik.kmath.operations.RealField +import kotlin.system.measureTimeMillis + +internal inline fun measureAndPrint(title: String, block: () -> Unit) { + val time = measureTimeMillis(block) + println("$title completed in $time millis") +} + + +fun main() { + val dim = 1000 + val n = 1000 + + // automatically build context most suited for given type. + val autoField = NDField.auto(RealField, dim, dim) + // 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.boxing(RealField, dim, dim) + + measureAndPrint("Automatic field addition") { + autoField.run { + var res = one + repeat(n) { + res += 1.0 + } + } + } + + measureAndPrint("Element addition"){ + var res = genericField.one + repeat(n) { + res += 1.0 + } + } + + measureAndPrint("Specialized addition") { + specializedField.run { + var res: NDBuffer = one + repeat(n) { + res += 1.0 + } + } + } + + measureAndPrint("Lazy addition") { + val res = specializedField.one.mapAsync(GlobalScope) { + var c = 0.0 + repeat(n) { + c += 1.0 + } + c + } + + res.elements().forEach { it.second } + } + + measureAndPrint("Generic addition") { + //genericField.run(action) + genericField.run { + var res: NDBuffer = one + repeat(n) { + res += 1.0 + } + } + } + +} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt b/examples/src/main/kotlin/scientifik/kmath/structures/StructureReadBenchmark.kt similarity index 62% rename from examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt rename to examples/src/main/kotlin/scientifik/kmath/structures/StructureReadBenchmark.kt index 84dd6538c..ecfb4ab20 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt +++ b/examples/src/main/kotlin/scientifik/kmath/structures/StructureReadBenchmark.kt @@ -1,42 +1,36 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +package scientifik.kmath.structures -package space.kscience.kmath.structures - -import space.kscience.kmath.nd.BufferND -import space.kscience.kmath.nd.DefaultStrides import kotlin.system.measureTimeMillis -@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") -fun main() { +fun main(args: Array) { val n = 6000 + val array = DoubleArray(n * n) { 1.0 } val buffer = DoubleBuffer(array) val strides = DefaultStrides(intArrayOf(n, n)) - val structure = BufferND(strides, buffer) + + val structure = BufferNDStructure(strides, buffer) measureTimeMillis { - var res = 0.0 + var res: Double = 0.0 strides.indices().forEach { res = structure[it] } } // warmup val time1 = measureTimeMillis { - var res = 0.0 + var res: Double = 0.0 strides.indices().forEach { res = structure[it] } } println("Structure reading finished in $time1 millis") val time2 = measureTimeMillis { - var res = 0.0 + var res: Double = 0.0 strides.indices().forEach { res = buffer[strides.offset(it)] } } println("Buffer reading finished in $time2 millis") val time3 = measureTimeMillis { - var res = 0.0 + var res: Double = 0.0 strides.indices().forEach { res = array[strides.offset(it)] } } println("Array reading finished in $time3 millis") -} +} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt b/examples/src/main/kotlin/scientifik/kmath/structures/StructureWriteBenchmark.kt similarity index 53% rename from examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt rename to examples/src/main/kotlin/scientifik/kmath/structures/StructureWriteBenchmark.kt index 84644ddd9..2d16cc8f4 100644 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt +++ b/examples/src/main/kotlin/scientifik/kmath/structures/StructureWriteBenchmark.kt @@ -1,28 +1,29 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +package scientifik.kmath.structures -package space.kscience.kmath.structures - -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.mapToBuffer import kotlin.system.measureTimeMillis -@Suppress("UNUSED_VARIABLE") -fun main() { + +fun main(args: Array) { + val n = 6000 - val structure = StructureND.buffered(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 } + + val structure = NDStructure.build(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 } + structure.mapToBuffer { it + 1 } // warm-up - val time1 = measureTimeMillis { val res = structure.mapToBuffer { it + 1 } } + + val time1 = measureTimeMillis { + val res = structure.mapToBuffer { it + 1 } + } println("Structure mapping finished in $time1 millis") + val array = DoubleArray(n * n) { 1.0 } val time2 = measureTimeMillis { val target = DoubleArray(n * n) - val res = array.forEachIndexed { index, value -> target[index] = value + 1 } + val res = array.forEachIndexed { index, value -> + target[index] = value + 1 + } } - println("Array mapping finished in $time2 millis") val buffer = DoubleBuffer(DoubleArray(n * n) { 1.0 }) diff --git a/examples/src/main/kotlin/scientifik/kmath/structures/typeSafeDimensions.kt b/examples/src/main/kotlin/scientifik/kmath/structures/typeSafeDimensions.kt new file mode 100644 index 000000000..fdc09ed5d --- /dev/null +++ b/examples/src/main/kotlin/scientifik/kmath/structures/typeSafeDimensions.kt @@ -0,0 +1,35 @@ +package scientifik.kmath.structures + +import scientifik.kmath.dimensions.D2 +import scientifik.kmath.dimensions.D3 +import scientifik.kmath.dimensions.DMatrixContext +import scientifik.kmath.dimensions.Dimension +import scientifik.kmath.operations.RealField + +fun DMatrixContext.simple() { + val m1 = produce { i, j -> (i + j).toDouble() } + val m2 = produce { i, j -> (i + j).toDouble() } + + //Dimension-safe addition + m1.transpose() + m2 +} + + +object D5 : Dimension { + override val dim: UInt = 5u +} + +fun DMatrixContext.custom() { + val m1 = produce { i, j -> (i + j).toDouble() } + val m2 = produce { i, j -> (i - j).toDouble() } + val m3 = produce { i, j -> (i - j).toDouble() } + + (m1 dot m2) + m3 +} + +fun main() { + DMatrixContext.real.run { + simple() + custom() + } +} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt deleted file mode 100644 index 0c16d82d1..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess -import space.kscience.kmath.ast.rendering.LatexSyntaxRenderer -import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer -import space.kscience.kmath.ast.rendering.renderWithStringBuilder - -fun main() { - val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(-12)".parseMath() - val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst) - println("MathSyntax:") - println(syntax) - println() - val latex = LatexSyntaxRenderer.renderWithStringBuilder(syntax) - println("LaTeX:") - println(latex) - println() - val mathML = MathMLSyntaxRenderer.renderWithStringBuilder(syntax) - println("MathML:") - println(mathML) -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt deleted file mode 100644 index 887d76c42..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.MstField -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.interpret -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.invoke - -fun main() { - val expr = MstField { - x * 2.0 + number(2.0) / x - 16.0 - } - - repeat(10000000) { - expr.interpret(DoubleField, x to 1.0) - } -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt deleted file mode 100644 index 4e3528b3e..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.derivative -import space.kscience.kmath.expressions.invoke -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, *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 actualDerivative = "x^2-4*x-44" - .parseMath() - .toKotlingradExpression(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/ast/symjaSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt deleted file mode 100644 index 209523c89..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.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 deleted file mode 100644 index 406cbd040..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.commons.fit - -import kotlinx.html.br -import kotlinx.html.h3 -import space.kscience.kmath.commons.optimization.chiSquared -import space.kscience.kmath.commons.optimization.minimize -import space.kscience.kmath.distributions.NormalDistribution -import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.optimization.FunctionOptimization -import space.kscience.kmath.optimization.OptimizationResult -import space.kscience.kmath.real.DoubleVector -import space.kscience.kmath.real.map -import space.kscience.kmath.real.step -import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.structures.asIterable -import space.kscience.kmath.structures.toList -import space.kscience.plotly.* -import space.kscience.plotly.models.ScatterMode -import space.kscience.plotly.models.TraceValues -import kotlin.math.pow -import kotlin.math.sqrt - -// Forward declaration of symbols that will be used in expressions. -private val a by symbol -private val b by symbol -private val c by symbol - -/** - * Shortcut to use buffers in plotly - */ -operator fun TraceValues.invoke(vector: DoubleVector) { - numbers = vector.asIterable() -} - -/** - * Least squares fie with auto-differentiation. Uses `kmath-commons` and `kmath-for-real` modules. - */ -suspend fun main() { - //A generator for a normally distributed values - val generator = NormalDistribution(2.0, 7.0) - - //A chain/flow of random values with the given seed - val chain = generator.sample(RandomGenerator.default(112667)) - - - //Create a uniformly distributed x values like numpy.arrange - val x = 1.0..100.0 step 1.0 - - - //Perform an operation on each x value (much more effective, than numpy) - val y = x.map { - val value = it.pow(2) + it + 1 - value + chain.next() * sqrt(value) - } - // this will also work, but less effective: - // val y = x.pow(2)+ x + 1 + chain.nextDouble() - - // create same errors for all xs - val yErr = y.map { sqrt(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 -> - //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 - } - - //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) - - //display a page with plot and numerical results - val page = Plotly.page { - plot { - scatter { - mode = ScatterMode.markers - x(x) - y(y) - error_y { - array = yErr.toList() - } - name = "data" - } - scatter { - mode = ScatterMode.lines - x(x) - y(x.map { result.point[a]!! * it.pow(2) + result.point[b]!! * it + 1 }) - name = "fit" - } - } - br() - h3 { - +"Fit result: $result" - } - h3 { - +"Chi2/dof = ${result.value / (x.size - 3)}" - } - } - - page.makeFile() -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt deleted file mode 100644 index c77d1d70c..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.integration.gaussIntegrator -import space.kscience.kmath.integration.integrate -import space.kscience.kmath.integration.value -import space.kscience.kmath.operations.DoubleField -import kotlin.math.pow - -fun main() { - //Define a function - val function: UnivariateFunction = { x -> 3 * x.pow(2) + 2 * x + 1 } - - //get the result of the integration - val result = DoubleField.gaussIntegrator.integrate(0.0..10.0, function = function) - - //the value is nullable because in some cases the integration could not succeed - println(result.value) -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt deleted file mode 100644 index a98467ced..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.interpolation.SplineInterpolator -import space.kscience.kmath.interpolation.interpolatePolynomials -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.plotly.Plotly -import space.kscience.plotly.UnstablePlotlyAPI -import space.kscience.plotly.makeFile -import space.kscience.plotly.models.functionXY -import space.kscience.plotly.scatter -import kotlin.math.PI -import kotlin.math.sin - -@OptIn(UnstablePlotlyAPI::class) -fun main() { - val data = (0..10).map { - val x = it.toDouble() / 5 * PI - x to sin(x) - } - - val polynomial: PiecewisePolynomial = SplineInterpolator( - DoubleField, ::DoubleBuffer - ).interpolatePolynomials(data) - - val function = polynomial.asFunction(DoubleField, 0.0) - - val cmInterpolate = org.apache.commons.math3.analysis.interpolation.SplineInterpolator().interpolate( - data.map { it.first }.toDoubleArray(), - data.map { it.second }.toDoubleArray() - ) - - Plotly.plot { - scatter { - name = "interpolated" - x.numbers = data.map { it.first } - y.numbers = x.doubles.map { function(it) } - } - scatter { - name = "original" - functionXY(0.0..(2 * PI), 0.1) { sin(it) } - } - scatter { - name = "cm" - x.numbers = data.map { it.first } - y.numbers = x.doubles.map { cmInterpolate.value(it) } - } - }.makeFile() -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt deleted file mode 100644 index 76422d658..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.interpolation.SplineInterpolator -import space.kscience.kmath.interpolation.interpolatePolynomials -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.real.step -import space.kscience.kmath.structures.map -import space.kscience.plotly.Plotly -import space.kscience.plotly.UnstablePlotlyAPI -import space.kscience.plotly.makeFile -import space.kscience.plotly.models.functionXY -import space.kscience.plotly.scatter - -@OptIn(UnstablePlotlyAPI::class) -fun main() { - val function: UnivariateFunction = { x -> - if (x in 30.0..50.0) { - 1.0 - } else { - 0.0 - } - } - val xs = 0.0..100.0 step 0.5 - val ys = xs.map(function) - - val polynomial: PiecewisePolynomial = SplineInterpolator.double.interpolatePolynomials(xs, ys) - - val polyFunction = polynomial.asFunction(DoubleField, 0.0) - - Plotly.plot { - scatter { - name = "interpolated" - functionXY(25.0..55.0, 0.1) { polyFunction(it) } - } - scatter { - name = "original" - functionXY(25.0..55.0, 0.1) { function(it) } - } - }.makeFile() -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt deleted file mode 100644 index 5af867061..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.integration.gaussIntegrator -import space.kscience.kmath.integration.integrate -import space.kscience.kmath.integration.value -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.nd -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.invoke - -fun main(): Unit = DoubleField { - nd(2, 2) { - - //Produce a diagonal StructureND - fun diagonal(v: Double) = produce { (i, j) -> - if (i == j) v else 0.0 - } - - //Define a function in a nd space - val function: (Double) -> StructureND = { x: Double -> 3 * number(x).pow(2) + 2 * diagonal(x) + 1 } - - //get the result of the integration - val result = gaussIntegrator.integrate(0.0..10.0, function = function) - - //the value is nullable because in some cases the integration could not succeed - println(result.value) - } -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt deleted file mode 100644 index 10ed30728..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/jafama/JafamaDemo.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.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/linear/gradient.kt b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt deleted file mode 100644 index afc42ea26..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.linear - -import space.kscience.kmath.real.* -import space.kscience.kmath.structures.DoubleBuffer - -fun main() { - val x0 = DoubleVector(0.0, 0.0, 0.0) - val sigma = DoubleVector(1.0, 1.0, 1.0) - - val gaussian: (Point) -> Double = { x -> - require(x.size == x0.size) - kotlin.math.exp(-((x - x0) / sigma).square().sum()) - } - - fun ((Point) -> Double).grad(x: Point): Point { - require(x.size == x0.size) - return DoubleBuffer(x.size) { i -> - val h = sigma[i] / 5 - val dVector = DoubleBuffer(x.size) { if (it == i) h else 0.0 } - val f1 = this(x + dVector / 2) - val f0 = this(x - dVector / 2) - (f1 - f0) / h - } - } - - println(gaussian.grad(x0)) - -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt deleted file mode 100644 index 2039953b5..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations - -fun main() { - val res = BigIntField { number(1) * 2 } - println("bigint:$res") -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt deleted file mode 100644 index eefc6e896..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.complex.Complex -import space.kscience.kmath.complex.complex -import space.kscience.kmath.nd.AlgebraND - -fun main() { - // 2d element - val element = AlgebraND.complex(2, 2).produce { (i, j) -> - Complex(i.toDouble() - j.toDouble(), i.toDouble() + j.toDouble()) - } - println(element) - - // 1d element operation - val result = with(AlgebraND.complex(8)) { - val a = produce { (it) -> i * it - it.toDouble() } - val b = 3 - val c = Complex(1.0, 1.0) - - (a pow b) + c - } - - println(result) -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt deleted file mode 100644 index 685214c39..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.stat - -import kotlinx.coroutines.runBlocking -import space.kscience.kmath.chains.Chain -import space.kscience.kmath.chains.collectWithState -import space.kscience.kmath.distributions.NormalDistribution - -private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0) - -/** - * Averaging. - */ -private fun Chain.mean(): Chain = collectWithState(AveragingChainState(), { it.copy() }) { chain -> - val next = chain.next() - num++ - value += next - return@collectWithState value / num -} - - -fun main() { - val normal = NormalDistribution(0.0, 2.0) - val chain = normal.sample(RandomGenerator.default).mean() - - runBlocking { - repeat(10001) { counter -> - val mean = chain.next() - if (counter % 1000 == 0) { - println("[$counter] Average value is $mean") - } - } - } -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt deleted file mode 100644 index c842960be..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.GlobalScope -import org.nd4j.linalg.factory.Nd4j -import space.kscience.kmath.nd.* -import space.kscience.kmath.nd4j.Nd4jArrayField -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.viktor.ViktorNDField -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.system.measureTimeMillis - -internal inline fun measureAndPrint(title: String, block: () -> Unit) { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - val time = measureTimeMillis(block) - println("$title completed in $time millis") -} - -@OptIn(DelicateCoroutinesApi::class) -fun main() { - // initializing Nd4j - Nd4j.zeros(0) - val dim = 1000 - val n = 1000 - - // 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. - 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) - // Nd4j specialized field. - val nd4jField = Nd4jArrayField.real(dim, dim) - //viktor field - val viktorField = ViktorNDField(dim, dim) - //parallel processing based on Java Streams - val parallelField = AlgebraND.realWithStream(dim, dim) - - measureAndPrint("Boxing addition") { - boxingField { - var res: StructureND = one - repeat(n) { res += 1.0 } - } - } - - measureAndPrint("Specialized addition") { - realField { - var res: StructureND = one - repeat(n) { res += 1.0 } - } - } - - measureAndPrint("Nd4j specialized addition") { - nd4jField { - var res: StructureND = one - repeat(n) { res += 1.0 } - } - } - - measureAndPrint("Viktor addition") { - viktorField { - var res: StructureND = one - repeat(n) { res += 1.0 } - } - } - - measureAndPrint("Parallel stream addition") { - parallelField { - var res: StructureND = one - repeat(n) { res += 1.0 } - } - } - - measureAndPrint("Automatic field addition") { - autoField { - var res: StructureND = one - repeat(n) { res += 1.0 } - } - } - - measureAndPrint("Lazy addition") { - val res = realField.one.mapAsync(GlobalScope) { - var c = 0.0 - repeat(n) { - c += 1.0 - } - c - } - - res.elements().forEach { it.second } - } -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt deleted file mode 100644 index e443a588d..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.NumbersAddOperations -import java.util.* -import java.util.stream.IntStream - -/** - * A demonstration implementation of NDField over Real using Java [java.util.stream.DoubleStream] for parallel - * execution. - */ -class StreamDoubleFieldND(override val shape: IntArray) : FieldND, - NumbersAddOperations>, - ExtendedField> { - - private val strides = DefaultStrides(shape) - override val elementContext: DoubleField get() = DoubleField - override val zero: BufferND by lazy { produce { zero } } - override val one: BufferND by lazy { produce { one } } - - override fun number(value: Number): BufferND { - val d = value.toDouble() // minimize conversions - return produce { d } - } - - private val StructureND.buffer: DoubleBuffer - get() = when { - !shape.contentEquals(this@StreamDoubleFieldND.shape) -> throw ShapeMismatchException( - this@StreamDoubleFieldND.shape, - shape - ) - this is BufferND && this.strides == this@StreamDoubleFieldND.strides -> this.buffer as DoubleBuffer - else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) } - } - - override fun produce(initializer: DoubleField.(IntArray) -> Double): BufferND { - val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset -> - val index = strides.index(offset) - DoubleField.initializer(index) - }.toArray() - - return BufferND(strides, array.asBuffer()) - } - - override fun StructureND.map( - transform: DoubleField.(Double) -> Double, - ): BufferND { - val array = Arrays.stream(buffer.array).parallel().map { DoubleField.transform(it) }.toArray() - return BufferND(strides, array.asBuffer()) - } - - override fun StructureND.mapIndexed( - transform: DoubleField.(index: IntArray, Double) -> Double, - ): BufferND { - val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset -> - DoubleField.transform( - strides.index(offset), - buffer.array[offset] - ) - }.toArray() - - return BufferND(strides, array.asBuffer()) - } - - override fun combine( - a: StructureND, - b: StructureND, - transform: DoubleField.(Double, Double) -> Double, - ): BufferND { - val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset -> - DoubleField.transform(a.buffer.array[offset], b.buffer.array[offset]) - }.toArray() - return BufferND(strides, array.asBuffer()) - } - - override fun StructureND.unaryMinus(): StructureND = map { -it } - - override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } - - override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) } - - override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } - - override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } - - override fun sin(arg: StructureND): BufferND = arg.map { sin(it) } - override fun cos(arg: StructureND): BufferND = arg.map { cos(it) } - override fun tan(arg: StructureND): BufferND = arg.map { tan(it) } - override fun asin(arg: StructureND): BufferND = arg.map { asin(it) } - override fun acos(arg: StructureND): BufferND = arg.map { acos(it) } - override fun atan(arg: StructureND): BufferND = arg.map { atan(it) } - - override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) } - override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) } - override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) } - override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) } - override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) } - override fun atanh(arg: StructureND): BufferND = arg.map { atanh(it) } -} - -fun AlgebraND.Companion.realWithStream(vararg shape: Int): StreamDoubleFieldND = StreamDoubleFieldND(shape) diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt deleted file mode 100644 index 853ebad32..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import space.kscience.kmath.dimensions.D2 -import space.kscience.kmath.dimensions.D3 -import space.kscience.kmath.dimensions.DMatrixContext -import space.kscience.kmath.dimensions.Dimension - -private fun DMatrixContext.simple() { - val m1 = produce { i, j -> (i + j).toDouble() } - val m2 = produce { i, j -> (i + j).toDouble() } - - //Dimension-safe addition - m1.transpose() + m2 -} - -private object D5 : Dimension { - override val dim: Int = 5 -} - -private fun DMatrixContext.custom() { - val m1 = produce { i, j -> (i + j).toDouble() } - val m2 = produce { i, j -> (i - j).toDouble() } - val m3 = produce { i, j -> (i - j).toDouble() } - (m1 dot m2) + m3 -} - -fun main(): Unit = with(DMatrixContext.real) { - simple() - 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 deleted file mode 100644 index 3ef745da3..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra - - -// Dataset normalization - -fun main() = BroadcastDoubleTensorAlgebra { // work in context with broadcast methods - // take dataset of 5-element vectors from normal distribution - val dataset = randomNormal(intArrayOf(100, 5)) * 1.5 // all elements from N(0, 1.5) - - dataset += fromArray( - intArrayOf(5), - doubleArrayOf(0.0, 1.0, 1.5, 3.0, 5.0) // row means - ) - - - // find out mean and standard deviation of each column - val mean = dataset.mean(0, false) - val std = dataset.std(0, false) - - println("Mean:\n$mean") - println("Standard deviation:\n$std") - - // also, we can calculate other statistic as minimum and maximum of rows - println("Minimum:\n${dataset.min(0, false)}") - println("Maximum:\n${dataset.max(0, false)}") - - // now we can scale dataset with mean normalization - val datasetScaled = (dataset - mean) / std - - // find out mean and std of scaled dataset - - println("Mean of scaled:\n${datasetScaled.mean(0, false)}") - println("Mean of scaled:\n${datasetScaled.std(0, false)}") -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt deleted file mode 100644 index 27886413f..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra -import space.kscience.kmath.tensors.core.DoubleTensor - -// solving linear system with LUP decomposition - -fun main() = BroadcastDoubleTensorAlgebra {// work in context with linear operations - - // set true value of x - val trueX = fromArray( - intArrayOf(4), - doubleArrayOf(-2.0, 1.5, 6.8, -2.4) - ) - - // and A matrix - val a = fromArray( - intArrayOf(4, 4), - doubleArrayOf( - 0.5, 10.5, 4.5, 1.0, - 8.5, 0.9, 12.8, 0.1, - 5.56, 9.19, 7.62, 5.45, - 1.0, 2.0, -3.0, -2.5 - ) - ) - - // calculate y value - val b = a dot trueX - - // check out A and b - println("A:\n$a") - println("b:\n$b") - - // solve `Ax = b` system using LUP decomposition - - // get P, L, U such that PA = LU - val (p, l, u) = a.lu() - - // check P is permutation matrix - println("P:\n$p") - // L is lower triangular matrix and U is upper triangular matrix - println("L:\n$l") - println("U:\n$u") - // and PA = LU - println("PA:\n${p dot a}") - println("LU:\n${l dot u}") - - /* Ax = b; - PAx = Pb; - LUx = Pb; - let y = Ux, then - Ly = Pb -- this system can be easily solved, since the matrix L is lower triangular; - Ux = y can be solved the same way, since the matrix L is upper triangular - */ - - - - // this function returns solution x of a system lx = b, l should be lower triangular - fun solveLT(l: DoubleTensor, b: DoubleTensor): DoubleTensor { - val n = l.shape[0] - val x = zeros(intArrayOf(n)) - for (i in 0 until n) { - x[intArrayOf(i)] = (b[intArrayOf(i)] - l[i].dot(x).value()) / l[intArrayOf(i, i)] - } - return x - } - - val y = solveLT(l, p dot b) - - // solveLT(l, b) function can be easily adapted for upper triangular matrix by the permutation matrix revMat - // create it by placing ones on side diagonal - val revMat = u.zeroesLike() - val n = revMat.shape[0] - for (i in 0 until n) { - revMat[intArrayOf(i, n - 1 - i)] = 1.0 - } - - // solution of system ux = b, u should be upper triangular - fun solveUT(u: DoubleTensor, b: DoubleTensor): DoubleTensor = revMat dot solveLT( - revMat dot u dot revMat, revMat dot b - ) - - val x = solveUT(u, y) - - println("True x:\n$trueX") - println("x founded with LU method:\n$x") -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt deleted file mode 100644 index 3025ff8a3..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.toDoubleArray -import kotlin.math.sqrt - -const val seed = 100500L - -// Simple feedforward neural network with backpropagation training - -// interface of network layer -interface Layer { - fun forward(input: DoubleTensor): DoubleTensor - fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor -} - -// activation layer -open class Activation( - val activation: (DoubleTensor) -> DoubleTensor, - val activationDer: (DoubleTensor) -> DoubleTensor, -) : Layer { - override fun forward(input: DoubleTensor): DoubleTensor { - return activation(input) - } - - override fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor { - return DoubleTensorAlgebra { outputError * activationDer(input) } - } -} - -fun relu(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { - x.map { if (it > 0) it else 0.0 } -} - -fun reluDer(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { - x.map { if (it > 0) 1.0 else 0.0 } -} - -// activation layer with relu activator -class ReLU : Activation(::relu, ::reluDer) - -fun sigmoid(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { - 1.0 / (1.0 + (-x).exp()) -} - -fun sigmoidDer(x: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { - sigmoid(x) * (1.0 - sigmoid(x)) -} - -// activation layer with sigmoid activator -class Sigmoid : Activation(::sigmoid, ::sigmoidDer) - -// dense layer -class Dense( - private val inputUnits: Int, - private val outputUnits: Int, - private val learningRate: Double = 0.1, -) : Layer { - - private val weights: DoubleTensor = DoubleTensorAlgebra { - randomNormal( - intArrayOf(inputUnits, outputUnits), - seed - ) * sqrt(2.0 / (inputUnits + outputUnits)) - } - - private val bias: DoubleTensor = DoubleTensorAlgebra { zeros(intArrayOf(outputUnits)) } - - override fun forward(input: DoubleTensor): DoubleTensor = BroadcastDoubleTensorAlgebra { - (input dot weights) + bias - } - - override fun backward(input: DoubleTensor, outputError: DoubleTensor): DoubleTensor = DoubleTensorAlgebra { - val gradInput = outputError dot weights.transpose() - - val gradW = input.transpose() dot outputError - val gradBias = outputError.mean(dim = 0, keepDim = false) * input.shape[0].toDouble() - - weights -= learningRate * gradW - bias -= learningRate * gradBias - - gradInput - } - -} - -// simple accuracy equal to the proportion of correct answers -fun accuracy(yPred: DoubleTensor, yTrue: DoubleTensor): Double { - check(yPred.shape contentEquals yTrue.shape) - val n = yPred.shape[0] - var correctCnt = 0 - for (i in 0 until n) { - if (yPred[intArrayOf(i, 0)] == yTrue[intArrayOf(i, 0)]) { - correctCnt += 1 - } - } - return correctCnt.toDouble() / n.toDouble() -} - -// neural network class -@OptIn(ExperimentalStdlibApi::class) -class NeuralNetwork(private val layers: List) { - private fun softMaxLoss(yPred: DoubleTensor, yTrue: DoubleTensor): DoubleTensor = BroadcastDoubleTensorAlgebra { - - val onesForAnswers = yPred.zeroesLike() - yTrue.toDoubleArray().forEachIndexed { index, labelDouble -> - val label = labelDouble.toInt() - onesForAnswers[intArrayOf(index, label)] = 1.0 - } - - val softmaxValue = yPred.exp() / yPred.exp().sum(dim = 1, keepDim = true) - - (-onesForAnswers + softmaxValue) / (yPred.shape[0].toDouble()) - } - - - private fun forward(x: DoubleTensor): List { - var input = x - - return buildList { - layers.forEach { layer -> - val output = layer.forward(input) - add(output) - input = output - } - } - } - - private fun train(xTrain: DoubleTensor, yTrain: DoubleTensor) { - val layerInputs = buildList { - add(xTrain) - addAll(forward(xTrain)) - } - - var lossGrad = softMaxLoss(layerInputs.last(), yTrain) - - layers.zip(layerInputs).reversed().forEach { (layer, input) -> - lossGrad = layer.backward(input, lossGrad) - } - } - - fun fit(xTrain: DoubleTensor, yTrain: DoubleTensor, batchSize: Int, epochs: Int) = DoubleTensorAlgebra { - fun iterBatch(x: DoubleTensor, y: DoubleTensor): Sequence> = sequence { - val n = x.shape[0] - val shuffledIndices = (0 until n).shuffled() - for (i in 0 until n step batchSize) { - val excerptIndices = shuffledIndices.drop(i).take(batchSize).toIntArray() - val batch = x.rowsByIndices(excerptIndices) to y.rowsByIndices(excerptIndices) - yield(batch) - } - } - - for (epoch in 0 until epochs) { - println("Epoch ${epoch + 1}/$epochs") - for ((xBatch, yBatch) in iterBatch(xTrain, yTrain)) { - train(xBatch, yBatch) - } - println("Accuracy:${accuracy(yTrain, predict(xTrain).argMax(1, true))}") - } - } - - fun predict(x: DoubleTensor): DoubleTensor { - return forward(x).last() - } - -} - - -@OptIn(ExperimentalStdlibApi::class) -fun main() = BroadcastDoubleTensorAlgebra { - val features = 5 - val sampleSize = 250 - val trainSize = 180 - //val testSize = sampleSize - trainSize - - // take sample of features from normal distribution - val x = randomNormal(intArrayOf(sampleSize, features), seed) * 2.5 - - x += fromArray( - intArrayOf(5), - doubleArrayOf(0.0, -1.0, -2.5, -3.0, 5.5) // row means - ) - - - // define class like '1' if the sum of features > 0 and '0' otherwise - val y = fromArray( - intArrayOf(sampleSize, 1), - DoubleArray(sampleSize) { i -> - if (x[i].sum() > 0.0) { - 1.0 - } else { - 0.0 - } - } - ) - - // split train ans test - val trainIndices = (0 until trainSize).toList().toIntArray() - val testIndices = (trainSize until sampleSize).toList().toIntArray() - - val xTrain = x.rowsByIndices(trainIndices) - val yTrain = y.rowsByIndices(trainIndices) - - val xTest = x.rowsByIndices(testIndices) - val yTest = y.rowsByIndices(testIndices) - - // build model - val layers = buildList { - add(Dense(features, 64)) - add(ReLU()) - add(Dense(64, 16)) - add(ReLU()) - add(Dense(16, 2)) - add(Sigmoid()) - } - val model = NeuralNetwork(layers) - - // fit it with train data - model.fit(xTrain, yTrain, batchSize = 20, epochs = 10) - - // make prediction - val prediction = model.predict(xTest) - - // process raw prediction via argMax - val predictionLabels = prediction.argMax(1, true) - - // find out accuracy - val acc = accuracy(yTest, predictionLabels) - println("Test accuracy:$acc") - -} diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt deleted file mode 100644 index a266d4849..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra - -import kotlin.math.abs - -// OLS estimator using SVD - -fun main() { - //seed for random - val randSeed = 100500L - - // work in context with linear operations - DoubleTensorAlgebra { - // take coefficient vector from normal distribution - val alpha = randomNormal( - intArrayOf(5), - randSeed - ) + fromArray( - intArrayOf(5), - doubleArrayOf(1.0, 2.5, 3.4, 5.0, 10.1) - ) - - println("Real alpha:\n$alpha") - - // also take sample of size 20 from normal distribution for x - val x = randomNormal( - intArrayOf(20, 5), - randSeed - ) - - // calculate y and add gaussian noise (N(0, 0.05)) - val y = x dot alpha - y += y.randomNormalLike(randSeed) * 0.05 - - // now restore the coefficient vector with OSL estimator with SVD - val (u, singValues, v) = x.svd() - - // we have to make sure the singular values of the matrix are not close to zero - println("Singular values:\n$singValues") - - - // inverse Sigma matrix can be restored from singular values with diagonalEmbedding function - val sigma = diagonalEmbedding(singValues.map{ if (abs(it) < 1e-3) 0.0 else 1.0/it }) - - val alphaOLS = v dot sigma dot u.transpose() dot y - println("Estimated alpha:\n" + - "$alphaOLS") - - // figure out MSE of approximation - fun mse(yTrue: DoubleTensor, yPred: DoubleTensor): Double { - require(yTrue.shape.size == 1) - require(yTrue.shape contentEquals yPred.shape) - - val diff = yTrue - yPred - return diff.dot(diff).sqrt().value() - } - - println("MSE: ${mse(alpha, alphaOLS)}") - } -} \ No newline at end of file diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt deleted file mode 100644 index 3302b49a8..000000000 --- a/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra - - -// simple PCA - -fun main(): Unit = BroadcastDoubleTensorAlgebra { // work in context with broadcast methods - val seed = 100500L - - // assume x is range from 0 until 10 - val x = fromArray( - intArrayOf(10), - (0 until 10).toList().map { it.toDouble() }.toDoubleArray() - ) - - // take y dependent on x with noise - val y = 2.0 * x + (3.0 + x.randomNormalLike(seed) * 1.5) - - println("x:\n$x") - println("y:\n$y") - - // stack them into single dataset - val dataset = stack(listOf(x, y)).transpose() - - // normalize both x and y - val xMean = x.mean() - val yMean = y.mean() - - val xStd = x.std() - val yStd = y.std() - - val xScaled = (x - xMean) / xStd - val yScaled = (y - yMean) / yStd - - // save means ans standard deviations for further recovery - val mean = fromArray( - intArrayOf(2), - doubleArrayOf(xMean, yMean) - ) - println("Means:\n$mean") - - val std = fromArray( - intArrayOf(2), - doubleArrayOf(xStd, yStd) - ) - println("Standard deviations:\n$std") - - // calculate the covariance matrix of scaled x and y - val covMatrix = cov(listOf(xScaled, yScaled)) - println("Covariance matrix:\n$covMatrix") - - // and find out eigenvector of it - val (_, evecs) = covMatrix.symEig() - val v = evecs[0] - println("Eigenvector:\n$v") - - // reduce dimension of dataset - val datasetReduced = v dot stack(listOf(xScaled, yScaled)) - println("Reduced data:\n$datasetReduced") - - // we can restore original data from reduced data; - // for example, find 7th element of dataset. - val n = 7 - val restored = (datasetReduced[n] dot v.view(intArrayOf(1, 2))) * std + mean - println("Original value:\n${dataset[n]}") - println("Restored value:\n$restored") -} diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index b97db1c54..000000000 --- a/gradle.properties +++ /dev/null @@ -1,12 +0,0 @@ -# -# Copyright 2018-2021 KMath contributors. -# Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. -# - -kotlin.code.style=official -kotlin.mpp.enableGranularSourceSetsMetadata=true -kotlin.mpp.stability.nowarn=true -kotlin.native.enableDependencyPropagation=false -org.gradle.configureondemand=true -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 7454180f2..62d4c0535 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 05679dc3c..622ab64a3 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.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 744e882ed..fbd7c5158 100755 --- a/gradlew +++ b/gradlew @@ -72,7 +72,7 @@ case "`uname`" in Darwin* ) darwin=true ;; - MSYS* | MINGW* ) + MINGW* ) msys=true ;; NONSTOP* ) @@ -130,7 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath diff --git a/gradlew.bat b/gradlew.bat index 107acd32c..5093609d5 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto execute +if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,6 +64,21 @@ echo location of your Java installation. goto fail +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + :execute @rem Setup the command line @@ -71,7 +86,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell diff --git a/kmath-ast/README.md b/kmath-ast/README.md deleted file mode 100644 index 686506f6f..000000000 --- a/kmath-ast/README.md +++ /dev/null @@ -1,241 +0,0 @@ -# Module kmath-ast - -Performance and visualization extensions to MST API. - - - [expression-language](src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt) : Expression language and its parser - - [mst-jvm-codegen](src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler - - [mst-js-codegen](src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler - - [rendering](src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt) : Extendable MST rendering - - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-ast:0.3.0-dev-14`. - -**Gradle:** -```gradle -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-ast:0.3.0-dev-14' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-ast:0.3.0-dev-14") -} -``` - -## Dynamic expression code generation - -### On JVM - -`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a -special implementation of `Expression` with implemented `invoke` function. - -For example, the following 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 { x + 2 }.compileToExpression(DoubleField) -``` - -... leads to generation of bytecode, which can be decompiled to the following Java class: - -```java -package space.kscience.kmath.asm.generated; - -import java.util.Map; - -import kotlin.jvm.functions.Function2; -import space.kscience.kmath.asm.internal.MapIntrinsics; -import space.kscience.kmath.expressions.Expression; -import space.kscience.kmath.expressions.Symbol; - -public final class AsmCompiledExpression_45045_0 implements Expression { - private final Object[] constants; - - public final Double invoke(Map arguments) { - return (Double) ((Function2) this.constants[0]).invoke((Double) MapIntrinsics.getOrFail(arguments, "x"), 2); - } - - public AsmCompiledExpression_45045_0(Object[] constants) { - this.constants = constants; - } -} - -``` - -#### Known issues - -- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class - loading overhead. -- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders. - -### On JS - -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 { x + 2 }.compileToExpression(DoubleField) -``` - -The code above returns expression implemented with such a JS function: - -```js -var executable = function (constants, arguments) { - return constants[1](constants[0](arguments, "x"), 2); -}; -``` - -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 { x + 2 }.compileToExpression(DoubleField) -``` - -An example of emitted Wasm IR in the form of WAT: - -```lisp -(func $executable (param $0 f64) (result f64) - (f64.add - (local.get $0) - (f64.const 2) - ) -) -``` - -#### Known issues - -- ESTree expression compilation uses `eval` which can be unavailable in several environments. -- WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/). - -## Rendering expressions - -kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax. - -Example usage: - -```kotlin -import space.kscience.kmath.ast.* -import space.kscience.kmath.ast.rendering.* -import space.kscience.kmath.misc.* - -@OptIn(UnstableKMathAPI::class) -public fun main() { - val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(12)+x^(2/3)".parseMath() - val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst) - val latex = LatexSyntaxRenderer.renderWithStringBuilder(syntax) - println("LaTeX:") - println(latex) - println() - val mathML = MathMLSyntaxRenderer.renderWithStringBuilder(syntax) - println("MathML:") - println(mathML) -} -``` - -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): - -
- -```html - - - exp - - - - x - - - - - - - - - arcsin - - - 2 - - x - - - - 2 - × - - - 10 - - - 10 - - - + - - - x - - - 3 - - - - - - - 12 - - - + - - - x - - - 2 - / - 3 - - - - -``` - -
- -It is also possible to create custom algorithms of render, and even add support of other markup languages -(see API reference). diff --git a/kmath-ast/build.gradle.kts b/kmath-ast/build.gradle.kts deleted file mode 100644 index 9de7e9980..000000000 --- a/kmath-ast/build.gradle.kts +++ /dev/null @@ -1,81 +0,0 @@ -plugins { - kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") -} - -kotlin.js { - nodejs { - testTask { - useMocha().timeout = "0" - } - } - - browser { - testTask { - useMocha().timeout = "0" - } - } -} - -kotlin.sourceSets { - filter { it.name.contains("test", true) } - .map(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::languageSettings) - .forEach { it.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") } - - commonMain { - dependencies { - api("com.github.h0tk3y.betterParse:better-parse:0.4.2") - api(project(":kmath-core")) - } - } - - commonTest { - dependencies { - implementation(project(":kmath-complex")) - } - } - - jsMain { - dependencies { - 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-commons:9.2") - } - } -} - -//Workaround for https://github.com/Kotlin/dokka/issues/1455 -tasks.dokkaHtml { - dependsOn(tasks.build) -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL - propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) - - feature( - id = "expression-language", - ref = "src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt" - ) { "Expression language and its parser" } - - feature( - id = "mst-jvm-codegen", - ref = "src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt" - ) { "Dynamic MST to JVM bytecode compiler" } - - feature( - id = "mst-js-codegen", - ref = "src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt" - ) { "Dynamic MST to JS compiler" } - - feature( - id = "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 deleted file mode 100644 index 9494af63a..000000000 --- a/kmath-ast/docs/README-TEMPLATE.md +++ /dev/null @@ -1,212 +0,0 @@ -# Module kmath-ast - -Performance and visualization extensions to MST API. - -${features} - -${artifact} - -## Dynamic expression code generation - -### On JVM - -`kmath-ast` JVM module supports runtime code generation to eliminate overhead of tree traversal. Code generator builds a -special implementation of `Expression` with implemented `invoke` function. - -For example, the following 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 { x + 2 }.compileToExpression(DoubleField) -``` - -... leads to generation of bytecode, which can be decompiled to the following Java class: - -```java -package space.kscience.kmath.asm.generated; - -import java.util.Map; - -import kotlin.jvm.functions.Function2; -import space.kscience.kmath.asm.internal.MapIntrinsics; -import space.kscience.kmath.expressions.Expression; -import space.kscience.kmath.expressions.Symbol; - -public final class AsmCompiledExpression_45045_0 implements Expression { - private final Object[] constants; - - public final Double invoke(Map arguments) { - return (Double) ((Function2) this.constants[0]).invoke((Double) MapIntrinsics.getOrFail(arguments, "x"), 2); - } - - public AsmCompiledExpression_45045_0(Object[] constants) { - this.constants = constants; - } -} - -``` - -#### Known issues - -- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid class - loading overhead. -- This API is not supported by non-dynamic JVM implementations (like TeaVM and GraalVM) because of using class loaders. - -### On JS - -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 { x + 2 }.compileToExpression(DoubleField) -``` - -The code above returns expression implemented with such a JS function: - -```js -var executable = function (constants, arguments) { - return constants[1](constants[0](arguments, "x"), 2); -}; -``` - -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 { x + 2 }.compileToExpression(DoubleField) -``` - -An example of emitted Wasm IR in the form of WAT: - -```lisp -(func \$executable (param \$0 f64) (result f64) - (f64.add - (local.get \$0) - (f64.const 2) - ) -) -``` - -#### Known issues - -- ESTree expression compilation uses `eval` which can be unavailable in several environments. -- WebAssembly isn't supported by old versions of browsers (see https://webassembly.org/roadmap/). - -## Rendering expressions - -kmath-ast also includes an extensible engine to display expressions in LaTeX or MathML syntax. - -Example usage: - -```kotlin -import space.kscience.kmath.ast.* -import space.kscience.kmath.ast.rendering.* -import space.kscience.kmath.misc.* - -@OptIn(UnstableKMathAPI::class) -public fun main() { - val mst = "exp(sqrt(x))-asin(2*x)/(2e10+x^3)/(12)+x^(2/3)".parseMath() - val syntax = FeaturedMathRendererWithPostProcess.Default.render(mst) - val latex = LatexSyntaxRenderer.renderWithStringBuilder(syntax) - println("LaTeX:") - println(latex) - println() - val mathML = MathMLSyntaxRenderer.renderWithStringBuilder(syntax) - println("MathML:") - println(mathML) -} -``` - -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): - -
- -```html - - - exp - - - - x - - - - - - - - - arcsin - - - 2 - - x - - - - 2 - × - - - 10 - - - 10 - - - + - - - x - - - 3 - - - - - - - 12 - - - + - - - x - - - 2 - / - 3 - - - - -``` - -
- -It is also possible to create custom algorithms of render, and even add support of other markup languages -(see API reference). diff --git a/kmath-ast/reference/ArithmeticsEvaluator.g4 b/kmath-ast/reference/ArithmeticsEvaluator.g4 deleted file mode 100644 index dc47b23fb..000000000 --- a/kmath-ast/reference/ArithmeticsEvaluator.g4 +++ /dev/null @@ -1,59 +0,0 @@ -grammar ArithmeticsEvaluator; - -fragment DIGIT: '0'..'9'; -fragment LETTER: 'a'..'z'; -fragment CAPITAL_LETTER: 'A'..'Z'; -fragment UNDERSCORE: '_'; - -ID: (LETTER | UNDERSCORE | CAPITAL_LETTER) (LETTER | UNDERSCORE | DIGIT | CAPITAL_LETTER)*; -NUM: (DIGIT | '.')+ ([eE] [-+]? DIGIT+)?; -MUL: '*'; -DIV: '/'; -PLUS: '+'; -MINUS: '-'; -POW: '^'; -COMMA: ','; -LPAR: '('; -RPAR: ')'; -WS: [ \n\t\r]+ -> skip; - -num - : NUM - ; - -singular - : ID - ; - -unaryFunction - : ID LPAR subSumChain RPAR - ; - -binaryFunction - : ID LPAR subSumChain COMMA subSumChain RPAR - ; - -term - : num - | singular - | unaryFunction - | binaryFunction - | MINUS term - | LPAR subSumChain RPAR - ; - -powChain - : term (POW term)* - ; - -divMulChain - : powChain ((DIV | MUL) powChain)* - ; - -subSumChain - : divMulChain ((PLUS | MINUS) divMulChain)* - ; - -rootParser - : subSumChain EOF - ; diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt deleted file mode 100644 index b02cc926b..000000000 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast - -import com.github.h0tk3y.betterParse.combinators.* -import com.github.h0tk3y.betterParse.grammar.Grammar -import com.github.h0tk3y.betterParse.grammar.parseToEnd -import com.github.h0tk3y.betterParse.grammar.parser -import com.github.h0tk3y.betterParse.grammar.tryParseToEnd -import com.github.h0tk3y.betterParse.lexer.Token -import com.github.h0tk3y.betterParse.lexer.TokenMatch -import com.github.h0tk3y.betterParse.lexer.literalToken -import com.github.h0tk3y.betterParse.lexer.regexToken -import com.github.h0tk3y.betterParse.parser.ParseResult -import com.github.h0tk3y.betterParse.parser.Parser -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.StringSymbol -import space.kscience.kmath.operations.FieldOperations -import space.kscience.kmath.operations.GroupOperations -import space.kscience.kmath.operations.PowerOperations -import space.kscience.kmath.operations.RingOperations - -/** - * better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4. - * - * @author Alexander Nozik - * @author Iaroslav Postovalov - */ -public object ArithmeticsEvaluator : Grammar() { - private val num: Token by regexToken("[\\d.]+(?:[eE][-+]?\\d+)?".toRegex()) - private val id: Token by regexToken("[a-z_A-Z][\\da-z_A-Z]*".toRegex()) - private val lpar: Token by literalToken("(") - private val rpar: Token by literalToken(")") - private val comma: Token by literalToken(",") - private val mul: Token by literalToken("*") - private val pow: Token by literalToken("^") - private val div: Token by literalToken("/") - private val minus: Token by literalToken("-") - private val plus: Token by literalToken("+") - private val ws: Token by regexToken("\\s+".toRegex(), ignore = true) - - private val number: Parser by num use { MST.Numeric(text.toDouble()) } - private val singular: Parser by id use { StringSymbol(text) } - - private val unaryFunction: Parser by (id and -lpar and parser(ArithmeticsEvaluator::subSumChain) and -rpar) - .map { (id, term) -> MST.Unary(id.text, term) } - - private val binaryFunction: Parser by id - .and(-lpar) - .and(parser(ArithmeticsEvaluator::subSumChain)) - .and(-comma) - .and(parser(ArithmeticsEvaluator::subSumChain)) - .and(-rpar) - .map { (id, left, right) -> MST.Binary(id.text, left, right) } - - private val term: Parser by number - .or(binaryFunction) - .or(unaryFunction) - .or(singular) - .or(-minus and parser(ArithmeticsEvaluator::term) map { MST.Unary(GroupOperations.MINUS_OPERATION, it) }) - .or(-lpar and parser(ArithmeticsEvaluator::subSumChain) and -rpar) - - private val powChain: Parser by leftAssociative(term = term, operator = pow) { a, _, b -> - MST.Binary(PowerOperations.POW_OPERATION, a, b) - } - - private val divMulChain: Parser by leftAssociative( - term = powChain, - operator = div or mul use TokenMatch::type - ) { a, op, b -> - if (op == div) - MST.Binary(FieldOperations.DIV_OPERATION, a, b) - else - MST.Binary(RingOperations.TIMES_OPERATION, a, b) - } - - private val subSumChain: Parser by leftAssociative( - term = divMulChain, - operator = plus or minus use TokenMatch::type - ) { a, op, b -> - if (op == plus) - MST.Binary(GroupOperations.PLUS_OPERATION, a, b) - else - MST.Binary(GroupOperations.MINUS_OPERATION, a, b) - } - - override val rootParser: Parser by subSumChain -} - -/** - * Tries to parse the string into [MST] using [ArithmeticsEvaluator]. Returns [ParseResult] representing expression or error. - * - * @receiver the string to parse. - * @return the [MST] node. - */ -public fun String.tryParseMath(): ParseResult = ArithmeticsEvaluator.tryParseToEnd(this) - -/** - * Parses the string into [MST] using [ArithmeticsEvaluator]. - * - * @receiver the string to parse. - * @return the [MST] node. - */ -public fun String.parseMath(): MST = ArithmeticsEvaluator.parseToEnd(this) 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 deleted file mode 100644 index bf5916fa5..000000000 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast.rendering - -import space.kscience.kmath.misc.UnstableKMathAPI - -/** - * [SyntaxRenderer] implementation for LaTeX. - * - * The generated string is a valid LaTeX fragment to be used in the Math Mode. - * - * Example usage: - * - * ``` - * \documentclass{article} - * \begin{document} - * \begin{equation} - * %code generated by the syntax renderer - * \end{equation} - * \end{document} - * ``` - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public object LatexSyntaxRenderer : SyntaxRenderer { - override fun render(node: MathSyntax, output: Appendable): Unit = output.run { - fun render(syntax: MathSyntax) = render(syntax, output) - - when (node) { - is NumberSyntax -> append(node.string) - is SymbolSyntax -> append(node.string) - - is OperatorNameSyntax -> { - append("\\operatorname{") - append(node.name) - append('}') - } - - is SpecialSymbolSyntax -> when (node.kind) { - SpecialSymbolSyntax.Kind.INFINITY -> append("\\infty") - SpecialSymbolSyntax.Kind.SMALL_PI -> append("\\pi") - } - - is OperandSyntax -> { - if (node.parentheses) append("\\left(") - render(node.operand) - if (node.parentheses) append("\\right)") - } - - is UnaryOperatorSyntax -> { - render(node.prefix) - append("\\,") - render(node.operand) - } - - is UnaryPlusSyntax -> { - append('+') - render(node.operand) - } - - is UnaryMinusSyntax -> { - append('-') - render(node.operand) - } - - is RadicalSyntax -> { - append("\\sqrt") - append('{') - render(node.operand) - append('}') - } - - is ExponentSyntax -> if (node.useOperatorForm) { - append("\\operatorname{exp}\\,") - render(node.operand) - } else { - append("e^{") - render(node.operand) - append('}') - } - - is SuperscriptSyntax -> { - render(node.left) - append("^{") - render(node.right) - append('}') - } - - is SubscriptSyntax -> { - render(node.left) - append("_{") - render(node.right) - append('}') - } - - is BinaryOperatorSyntax -> { - render(node.prefix) - append("\\left(") - render(node.left) - append(',') - render(node.right) - append("\\right)") - } - - is BinaryPlusSyntax -> { - render(node.left) - append('+') - render(node.right) - } - - is BinaryMinusSyntax -> { - render(node.left) - append('-') - render(node.right) - } - - is FractionSyntax -> if (node.infix) { - render(node.left) - append('/') - render(node.right) - } else { - append("\\frac{") - render(node.left) - append("}{") - render(node.right) - append('}') - } - - is RadicalWithIndexSyntax -> { - append("\\sqrt") - append('[') - render(node.left) - append(']') - append('{') - render(node.right) - append('}') - } - - is MultiplicationSyntax -> { - render(node.left) - append(if (node.times) "\\times" else "\\,") - render(node.right) - } - } - } -} 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 deleted file mode 100644 index 5439c42fa..000000000 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast.rendering - -import space.kscience.kmath.misc.UnstableKMathAPI - -/** - * [SyntaxRenderer] implementation for MathML. - * - * The generated XML string is a valid MathML instance. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public object MathMLSyntaxRenderer : SyntaxRenderer { - override fun render(node: MathSyntax, output: Appendable) { - output.append("") - renderPart(node, output) - output.append("") - } - - /** - * Renders a part of syntax returning a correct MathML tag not the whole MathML instance. - */ - public fun renderPart(node: MathSyntax, output: Appendable): Unit = output.run { - fun tag(tagName: String, vararg attr: Pair, block: () -> Unit = {}) { - append('<') - append(tagName) - - if (attr.isNotEmpty()) { - append(' ') - var count = 0 - - for ((name, value) in attr) { - if (++count > 1) append(' ') - append(name) - append("=\"") - append(value) - append('"') - } - } - - append('>') - block() - append("') - } - - fun render(syntax: MathSyntax) = renderPart(syntax, output) - - when (node) { - is NumberSyntax -> tag("mn") { append(node.string) } - is SymbolSyntax -> tag("mi") { append(node.string) } - is OperatorNameSyntax -> tag("mo") { append(node.name) } - - is SpecialSymbolSyntax -> when (node.kind) { - SpecialSymbolSyntax.Kind.INFINITY -> tag("mo") { append("∞") } - SpecialSymbolSyntax.Kind.SMALL_PI -> tag("mo") { append("π") } - } - - is OperandSyntax -> if (node.parentheses) { - tag("mfenced", "open" to "(", "close" to ")", "separators" to "") { - render(node.operand) - } - } else { - render(node.operand) - } - - is UnaryOperatorSyntax -> { - render(node.prefix) - tag("mspace", "width" to "0.167em") - render(node.operand) - } - - is UnaryPlusSyntax -> { - tag("mo") { append('+') } - render(node.operand) - } - - is UnaryMinusSyntax -> { - tag("mo") { append("-") } - render(node.operand) - } - - is RadicalSyntax -> tag("msqrt") { render(node.operand) } - - is ExponentSyntax -> if (node.useOperatorForm) { - tag("mo") { append("exp") } - tag("mspace", "width" to "0.167em") - render(node.operand) - } else { - tag("msup") { - tag("mrow") { - tag("mi") { append("e") } - } - tag("mrow") { render(node.operand) } - } - } - - is SuperscriptSyntax -> tag("msup") { - tag("mrow") { render(node.left) } - tag("mrow") { render(node.right) } - } - - is SubscriptSyntax -> tag("msub") { - tag("mrow") { render(node.left) } - tag("mrow") { render(node.right) } - } - - is BinaryOperatorSyntax -> { - render(node.prefix) - - tag("mfenced", "open" to "(", "close" to ")", "separators" to "") { - render(node.left) - tag("mo") { append(',') } - render(node.right) - } - } - - is BinaryPlusSyntax -> { - render(node.left) - tag("mo") { append('+') } - render(node.right) - } - - is BinaryMinusSyntax -> { - render(node.left) - tag("mo") { append('-') } - render(node.right) - } - - is FractionSyntax -> if (node.infix) { - render(node.left) - tag("mo") { append('/') } - render(node.right) - } else tag("mfrac") { - tag("mrow") { render(node.left) } - tag("mrow") { render(node.right) } - } - - is RadicalWithIndexSyntax -> tag("mroot") { - tag("mrow") { render(node.right) } - tag("mrow") { render(node.left) } - } - - is MultiplicationSyntax -> { - render(node.left) - if (node.times) tag("mo") { append("×") } else tag("mspace", "width" to "0.167em") - render(node.right) - } - } - } -} 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 deleted file mode 100644 index 24bac425a..000000000 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathRenderer.kt +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast.rendering - -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.misc.UnstableKMathAPI - -/** - * Renders [MST] to [MathSyntax]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun interface MathRenderer { - /** - * Renders [MST] to [MathSyntax]. - */ - public fun render(mst: MST): MathSyntax -} - -/** - * Implements [MST] render process with sequence of features. - * - * @property features The applied features. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public open class FeaturedMathRenderer(public val features: List) : MathRenderer { - 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.") - } - - /** - * Logical unit of [MST] rendering. - */ - public fun interface RenderFeature { - /** - * Renders [MST] to [MathSyntax] in the context of owning renderer. - */ - public fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? - } -} - -/** - * Extends [FeaturedMathRenderer] by adding post-processing stages. - * - * @property stages The applied stages. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public open class FeaturedMathRendererWithPostProcess( - features: List, - public val stages: List, -) : FeaturedMathRenderer(features) { - override fun render(mst: MST): MathSyntax { - val res = super.render(mst) - for (stage in stages) stage.perform(res) - return res - } - - /** - * Logical unit of [MathSyntax] post-processing. - */ - public fun interface PostProcessPhase { - /** - * Performs the specified action over [MathSyntax]. - */ - public fun perform(node: MathSyntax) - } - - public companion object { - /** - * The default setup of [FeaturedMathRendererWithPostProcess]. - */ - public val Default: FeaturedMathRendererWithPostProcess = FeaturedMathRendererWithPostProcess( - listOf( - // Printing known operations - BinaryPlus.Default, - BinaryMinus.Default, - UnaryPlus.Default, - UnaryMinus.Default, - Multiplication.Default, - Fraction.Default, - Power.Default, - SquareRoot.Default, - Exponent.Default, - InverseTrigonometricOperations.Default, - InverseHyperbolicOperations.Default, - - // Fallback option for unknown operations - printing them as operator - BinaryOperator.Default, - UnaryOperator.Default, - - // Pretty printing for some objects - PrettyPrintFloats.Default, - PrettyPrintIntegers.Default, - PrettyPrintPi.Default, - - // Printing terminal nodes as string - PrintNumeric, - PrintSymbol, - ), - listOf( - BetterExponent, - BetterFraction, - SimplifyParentheses.Default, - BetterMultiplication, - ), - ) - } -} 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 deleted file mode 100644 index 81b7d2afb..000000000 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathSyntax.kt +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast.rendering - -import space.kscience.kmath.misc.UnstableKMathAPI - -/** - * Syntax node for mathematical typography. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public sealed class MathSyntax { - /** - * The parent node of this syntax node. - */ - public var parent: MathSyntax? = null -} - -/** - * Terminal node, which should not have any children nodes. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public sealed class TerminalSyntax : MathSyntax() - -/** - * Node containing a certain operation. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public sealed class OperationSyntax : MathSyntax() { - /** - * The operation token. - */ - public abstract val operation: String -} - -/** - * Unary node, which has only one child. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public sealed class UnarySyntax : OperationSyntax() { - /** - * The operand of this node. - */ - public abstract val operand: MathSyntax -} - -/** - * Binary node, which has only two children. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public sealed class BinarySyntax : OperationSyntax() { - /** - * The left-hand side operand. - */ - public abstract val left: MathSyntax - - /** - * The right-hand side operand. - */ - public abstract val right: MathSyntax -} - -/** - * Represents a number. - * - * @property string The digits of number. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class NumberSyntax(public var string: String) : TerminalSyntax() - -/** - * Represents a symbol. - * - * @property string The symbol. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class SymbolSyntax(public var string: String) : TerminalSyntax() - -/** - * Represents special typing for operator name. - * - * @property name The operator name. - * @see BinaryOperatorSyntax - * @see UnaryOperatorSyntax - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class OperatorNameSyntax(public var name: String) : TerminalSyntax() - -/** - * Represents a usage of special symbols (e.g., *∞*). - * - * @property kind The kind of symbol. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class SpecialSymbolSyntax(public var kind: Kind) : TerminalSyntax() { - /** - * The kind of symbol. - */ - public enum class Kind { - /** - * The infinity (∞) symbol. - */ - INFINITY, - - /** - * The Pi (π) symbol. - */ - SMALL_PI; - } -} - -/** - * Represents operand of a certain operator wrapped with parentheses or not. - * - * @property operand The operand. - * @property parentheses Whether the operand should be wrapped with parentheses. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class OperandSyntax( - public val operand: MathSyntax, - public var parentheses: Boolean, -) : MathSyntax() { - init { - operand.parent = this - } -} - -/** - * Represents unary, prefix operator syntax (like *f(x)*). - * - * @property prefix The prefix. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class UnaryOperatorSyntax( - override val operation: String, - public var prefix: MathSyntax, - override val operand: OperandSyntax, -) : UnarySyntax() { - init { - operand.parent = this - } -} - -/** - * Represents prefix, unary plus operator (*+x*). - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class UnaryPlusSyntax( - override val operation: String, - override val operand: OperandSyntax, -) : UnarySyntax() { - init { - operand.parent = this - } -} - -/** - * Represents prefix, unary minus operator (*-x*). - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class UnaryMinusSyntax( - override val operation: String, - override val operand: OperandSyntax, -) : UnarySyntax() { - init { - operand.parent = this - } -} - -/** - * Represents radical with a node inside it (*√x*). - * - * @property operand The radicand. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class RadicalSyntax( - override val operation: String, - override val operand: MathSyntax, -) : UnarySyntax() { - init { - operand.parent = this - } -} - -/** - * Represents exponential function. - * - * @property operand The argument of function. - * @property useOperatorForm `true` if operator form is used (*exp (x)*), `false` if exponentiation form is used - * (*ex*). - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class ExponentSyntax( - override val operation: String, - override val operand: OperandSyntax, - public var useOperatorForm: Boolean, -) : UnarySyntax() { - init { - operand.parent = this - } -} - -/** - * Represents a syntax node with superscript (*x2*). - * - * @property left The node. - * @property right The superscript. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class SuperscriptSyntax( - override val operation: String, - override val left: MathSyntax, - override val right: MathSyntax, -) : BinarySyntax() { - init { - left.parent = this - right.parent = this - } -} - -/** - * Represents a syntax node with subscript (*xi*). - * - * @property left The node. - * @property right The subscript. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class SubscriptSyntax( - override val operation: String, - override val left: MathSyntax, - override val right: MathSyntax, -) : BinarySyntax() { - init { - left.parent = this - right.parent = this - } -} - -/** - * Represents binary, prefix operator syntax (like *f(a, b)*). - * - * @property prefix The prefix. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class BinaryOperatorSyntax( - override val operation: String, - public var prefix: MathSyntax, - override val left: MathSyntax, - override val right: MathSyntax, -) : BinarySyntax() { - init { - left.parent = this - right.parent = this - } -} - -/** - * Represents binary, infix addition (*42 + 42*). - * - * @param left The augend. - * @param right The addend. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class BinaryPlusSyntax( - override val operation: String, - override val left: OperandSyntax, - override val right: OperandSyntax, -) : BinarySyntax() { - init { - left.parent = this - right.parent = this - } -} - -/** - * Represents binary, infix subtraction (*42 − 42*). - * - * @param left The minuend. - * @param right The subtrahend. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class BinaryMinusSyntax( - override val operation: String, - override val left: OperandSyntax, - override val right: OperandSyntax, -) : BinarySyntax() { - init { - left.parent = this - right.parent = this - } -} - -/** - * Represents fraction with numerator and denominator. - * - * @property left The numerator. - * @property right The denominator. - * @property infix Whether infix (*1 / 2*) or normal (*½*) fraction should be made. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class FractionSyntax( - override val operation: String, - override val left: OperandSyntax, - override val right: OperandSyntax, - public var infix: Boolean, -) : BinarySyntax() { - init { - left.parent = this - right.parent = this - } -} - -/** - * Represents radical syntax with index (*3√x*). - * - * @property left The index. - * @property right The radicand. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class RadicalWithIndexSyntax( - override val operation: String, - override val left: MathSyntax, - override val right: MathSyntax, -) : BinarySyntax() { - init { - left.parent = this - right.parent = this - } -} - -/** - * Represents binary, infix multiplication in the form of coefficient (*2 x*) or with operator (*x × 2*). - * - * @property left The multiplicand. - * @property right The multiplier. - * @property times Whether the times (×) symbol should be used. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public data class MultiplicationSyntax( - override val operation: String, - override val left: OperandSyntax, - override val right: OperandSyntax, - public var times: Boolean, -) : BinarySyntax() { - init { - left.parent = this - right.parent = this - } -} 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 deleted file mode 100644 index 2f285c600..000000000 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/SyntaxRenderer.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast.rendering - -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 subtype. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun interface SyntaxRenderer { - /** - * Renders the [MathSyntax] to [output]. - */ - public fun render(node: MathSyntax, output: Appendable) -} - -/** - * Calls [SyntaxRenderer.render] with given [node] and a new [StringBuilder] instance, and returns its content. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun SyntaxRenderer.renderWithStringBuilder(node: MathSyntax): String { - val sb = StringBuilder() - render(node, sb) - return sb.toString() -} 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 deleted file mode 100644 index a7a28d87f..000000000 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/features.kt +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast.rendering - -import space.kscience.kmath.ast.rendering.FeaturedMathRenderer.RenderFeature -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.reflect.KClass - -/** - * Prints any [Symbol] as a [SymbolSyntax] containing the [Symbol.identity] of it. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public val PrintSymbol: RenderFeature = RenderFeature { _, node -> - if (node !is Symbol) null - else SymbolSyntax(string = node.identity) -} - -/** - * Prints any [MST.Numeric] as a [NumberSyntax] containing the [Any.toString] result of it. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public val PrintNumeric: RenderFeature = RenderFeature { _, node -> - if (node !is MST.Numeric) - null - else - NumberSyntax(string = node.value.toString()) -} - -@UnstableKMathAPI -private fun printSignedNumberString(s: String): MathSyntax = if (s.startsWith('-')) - UnaryMinusSyntax( - operation = GroupOperations.MINUS_OPERATION, - operand = OperandSyntax( - operand = NumberSyntax(string = s.removePrefix("-")), - parentheses = true, - ), - ) -else - NumberSyntax(string = s) - -/** - * Special printing for numeric types that are printed in form of - * *('-'? (DIGIT+ ('.' DIGIT+)? ('E' '-'? DIGIT+)? | 'Infinity')) | 'NaN'*. - * - * @property types The suitable types. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public class PrettyPrintFloats(public val types: Set>) : RenderFeature { - 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) { - is Float -> v.multiplatformToString() - is Double -> v.multiplatformToString() - else -> v.toString() - }.removeSuffix(".0") - - if (toString.contains('E', ignoreCase = true)) { - val (beforeE, afterE) = toString.split('E', ignoreCase = true) - val significand = beforeE.toDouble().toString().removeSuffix(".0") - val exponent = afterE.toDouble().toString().removeSuffix(".0") - - return MultiplicationSyntax( - operation = RingOperations.TIMES_OPERATION, - left = OperandSyntax(operand = NumberSyntax(significand), parentheses = true), - right = OperandSyntax( - operand = SuperscriptSyntax( - operation = PowerOperations.POW_OPERATION, - left = NumberSyntax(string = "10"), - right = printSignedNumberString(exponent), - ), - parentheses = true, - ), - times = true, - ) - } - - if (toString.endsWith("Infinity")) { - val infty = SpecialSymbolSyntax(SpecialSymbolSyntax.Kind.INFINITY) - - if (toString.startsWith('-')) - return UnaryMinusSyntax( - operation = GroupOperations.MINUS_OPERATION, - operand = OperandSyntax(operand = infty, parentheses = true), - ) - - return infty - } - - return printSignedNumberString(toString) - } - - public companion object { - /** - * The default instance containing [Float], and [Double]. - */ - public val Default: PrettyPrintFloats = PrettyPrintFloats(setOf(Float::class, Double::class)) - } -} - -/** - * 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 { - override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = - if (node !is MST.Numeric || node.value::class !in types) - null - else - printSignedNumberString(node.value.toString()) - - public companion object { - /** - * The default instance containing [Byte], [Short], [Int], and [Long]. - */ - public val Default: PrettyPrintIntegers = - PrettyPrintIntegers(setOf(Byte::class, Short::class, Int::class, Long::class)) - } -} - -/** - * Special printing for symbols meaning Pi. - * - * @property symbols The allowed symbols. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public class PrettyPrintPi(public val symbols: Set) : RenderFeature { - override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = - if (node !is Symbol || node.identity !in symbols) - null - else - SpecialSymbolSyntax(kind = SpecialSymbolSyntax.Kind.SMALL_PI) - - public companion object { - /** - * The default instance containing `pi`. - */ - public val Default: PrettyPrintPi = PrettyPrintPi(setOf("pi")) - } -} - -/** - * 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. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public abstract class Unary(public val operations: Collection?) : RenderFeature { - /** - * The actual render function specialized for [MST.Unary]. - */ - protected abstract fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax? - - public final override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? = - if (node !is MST.Unary || operations != null && node.operation !in operations) - null - else - renderUnary(renderer, node) -} - -/** - * 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. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public abstract class Binary(public val operations: Collection?) : RenderFeature { - /** - * The actual render function specialized for [MST.Binary]. - */ - protected abstract fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax? - - public final override fun render(renderer: FeaturedMathRenderer, node: MST): MathSyntax? { - if (node !is MST.Binary || operations != null && node.operation !in operations) return null - return renderBinary(renderer, node) - } -} - -/** - * Handles binary nodes by producing [BinaryPlusSyntax]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public class BinaryPlus(operations: Collection?) : Binary(operations) { - override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = - BinaryPlusSyntax( - operation = node.operation, - left = OperandSyntax(parent.render(node.left), true), - right = OperandSyntax(parent.render(node.right), true), - ) - - public companion object { - /** - * The default instance configured with [GroupOperations.PLUS_OPERATION]. - */ - public val Default: BinaryPlus = BinaryPlus(setOf(GroupOperations.PLUS_OPERATION)) - } -} - -/** - * Handles binary nodes by producing [BinaryMinusSyntax]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public class BinaryMinus(operations: Collection?) : Binary(operations) { - override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = - BinaryMinusSyntax( - operation = node.operation, - left = OperandSyntax(operand = parent.render(node.left), parentheses = true), - right = OperandSyntax(operand = parent.render(node.right), parentheses = true), - ) - - public companion object { - /** - * The default instance configured with [GroupOperations.MINUS_OPERATION]. - */ - public val Default: BinaryMinus = BinaryMinus(setOf(GroupOperations.MINUS_OPERATION)) - } -} - -/** - * Handles unary nodes by producing [UnaryPlusSyntax]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public class UnaryPlus(operations: Collection?) : Unary(operations) { - override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryPlusSyntax( - operation = node.operation, - operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), - ) - - public companion object { - /** - * The default instance configured with [GroupOperations.PLUS_OPERATION]. - */ - public val Default: UnaryPlus = UnaryPlus(setOf(GroupOperations.PLUS_OPERATION)) - } -} - -/** - * Handles binary nodes by producing [UnaryMinusSyntax]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public class UnaryMinus(operations: Collection?) : Unary(operations) { - override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = UnaryMinusSyntax( - operation = node.operation, - operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), - ) - - public companion object { - /** - * The default instance configured with [GroupOperations.MINUS_OPERATION]. - */ - public val Default: UnaryMinus = UnaryMinus(setOf(GroupOperations.MINUS_OPERATION)) - } -} - -/** - * Handles binary nodes by producing [FractionSyntax]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public class Fraction(operations: Collection?) : Binary(operations) { - 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), - infix = true, - ) - - public companion object { - /** - * The default instance configured with [FieldOperations.DIV_OPERATION]. - */ - public val Default: Fraction = Fraction(setOf(FieldOperations.DIV_OPERATION)) - } -} - -/** - * Handles binary nodes by producing [BinaryOperatorSyntax]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public class BinaryOperator(operations: Collection?) : Binary(operations) { - override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = - BinaryOperatorSyntax( - operation = node.operation, - prefix = OperatorNameSyntax(name = node.operation), - left = parent.render(node.left), - right = parent.render(node.right), - ) - - public companion object { - /** - * The default instance configured with `null`. - */ - public val Default: BinaryOperator = BinaryOperator(null) - } -} - -/** - * Handles unary nodes by producing [UnaryOperatorSyntax]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public class UnaryOperator(operations: Collection?) : Unary(operations) { - override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = - UnaryOperatorSyntax( - operation = node.operation, - prefix = OperatorNameSyntax(node.operation), - operand = OperandSyntax(parent.render(node.value), true), - ) - - public companion object { - /** - * The default instance configured with `null`. - */ - public val Default: UnaryOperator = UnaryOperator(null) - } -} - -/** - * Handles binary nodes by producing [SuperscriptSyntax]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public class Power(operations: Collection?) : Binary(operations) { - override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = - SuperscriptSyntax( - operation = node.operation, - left = OperandSyntax(parent.render(node.left), true), - right = OperandSyntax(parent.render(node.right), true), - ) - - public companion object { - /** - * The default instance configured with [PowerOperations.POW_OPERATION]. - */ - public val Default: Power = Power(setOf(PowerOperations.POW_OPERATION)) - } -} - -/** - * Handles binary nodes by producing [RadicalSyntax] with no index. - */ -@UnstableKMathAPI -public class SquareRoot(operations: Collection?) : Unary(operations) { - override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = - RadicalSyntax(operation = node.operation, operand = parent.render(node.value)) - - public companion object { - /** - * The default instance configured with [PowerOperations.SQRT_OPERATION]. - */ - public val Default: SquareRoot = SquareRoot(setOf(PowerOperations.SQRT_OPERATION)) - } -} - -/** - * Handles unary nodes by producing [ExponentSyntax]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public class Exponent(operations: Collection?) : Unary(operations) { - override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = ExponentSyntax( - operation = node.operation, - operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), - useOperatorForm = true, - ) - - public companion object { - /** - * The default instance configured with [ExponentialOperations.EXP_OPERATION]. - */ - public val Default: Exponent = Exponent(setOf(ExponentialOperations.EXP_OPERATION)) - } -} - -/** - * Handles binary nodes by producing [MultiplicationSyntax]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public class Multiplication(operations: Collection?) : Binary(operations) { - override fun renderBinary(parent: FeaturedMathRenderer, node: MST.Binary): MathSyntax = - MultiplicationSyntax( - operation = node.operation, - left = OperandSyntax(operand = parent.render(node.left), parentheses = true), - right = OperandSyntax(operand = parent.render(node.right), parentheses = true), - times = true, - ) - - public companion object { - /** - * The default instance configured with [RingOperations.TIMES_OPERATION]. - */ - public val Default: Multiplication = Multiplication(setOf(RingOperations.TIMES_OPERATION)) - } -} - -/** - * Handles binary nodes by producing inverse [UnaryOperatorSyntax] with *arc* prefix instead of *a*. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public class InverseTrigonometricOperations(operations: Collection?) : Unary(operations) { - override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = - UnaryOperatorSyntax( - operation = node.operation, - prefix = OperatorNameSyntax(name = node.operation.replaceFirst("a", "arc")), - operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), - ) - - public companion object { - /** - * The default instance configured with [TrigonometricOperations.ACOS_OPERATION], - * [TrigonometricOperations.ASIN_OPERATION], [TrigonometricOperations.ATAN_OPERATION]. - */ - public val Default: InverseTrigonometricOperations = InverseTrigonometricOperations(setOf( - TrigonometricOperations.ACOS_OPERATION, - TrigonometricOperations.ASIN_OPERATION, - TrigonometricOperations.ATAN_OPERATION, - )) - } -} - -/** - * Handles binary nodes by producing inverse [UnaryOperatorSyntax] with *ar* prefix instead of *a*. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public class InverseHyperbolicOperations(operations: Collection?) : Unary(operations) { - override fun renderUnary(parent: FeaturedMathRenderer, node: MST.Unary): MathSyntax = - UnaryOperatorSyntax( - operation = node.operation, - prefix = OperatorNameSyntax(name = node.operation.replaceFirst("a", "ar")), - operand = OperandSyntax(operand = parent.render(node.value), parentheses = true), - ) - - public companion object { - /** - * The default instance configured with [ExponentialOperations.ACOSH_OPERATION], - * [ExponentialOperations.ASINH_OPERATION], and [ExponentialOperations.ATANH_OPERATION]. - */ - public val Default: InverseHyperbolicOperations = InverseHyperbolicOperations(setOf( - ExponentialOperations.ACOSH_OPERATION, - ExponentialOperations.ASINH_OPERATION, - ExponentialOperations.ATANH_OPERATION, - )) - } -} diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt deleted file mode 100644 index 3e33d6415..000000000 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast.rendering - -internal expect fun Double.multiplatformToString(): String -internal expect fun Float.multiplatformToString(): String diff --git a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt deleted file mode 100644 index 3d05e03d6..000000000 --- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/phases.kt +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.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 -import space.kscience.kmath.operations.PowerOperations -import space.kscience.kmath.operations.RingOperations - -/** - * Removes unnecessary times (×) symbols from [MultiplicationSyntax]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public val BetterMultiplication: PostProcessPhase = PostProcessPhase { node -> - fun perform(node: MathSyntax): Unit = when (node) { - is NumberSyntax -> Unit - is SymbolSyntax -> Unit - is OperatorNameSyntax -> Unit - is SpecialSymbolSyntax -> Unit - 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 -> perform(node.operand) - is ExponentSyntax -> perform(node.operand) - - is SuperscriptSyntax -> { - perform(node.left) - perform(node.right) - } - - is SubscriptSyntax -> { - perform(node.left) - perform(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 -> { - perform(node.left) - perform(node.right) - } - - is RadicalWithIndexSyntax -> { - perform(node.left) - perform(node.right) - } - - is MultiplicationSyntax -> { - node.times = node.right.operand is NumberSyntax && !node.right.parentheses - || node.left.operand is NumberSyntax && node.right.operand is FractionSyntax - || node.left.operand is NumberSyntax && node.right.operand is NumberSyntax - || node.left.operand is NumberSyntax && node.right.operand is SuperscriptSyntax && node.right.operand.left is NumberSyntax - - perform(node.left) - perform(node.right) - } - } - - perform(node) -} - -/** - * Chooses [FractionSyntax.infix] depending on the context. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -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 -> perform(node.operand, infix) - - is UnaryOperatorSyntax -> { - perform(node.prefix, infix) - perform(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 -> { - perform(node.left, true) - perform(node.right, true) - } - - is SubscriptSyntax -> { - perform(node.left, true) - perform(node.right, true) - } - - is BinaryOperatorSyntax -> { - perform(node.prefix, infix) - perform(node.left, infix) - perform(node.right, infix) - } - - is BinaryPlusSyntax -> { - perform(node.left, infix) - perform(node.right, infix) - } - - is BinaryMinusSyntax -> { - perform(node.left, infix) - perform(node.right, infix) - } - - is FractionSyntax -> { - node.infix = infix - perform(node.left, infix) - perform(node.right, infix) - } - - is RadicalWithIndexSyntax -> { - perform(node.left, true) - perform(node.right, true) - } - - is MultiplicationSyntax -> { - perform(node.left, infix) - perform(node.right, infix) - } - } - - perform(node) -} - -/** - * Applies [ExponentSyntax.useOperatorForm] to [ExponentSyntax] when the operand contains a fraction, a - * superscript or a subscript to improve readability. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -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 -> 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 = perform(node.operand) - node.useOperatorForm = r - r - } - - is SuperscriptSyntax -> true - is SubscriptSyntax -> true - 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 -> perform(node.left) || perform(node.right) - } - } - - perform(node) -} - -/** - * Removes unnecessary parentheses from [OperandSyntax]. - * - * @property precedenceFunction Returns the precedence number for syntax node. Higher number is lower priority. - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public class SimplifyParentheses(public val precedenceFunction: (MathSyntax) -> Int) : - PostProcessPhase { - override fun perform(node: MathSyntax): Unit = when (node) { - is NumberSyntax -> Unit - is SymbolSyntax -> Unit - is OperatorNameSyntax -> Unit - is SpecialSymbolSyntax -> Unit - - is OperandSyntax -> { - val isRightOfSuperscript = - (node.parent is SuperscriptSyntax) && (node.parent as SuperscriptSyntax).right === node - - val precedence = precedenceFunction(node.operand) - - val needParenthesesByPrecedence = when (val parent = node.parent) { - null -> false - - is BinarySyntax -> { - val parentPrecedence = precedenceFunction(parent) - - parentPrecedence < precedence || - parentPrecedence == precedence && parentPrecedence != 0 && node === parent.right - } - - else -> precedence > precedenceFunction(parent) - } - - val isInsideExpOperator = - node.parent is ExponentSyntax && (node.parent as ExponentSyntax).useOperatorForm - - val isOnOrUnderNormalFraction = node.parent is FractionSyntax && !((node.parent as FractionSyntax).infix) - - node.parentheses = !isRightOfSuperscript - && (needParenthesesByPrecedence || node.parent is UnaryOperatorSyntax || isInsideExpOperator) - && !isOnOrUnderNormalFraction - - perform(node.operand) - } - - is UnaryOperatorSyntax -> { - perform(node.prefix) - perform(node.operand) - } - - is UnaryPlusSyntax -> perform(node.operand) - is UnaryMinusSyntax -> perform(node.operand) - is RadicalSyntax -> perform(node.operand) - is ExponentSyntax -> perform(node.operand) - - is SuperscriptSyntax -> { - perform(node.left) - perform(node.right) - } - - is SubscriptSyntax -> { - perform(node.left) - perform(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 -> { - perform(node.left) - perform(node.right) - } - - is MultiplicationSyntax -> { - perform(node.left) - perform(node.right) - } - - is RadicalWithIndexSyntax -> { - perform(node.left) - perform(node.right) - } - } - - public companion object { - /** - * The default configuration of [SimplifyParentheses] where power is 1, multiplicative operations are 2, - * additive operations are 3. - */ - public val Default: SimplifyParentheses = SimplifyParentheses { - when (it) { - is TerminalSyntax -> 0 - is UnarySyntax -> 2 - - is BinarySyntax -> when (it.operation) { - PowerOperations.POW_OPERATION -> 1 - RingOperations.TIMES_OPERATION -> 3 - FieldOperations.DIV_OPERATION -> 3 - GroupOperations.MINUS_OPERATION -> 4 - GroupOperations.PLUS_OPERATION -> 4 - else -> 0 - } - - else -> 0 - } - } - } -} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt deleted file mode 100644 index 802d4c10e..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerConsistencyWithInterpreter.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.MstField -import space.kscience.kmath.expressions.MstRing -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.invoke -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class TestCompilerConsistencyWithInterpreter { - @Test - fun intRing() = runCompilerTest { - val mst = MstRing { - binaryOperationFunction("+")( - unaryOperationFunction("+")( - (x - (2.toByte() + (scale( - add(number(1), number(1)), - 2.0, - ) + 1.toByte()))) * 3.0 - 1.toByte() - ), - - number(1), - ) * number(2) - } - - assertEquals( - mst.interpret(IntRing, x to 3), - mst.compile(IntRing, x to 3), - ) - } - - @Test - fun doubleField() = runCompilerTest { - val mst = MstField { - +(3 - 2 + 2 * number(1) + 1.0) + binaryOperationFunction("+")( - (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 - } - - assertEquals( - mst.interpret(DoubleField, x to 2.0), - mst.compile(DoubleField, x to 2.0), - ) - } -} 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 deleted file mode 100644 index f5b1e2842..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerOperations.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast - -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.invoke -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class TestCompilerOperations { - @Test - fun testUnaryPlus() = runCompilerTest { - val expr = MstExtendedField { +x }.compileToExpression(DoubleField) - assertEquals(2.0, expr(x to 2.0)) - } - - @Test - fun testUnaryMinus() = runCompilerTest { - val expr = MstExtendedField { -x }.compileToExpression(DoubleField) - assertEquals(-2.0, expr(x to 2.0)) - } - - @Test - fun testAdd() = runCompilerTest { - val expr = MstExtendedField { x + x }.compileToExpression(DoubleField) - assertEquals(4.0, expr(x to 2.0)) - } - - @Test - fun testSine() = runCompilerTest { - val expr = MstExtendedField { sin(x) }.compileToExpression(DoubleField) - assertEquals(0.0, expr(x to 0.0)) - } - - @Test - fun testCosine() = runCompilerTest { - val expr = MstExtendedField { cos(x) }.compileToExpression(DoubleField) - assertEquals(1.0, expr(x to 0.0)) - } - - @Test - fun testSubtract() = runCompilerTest { - val expr = MstExtendedField { x - x }.compileToExpression(DoubleField) - assertEquals(0.0, expr(x to 2.0)) - } - - @Test - fun testDivide() = runCompilerTest { - val expr = MstExtendedField { x / x }.compileToExpression(DoubleField) - assertEquals(1.0, expr(x to 2.0)) - } - - @Test - fun testPower() = runCompilerTest { - 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 deleted file mode 100644 index 8d9a2301f..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestCompilerVariables.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.MstRing -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.operations.invoke -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFailsWith - -internal class TestCompilerVariables { - @Test - fun testVariable() = runCompilerTest { - val expr = MstRing { x }.compileToExpression(IntRing) - assertEquals(1, expr(x to 1)) - } - - @Test - fun testUndefinedVariableFails() = runCompilerTest { - val expr = MstRing { x }.compileToExpression(IntRing) - assertFailsWith { expr() } - } -} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt deleted file mode 100644 index 4c834a9ca..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParser.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.complex.Complex -import space.kscience.kmath.complex.ComplexField -import space.kscience.kmath.expressions.evaluate -import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.DoubleField -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class TestParser { - @Test - fun evaluateParsedMst() { - val mst = "2+2*(2+2)".parseMath() - val res = ComplexField.evaluate(mst) - assertEquals(Complex(10.0, 0.0), res) - } - - @Test - fun evaluateMstSymbol() { - val mst = "i".parseMath() - val res = ComplexField.evaluate(mst) - assertEquals(ComplexField.i, res) - } - - - @Test - fun evaluateMstUnary() { - val mst = "sin(0)".parseMath() - val res = DoubleField.evaluate(mst) - assertEquals(0.0, res) - } - - @Test - fun evaluateMstBinary() { - val magicalAlgebra = object : Algebra { - override fun bindSymbolOrNull(value: String): String = value - - override fun unaryOperationFunction(operation: String): (arg: String) -> String { - throw NotImplementedError() - } - - override fun binaryOperationFunction(operation: String): (left: String, right: String) -> String = - when (operation) { - "magic" -> { left, right -> "$left ★ $right" } - else -> throw NotImplementedError() - } - } - - val mst = "magic(a, b)".parseMath() - val res = magicalAlgebra.evaluate(mst) - assertEquals("a ★ b", res) - } -} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt deleted file mode 100644 index 9776da45c..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/TestParserPrecedence.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.evaluate -import space.kscience.kmath.operations.DoubleField -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class TestParserPrecedence { - @Test - fun test1(): Unit = assertEquals(6.0, f.evaluate("2*2+2".parseMath())) - - @Test - fun test2(): Unit = assertEquals(6.0, f.evaluate("2+2*2".parseMath())) - - @Test - fun test3(): Unit = assertEquals(10.0, f.evaluate("2^3+2".parseMath())) - - @Test - fun test4(): Unit = assertEquals(10.0, f.evaluate("2+2^3".parseMath())) - - @Test - fun test5(): Unit = assertEquals(16.0, f.evaluate("2^3*2".parseMath())) - - @Test - fun test6(): Unit = assertEquals(16.0, f.evaluate("2*2^3".parseMath())) - - @Test - fun test7(): Unit = assertEquals(18.0, f.evaluate("2+2^3*2".parseMath())) - - @Test - fun test8(): Unit = assertEquals(18.0, f.evaluate("2*2^3+2".parseMath())) - - private companion object { - private val f = DoubleField - } -} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt deleted file mode 100644 index ae429d97e..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestFeatures.kt +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast.rendering - -import space.kscience.kmath.ast.rendering.TestUtils.testLatex -import space.kscience.kmath.expressions.MST.Numeric -import kotlin.test.Test - -internal class TestFeatures { - @Test - fun printSymbolic() = testLatex("x", "x") - - @Test - fun printNumeric() { - val num = object : Number() { - override fun toByte(): Byte = throw UnsupportedOperationException() - override fun toChar(): Char = throw UnsupportedOperationException() - override fun toDouble(): Double = throw UnsupportedOperationException() - override fun toFloat(): Float = throw UnsupportedOperationException() - override fun toInt(): Int = throw UnsupportedOperationException() - override fun toLong(): Long = throw UnsupportedOperationException() - override fun toShort(): Short = throw UnsupportedOperationException() - override fun toString(): String = "foo" - } - - testLatex(Numeric(num), "foo") - } - - @Test - fun prettyPrintFloats() { - testLatex(Numeric(Double.NaN), "NaN") - testLatex(Numeric(Double.POSITIVE_INFINITY), "\\infty") - testLatex(Numeric(Double.NEGATIVE_INFINITY), "-\\infty") - testLatex(Numeric(1.0), "1") - testLatex(Numeric(-1.0), "-1") - testLatex(Numeric(1.42), "1.42") - testLatex(Numeric(-1.42), "-1.42") - testLatex(Numeric(1.1e10), "1.1\\times10^{10}") - testLatex(Numeric(1.1e-10), "1.1\\times10^{-10}") - testLatex(Numeric(-1.1e-10), "-1.1\\times10^{-10}") - testLatex(Numeric(-1.1e10), "-1.1\\times10^{10}") - testLatex(Numeric(0.001), "0.001") - testLatex(Numeric(0.0000001), "1\\times10^{-7}") - - testLatex(Numeric(Float.NaN), "NaN") - testLatex(Numeric(Float.POSITIVE_INFINITY), "\\infty") - testLatex(Numeric(Float.NEGATIVE_INFINITY), "-\\infty") - testLatex(Numeric(1.0f), "1") - testLatex(Numeric(-1.0f), "-1") - testLatex(Numeric(1.42f), "1.42") - testLatex(Numeric(-1.42f), "-1.42") - testLatex(Numeric(1e10f), "1\\times10^{10}") - testLatex(Numeric(1e-10f), "1\\times10^{-10}") - testLatex(Numeric(-1e-10f), "-1\\times10^{-10}") - testLatex(Numeric(-1e10f), "-1\\times10^{10}") - testLatex(Numeric(0.001f), "0.001") - testLatex(Numeric(0.0000001f), "1\\times10^{-7}") - } - - @Test - fun prettyPrintIntegers() { - testLatex(Numeric(42), "42") - testLatex(Numeric(-42), "-42") - } - - @Test - fun prettyPrintPi() { - testLatex("pi", "\\pi") - } - - @Test - fun binaryPlus() = testLatex("2+2", "2+2") - - @Test - fun binaryMinus() = testLatex("2-2", "2-2") - - @Test - fun fraction() = testLatex("2/2", "\\frac{2}{2}") - - @Test - fun binaryOperator() = testLatex("f(x, y)", "\\operatorname{f}\\left(x,y\\right)") - - @Test - fun unaryOperator() = testLatex("f(x)", "\\operatorname{f}\\,\\left(x\\right)") - - @Test - fun power() = testLatex("x^y", "x^{y}") - - @Test - fun squareRoot() = testLatex("sqrt(x)", "\\sqrt{x}") - - @Test - fun exponential() = testLatex("exp(x)", "e^{x}") - - @Test - fun multiplication() = testLatex("x*1", "x\\times1") - - @Test - fun inverseTrigonometric() { - testLatex("asin(x)", "\\operatorname{arcsin}\\,\\left(x\\right)") - testLatex("acos(x)", "\\operatorname{arccos}\\,\\left(x\\right)") - testLatex("atan(x)", "\\operatorname{arctan}\\,\\left(x\\right)") - } - - @Test - fun inverseHyperbolic() { - testLatex("asinh(x)", "\\operatorname{arsinh}\\,\\left(x\\right)") - testLatex("acosh(x)", "\\operatorname{arcosh}\\,\\left(x\\right)") - testLatex("atanh(x)", "\\operatorname{artanh}\\,\\left(x\\right)") - } - -// @Test -// fun unaryPlus() { -// testLatex("+1", "+1") -// testLatex("+1", "++1") -// } -} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt deleted file mode 100644 index d8e432230..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestLatex.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast.rendering - -import space.kscience.kmath.ast.rendering.TestUtils.testLatex -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.operations.GroupOperations -import kotlin.test.Test - -internal class TestLatex { - @Test - fun number() = testLatex("42", "42") - - @Test - fun symbol() = testLatex("x", "x") - - @Test - fun operatorName() = testLatex("sin(1)", "\\operatorname{sin}\\,\\left(1\\right)") - - @Test - fun specialSymbol() { - testLatex(MST.Numeric(Double.POSITIVE_INFINITY), "\\infty") - testLatex("pi", "\\pi") - } - - @Test - fun operand() { - testLatex("sin(1)", "\\operatorname{sin}\\,\\left(1\\right)") - testLatex("1+1", "1+1") - } - - @Test - fun unaryOperator() = testLatex("sin(1)", "\\operatorname{sin}\\,\\left(1\\right)") - - @Test - fun unaryPlus() = testLatex(MST.Unary(GroupOperations.PLUS_OPERATION, MST.Numeric(1)), "+1") - - @Test - fun unaryMinus() = testLatex("-x", "-x") - - @Test - fun radical() = testLatex("sqrt(x)", "\\sqrt{x}") - - @Test - fun superscript() = testLatex("x^y", "x^{y}") - - @Test - fun subscript() = testLatex(SubscriptSyntax("", SymbolSyntax("x"), NumberSyntax("123")), "x_{123}") - - @Test - fun binaryOperator() = testLatex("f(x, y)", "\\operatorname{f}\\left(x,y\\right)") - - @Test - fun binaryPlus() = testLatex("x+x", "x+x") - - @Test - fun binaryMinus() = testLatex("x-x", "x-x") - - @Test - fun fraction() = testLatex("x/x", "\\frac{x}{x}") - - @Test - fun radicalWithIndex() = testLatex(RadicalWithIndexSyntax("", SymbolSyntax("x"), SymbolSyntax("y")), "\\sqrt[x]{y}") - - @Test - fun multiplication() { - testLatex("x*1", "x\\times1") - testLatex("1*x", "1\\,x") - } -} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt deleted file mode 100644 index a7fcbc75b..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestMathML.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast.rendering - -import space.kscience.kmath.ast.rendering.TestUtils.testMathML -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.operations.GroupOperations -import kotlin.test.Test - -internal class TestMathML { - @Test - fun number() = testMathML("42", "42") - - @Test - fun symbol() = testMathML("x", "x") - - @Test - fun operatorName() = testMathML( - "sin(1)", - "sin1", - ) - - @Test - fun specialSymbol() { - testMathML(MST.Numeric(Double.POSITIVE_INFINITY), "") - testMathML("pi", "π") - } - - @Test - fun operand() { - testMathML( - "sin(1)", - "sin1", - ) - - testMathML("1+1", "1+1") - } - - @Test - fun unaryOperator() = testMathML( - "sin(1)", - "sin1", - ) - - @Test - fun unaryPlus() = - testMathML(MST.Unary(GroupOperations.PLUS_OPERATION, MST.Numeric(1)), "+1") - - @Test - fun unaryMinus() = testMathML("-x", "-x") - - @Test - fun radical() = testMathML("sqrt(x)", "x") - - @Test - fun superscript() = testMathML("x^y", "xy") - - @Test - fun subscript() = testMathML( - SubscriptSyntax("", SymbolSyntax("x"), NumberSyntax("123")), - "x123", - ) - - @Test - fun binaryOperator() = testMathML( - "f(x, y)", - "fx,y", - ) - - @Test - fun binaryPlus() = testMathML("x+x", "x+x") - - @Test - fun binaryMinus() = testMathML("x-x", "x-x") - - @Test - fun fraction() = testMathML("x/x", "xx") - - @Test - fun radicalWithIndex() = - testMathML(RadicalWithIndexSyntax("", SymbolSyntax("x"), SymbolSyntax("y")), - "yx") - - @Test - fun multiplication() { - testMathML("x*1", "x×1") - testMathML("1*x", "1x") - } -} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt deleted file mode 100644 index 4485605a6..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestStages.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast.rendering - -import space.kscience.kmath.ast.rendering.TestUtils.testLatex -import kotlin.test.Test - -internal class TestStages { - @Test - fun betterMultiplication() { - testLatex("a*1", "a\\times1") - testLatex("1*(2/3)", "1\\times\\left(\\frac{2}{3}\\right)") - testLatex("1*1", "1\\times1") - testLatex("2e10", "2\\times10^{10}") - testLatex("2*x", "2\\,x") - testLatex("2*(x+1)", "2\\,\\left(x+1\\right)") - testLatex("x*y", "x\\,y") - } - - @Test - fun parentheses() { - testLatex("(x+1)", "x+1") - testLatex("x*x*x", "x\\,x\\,x") - testLatex("(x+x)*x", "\\left(x+x\\right)\\,x") - testLatex("x+x*x", "x+x\\,x") - testLatex("x+x^x*x+x", "x+x^{x}\\,x+x") - testLatex("(x+x)^x+x*x", "\\left(x+x\\right)^{x}+x\\,x") - testLatex("x^(x+x)", "x^{x+x}") - } - - @Test - fun exponent() { - testLatex("exp(x)", "e^{x}") - testLatex("exp(x/2)", "\\operatorname{exp}\\,\\left(\\frac{x}{2}\\right)") - testLatex("exp(x^2)", "\\operatorname{exp}\\,\\left(x^{2}\\right)") - } - - @Test - fun fraction() { - testLatex("x/y", "\\frac{x}{y}") - testLatex("x^(x/y)", "x^{x/y}") - } -} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt deleted file mode 100644 index 6b418821b..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/rendering/TestUtils.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast.rendering - -import space.kscience.kmath.ast.parseMath -import space.kscience.kmath.expressions.MST -import kotlin.test.assertEquals - -internal object TestUtils { - private fun mathSyntax(mst: MST) = FeaturedMathRendererWithPostProcess.Default.render(mst) - private fun latex(mst: MST) = LatexSyntaxRenderer.renderWithStringBuilder(mathSyntax(mst)) - private fun mathML(mst: MST) = MathMLSyntaxRenderer.renderWithStringBuilder(mathSyntax(mst)) - - internal fun testLatex(mst: MST, expectedLatex: String) = assertEquals( - expected = expectedLatex, - actual = latex(mst), - ) - - internal fun testLatex(expression: String, expectedLatex: String) = assertEquals( - expected = expectedLatex, - actual = latex(expression.parseMath()), - ) - - internal fun testLatex(expression: MathSyntax, expectedLatex: String) = assertEquals( - expected = expectedLatex, - actual = LatexSyntaxRenderer.renderWithStringBuilder(expression), - ) - - internal fun testMathML(mst: MST, expectedMathML: String) = assertEquals( - expected = "$expectedMathML", - actual = mathML(mst), - ) - - internal fun testMathML(expression: String, expectedMathML: String) = assertEquals( - expected = "$expectedMathML", - actual = mathML(expression.parseMath()), - ) - - internal fun testMathML(expression: MathSyntax, expectedMathML: String) = assertEquals( - expected = "$expectedMathML", - actual = MathMLSyntaxRenderer.renderWithStringBuilder(expression), - ) -} diff --git a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt deleted file mode 100644 index ef9f3145a..000000000 --- a/kmath-ast/src/commonTest/kotlin/space/kscience/kmath/ast/utils.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.IntRing - -internal interface CompilerTestContext { - fun MST.compileToExpression(algebra: IntRing): Expression - fun MST.compile(algebra: IntRing, arguments: Map): Int - fun MST.compile(algebra: IntRing, vararg arguments: Pair): Int = compile(algebra, mapOf(*arguments)) - fun MST.compileToExpression(algebra: DoubleField): Expression - fun MST.compile(algebra: DoubleField, arguments: Map): Double - - fun MST.compile(algebra: DoubleField, vararg arguments: Pair): Double = - compile(algebra, mapOf(*arguments)) -} - -internal expect inline fun runCompilerTest(action: CompilerTestContext.() -> Unit) diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt deleted file mode 100644 index 2e69a536f..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.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 file. - */ - -package space.kscience.kmath.ast.rendering - -internal actual fun Double.multiplatformToString(): String { - val d = this - if (d >= 1e7 || d <= -1e7) return js("d.toExponential()") as String - return toString() -} - -internal actual fun Float.multiplatformToString(): String { - val d = this - if (d >= 1e7f || d <= -1e7f) return js("d.toExponential()") as String - return toString() -} diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt deleted file mode 100644 index 316fdeeff..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/estree.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.estree - -import space.kscience.kmath.estree.internal.ESTreeBuilder -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.MST.* -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.internal.estree.BaseExpression -import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.NumericAlgebra -import space.kscience.kmath.operations.bindSymbolOrNull - -@PublishedApi -internal fun MST.compileWith(algebra: Algebra): Expression { - fun ESTreeBuilder.visit(node: MST): BaseExpression = when (node) { - is Symbol -> { - val symbol = algebra.bindSymbolOrNull(node) - - if (symbol != null) - constant(symbol) - else - variable(node.identity) - } - - is Numeric -> constant(node.value) - - is Unary -> when { - algebra is NumericAlgebra && node.value is Numeric -> constant( - algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value))) - - else -> call(algebra.unaryOperationFunction(node.operation), visit(node.value)) - } - - is Binary -> when { - algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> constant( - algebra.binaryOperationFunction(node.operation).invoke( - algebra.number((node.left as Numeric).value), - algebra.number((node.right as Numeric).value) - ) - ) - - algebra is NumericAlgebra && node.left is Numeric -> call( - algebra.leftSideNumberOperationFunction(node.operation), - visit(node.left), - visit(node.right), - ) - - algebra is NumericAlgebra && node.right is Numeric -> call( - algebra.rightSideNumberOperationFunction(node.operation), - visit(node.left), - visit(node.right), - ) - - else -> call( - algebra.binaryOperationFunction(node.operation), - visit(node.left), - visit(node.right), - ) - } - } - - return ESTreeBuilder { visit(this@compileWith) }.instance -} - -/** - * Create a compiled expression with given [MST] and given [algebra]. - */ -public fun MST.compileToExpression(algebra: Algebra): Expression = compileWith(algebra) - - -/** - * Compile given MST to expression and evaluate it against [arguments] - */ -public inline fun MST.compile(algebra: Algebra, arguments: Map): T = - compileToExpression(algebra).invoke(arguments) - - -/** - * Compile given MST to expression and evaluate it against [arguments] - */ -public inline fun MST.compile(algebra: Algebra, vararg arguments: Pair): T = - compileToExpression(algebra).invoke(*arguments) diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt deleted file mode 100644 index 850f20be7..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/ESTreeBuilder.kt +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.estree.internal - -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.internal.astring.generate -import space.kscience.kmath.internal.estree.* - -internal class ESTreeBuilder(val bodyCallback: ESTreeBuilder.() -> BaseExpression) { - private class GeneratedExpression(val executable: dynamic, val constants: Array) : Expression { - @Suppress("UNUSED_VARIABLE") - override fun invoke(arguments: Map): T { - val e = executable - val c = constants - val a = js("{}") - arguments.forEach { (key, value) -> a[key.identity] = value } - return js("e(c, a)").unsafeCast() - } - } - - val instance: Expression by lazy { - val node = Program( - sourceType = "script", - VariableDeclaration( - kind = "var", - VariableDeclarator( - id = Identifier("executable"), - init = FunctionExpression( - params = arrayOf(Identifier("constants"), Identifier("arguments")), - body = BlockStatement(ReturnStatement(bodyCallback())), - ), - ), - ), - ) - - eval(generate(node)) - GeneratedExpression(js("executable"), constants.toTypedArray()) - } - - private val constants = mutableListOf() - - fun constant(value: Any?) = when { - value == null || jsTypeOf(value) == "number" || jsTypeOf(value) == "string" || jsTypeOf(value) == "boolean" -> - SimpleLiteral(value) - - jsTypeOf(value) == "undefined" -> Identifier("undefined") - - else -> { - val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex - - MemberExpression( - computed = true, - optional = false, - `object` = Identifier("constants"), - property = SimpleLiteral(idx), - ) - } - } - - fun variable(name: String): BaseExpression = call(getOrFail, Identifier("arguments"), SimpleLiteral(name)) - - fun call(function: Function, vararg args: BaseExpression): BaseExpression = SimpleCallExpression( - optional = false, - callee = constant(function), - *args, - ) - - private companion object { - @Suppress("UNUSED_VARIABLE") - val getOrFail: (`object`: dynamic, key: String) -> dynamic = { `object`, key -> - val k = key - val o = `object` - - if (!(js("k in o") as Boolean)) - throw NoSuchElementException("Key $key is missing in the map.") - - js("o[k]") - } - } -} diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt deleted file mode 100644 index c7faf73e0..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/estree/internal/astring/astring.typealises.kt +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.estree.internal.astring - -internal typealias Generator = Any diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt deleted file mode 100644 index c36860654..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -@file:JsModule("astring") -@file:JsNonModule - -package space.kscience.kmath.internal.astring - -import space.kscience.kmath.internal.estree.BaseNode - -internal external interface Options { - var indent: String? - get() = definedExternally - set(value) = definedExternally - var lineEnd: String? - get() = definedExternally - set(value) = definedExternally - var startingIndentLevel: Number? - get() = definedExternally - set(value) = definedExternally - var comments: Boolean? - get() = definedExternally - set(value) = definedExternally - var generator: Any? - get() = definedExternally - set(value) = definedExternally - var sourceMap: Any? - get() = definedExternally - set(value) = definedExternally -} - -internal external fun generate(node: BaseNode, options: Options /* Options & `T$0` */ = definedExternally): String - -internal external fun generate(node: BaseNode): String - -internal external var baseGenerator: Generator diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt deleted file mode 100644 index 0a5b059ba..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/astring/astring.typealises.kt +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.internal.astring - -internal typealias Generator = Any diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt deleted file mode 100644 index 26186c453..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/base64/base64.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -@file:Suppress( - "INTERFACE_WITH_SUPERCLASS", - "OVERRIDING_FINAL_MEMBER", - "RETURN_TYPE_MISMATCH_ON_OVERRIDE", - "CONFLICTING_OVERLOADS", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", - "ObjectPropertyName", - "ClassName", -) -@file:JsNonModule -@file:JsModule("js-base64") - -package space.kscience.kmath.internal.base64 - -import org.khronos.webgl.Uint8Array - -internal external var version: Any - -internal external var VERSION: Any - -internal external var btoaPolyfill: (bin: String) -> String - -internal external var _btoa: (bin: String) -> String - -internal external var fromUint8Array: (u8a: Uint8Array, urlsafe: Boolean) -> String - -internal external var utob: (u: String) -> String - -internal external var encode: (src: String, urlsafe: Boolean) -> String - -internal external var encodeURI: (src: String) -> String - -internal external var btou: (b: String) -> String - -internal external var atobPolyfill: (asc: String) -> String - -internal external var _atob: (asc: String) -> String - -internal external var toUint8Array: (a: String) -> Uint8Array - -internal external var decode: (src: String) -> String - -internal external var isValid: (src: Any) -> Boolean - -internal external var extendString: () -> Unit - -internal external var extendUint8Array: () -> Unit - -internal external var extendBuiltins: () -> Unit diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt deleted file mode 100644 index 13e3a49e2..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.kt +++ /dev/null @@ -1,2239 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -@file:Suppress( - "INTERFACE_WITH_SUPERCLASS", - "OVERRIDING_FINAL_MEMBER", - "RETURN_TYPE_MISMATCH_ON_OVERRIDE", - "CONFLICTING_OVERLOADS", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", - "PropertyName", - "ClassName", -) - -@file:JsModule("binaryen") -@file:JsNonModule - -package space.kscience.kmath.internal.binaryen - -import org.khronos.webgl.Uint8Array -import kotlin.js.Promise - -internal external var isReady: Boolean - -internal external var ready: Promise - -internal external var none: Type - -internal external var i32: Type - -internal external var i64: Type - -internal external var f32: Type - -internal external var f64: Type - -internal external var v128: Type - -internal external var funcref: Type - -internal external var anyref: Type - -internal external var nullref: Type - -internal external var exnref: Type - -internal external var unreachable: Type - -internal external var auto: Type - -internal external fun createType(types: Array): Type - -internal external fun expandType(type: Type): Array - -internal external enum class ExpressionIds { - Invalid, - Block, - If, - Loop, - Break, - Switch, - Call, - CallIndirect, - LocalGet, - LocalSet, - GlobalGet, - GlobalSet, - Load, - Store, - Const, - Unary, - Binary, - Select, - Drop, - Return, - Host, - Nop, - Unreachable, - AtomicCmpxchg, - AtomicRMW, - AtomicWait, - AtomicNotify, - AtomicFence, - SIMDExtract, - SIMDReplace, - SIMDShuffle, - SIMDTernary, - SIMDShift, - SIMDLoad, - MemoryInit, - DataDrop, - MemoryCopy, - MemoryFill, - RefNull, - RefIsNull, - RefFunc, - Try, - Throw, - Rethrow, - BrOnExn, - TupleMake, - TupleExtract, - Push, - Pop -} - -internal external var InvalidId: ExpressionIds - -internal external var BlockId: ExpressionIds - -internal external var IfId: ExpressionIds - -internal external var LoopId: ExpressionIds - -internal external var BreakId: ExpressionIds - -internal external var SwitchId: ExpressionIds - -internal external var CallId: ExpressionIds - -internal external var CallIndirectId: ExpressionIds - -internal external var LocalGetId: ExpressionIds - -internal external var LocalSetId: ExpressionIds - -internal external var GlobalGetId: ExpressionIds - -internal external var GlobalSetId: ExpressionIds - -internal external var LoadId: ExpressionIds - -internal external var StoreId: ExpressionIds - -internal external var ConstId: ExpressionIds - -internal external var UnaryId: ExpressionIds - -internal external var BinaryId: ExpressionIds - -internal external var SelectId: ExpressionIds - -internal external var DropId: ExpressionIds - -internal external var ReturnId: ExpressionIds - -internal external var HostId: ExpressionIds - -internal external var NopId: ExpressionIds - -internal external var UnreachableId: ExpressionIds - -internal external var AtomicCmpxchgId: ExpressionIds - -internal external var AtomicRMWId: ExpressionIds - -internal external var AtomicWaitId: ExpressionIds - -internal external var AtomicNotifyId: ExpressionIds - -internal external var AtomicFenceId: ExpressionIds - -internal external var SIMDExtractId: ExpressionIds - -internal external var SIMDReplaceId: ExpressionIds - -internal external var SIMDShuffleId: ExpressionIds - -internal external var SIMDTernaryId: ExpressionIds - -internal external var SIMDShiftId: ExpressionIds - -internal external var SIMDLoadId: ExpressionIds - -internal external var MemoryInitId: ExpressionIds - -internal external var DataDropId: ExpressionIds - -internal external var MemoryCopyId: ExpressionIds - -internal external var MemoryFillId: ExpressionIds - -internal external var RefNullId: ExpressionIds - -internal external var RefIsNullId: ExpressionIds - -internal external var RefFuncId: ExpressionIds - -internal external var TryId: ExpressionIds - -internal external var ThrowId: ExpressionIds - -internal external var RethrowId: ExpressionIds - -internal external var BrOnExnId: ExpressionIds - -internal external var TupleMakeId: ExpressionIds - -internal external var TupleExtractId: ExpressionIds - -internal external var PushId: ExpressionIds - -internal external var PopId: ExpressionIds - -internal external enum class ExternalKinds { - Function, - Table, - Memory, - Global, - Event -} - -internal external var ExternalFunction: ExternalKinds - -internal external var ExternalTable: ExternalKinds - -internal external var ExternalMemory: ExternalKinds - -internal external var ExternalGlobal: ExternalKinds - -internal external var ExternalEvent: ExternalKinds - -internal external enum class Features { - MVP, - Atomics, - MutableGlobals, - TruncSat, - SIMD, - BulkMemory, - SignExt, - ExceptionHandling, - TailCall, - ReferenceTypes, - Multivalue, - GC, - Memory64, - All -} - -internal external enum class Operations { - ClzInt32, - CtzInt32, - PopcntInt32, - NegFloat32, - AbsFloat32, - CeilFloat32, - FloorFloat32, - TruncFloat32, - NearestFloat32, - SqrtFloat32, - EqZInt32, - ClzInt64, - CtzInt64, - PopcntInt64, - NegFloat64, - AbsFloat64, - CeilFloat64, - FloorFloat64, - TruncFloat64, - NearestFloat64, - SqrtFloat64, - EqZInt64, - ExtendSInt32, - ExtendUInt32, - WrapInt64, - TruncSFloat32ToInt32, - TruncSFloat32ToInt64, - TruncUFloat32ToInt32, - TruncUFloat32ToInt64, - TruncSFloat64ToInt32, - TruncSFloat64ToInt64, - TruncUFloat64ToInt32, - TruncUFloat64ToInt64, - TruncSatSFloat32ToInt32, - TruncSatSFloat32ToInt64, - TruncSatUFloat32ToInt32, - TruncSatUFloat32ToInt64, - TruncSatSFloat64ToInt32, - TruncSatSFloat64ToInt64, - TruncSatUFloat64ToInt32, - TruncSatUFloat64ToInt64, - ReinterpretFloat32, - ReinterpretFloat64, - ConvertSInt32ToFloat32, - ConvertSInt32ToFloat64, - ConvertUInt32ToFloat32, - ConvertUInt32ToFloat64, - ConvertSInt64ToFloat32, - ConvertSInt64ToFloat64, - ConvertUInt64ToFloat32, - ConvertUInt64ToFloat64, - PromoteFloat32, - DemoteFloat64, - ReinterpretInt32, - ReinterpretInt64, - ExtendS8Int32, - ExtendS16Int32, - ExtendS8Int64, - ExtendS16Int64, - ExtendS32Int64, - AddInt32, - SubInt32, - MulInt32, - DivSInt32, - DivUInt32, - RemSInt32, - RemUInt32, - AndInt32, - OrInt32, - XorInt32, - ShlInt32, - ShrUInt32, - ShrSInt32, - RotLInt32, - RotRInt32, - EqInt32, - NeInt32, - LtSInt32, - LtUInt32, - LeSInt32, - LeUInt32, - GtSInt32, - GtUInt32, - GeSInt32, - GeUInt32, - AddInt64, - SubInt64, - MulInt64, - DivSInt64, - DivUInt64, - RemSInt64, - RemUInt64, - AndInt64, - OrInt64, - XorInt64, - ShlInt64, - ShrUInt64, - ShrSInt64, - RotLInt64, - RotRInt64, - EqInt64, - NeInt64, - LtSInt64, - LtUInt64, - LeSInt64, - LeUInt64, - GtSInt64, - GtUInt64, - GeSInt64, - GeUInt64, - AddFloat32, - SubFloat32, - MulFloat32, - DivFloat32, - CopySignFloat32, - MinFloat32, - MaxFloat32, - EqFloat32, - NeFloat32, - LtFloat32, - LeFloat32, - GtFloat32, - GeFloat32, - AddFloat64, - SubFloat64, - MulFloat64, - DivFloat64, - CopySignFloat64, - MinFloat64, - MaxFloat64, - EqFloat64, - NeFloat64, - LtFloat64, - LeFloat64, - GtFloat64, - GeFloat64, - MemorySize, - MemoryGrow, - AtomicRMWAdd, - AtomicRMWSub, - AtomicRMWAnd, - AtomicRMWOr, - AtomicRMWXor, - AtomicRMWXchg, - SplatVecI8x16, - ExtractLaneSVecI8x16, - ExtractLaneUVecI8x16, - ReplaceLaneVecI8x16, - SplatVecI16x8, - ExtractLaneSVecI16x8, - ExtractLaneUVecI16x8, - ReplaceLaneVecI16x8, - SplatVecI32x4, - ExtractLaneVecI32x4, - ReplaceLaneVecI32x4, - SplatVecI64x2, - ExtractLaneVecI64x2, - ReplaceLaneVecI64x2, - SplatVecF32x4, - ExtractLaneVecF32x4, - ReplaceLaneVecF32x4, - SplatVecF64x2, - ExtractLaneVecF64x2, - ReplaceLaneVecF64x2, - EqVecI8x16, - NeVecI8x16, - LtSVecI8x16, - LtUVecI8x16, - GtSVecI8x16, - GtUVecI8x16, - LeSVecI8x16, - LeUVecI8x16, - GeSVecI8x16, - GeUVecI8x16, - EqVecI16x8, - NeVecI16x8, - LtSVecI16x8, - LtUVecI16x8, - GtSVecI16x8, - GtUVecI16x8, - LeSVecI16x8, - LeUVecI16x8, - GeSVecI16x8, - GeUVecI16x8, - EqVecI32x4, - NeVecI32x4, - LtSVecI32x4, - LtUVecI32x4, - GtSVecI32x4, - GtUVecI32x4, - LeSVecI32x4, - LeUVecI32x4, - GeSVecI32x4, - GeUVecI32x4, - EqVecF32x4, - NeVecF32x4, - LtVecF32x4, - GtVecF32x4, - LeVecF32x4, - GeVecF32x4, - EqVecF64x2, - NeVecF64x2, - LtVecF64x2, - GtVecF64x2, - LeVecF64x2, - GeVecF64x2, - NotVec128, - AndVec128, - OrVec128, - XorVec128, - AndNotVec128, - BitselectVec128, - NegVecI8x16, - AnyTrueVecI8x16, - AllTrueVecI8x16, - ShlVecI8x16, - ShrSVecI8x16, - ShrUVecI8x16, - AddVecI8x16, - AddSatSVecI8x16, - AddSatUVecI8x16, - SubVecI8x16, - SubSatSVecI8x16, - SubSatUVecI8x16, - MulVecI8x16, - MinSVecI8x16, - MinUVecI8x16, - MaxSVecI8x16, - MaxUVecI8x16, - NegVecI16x8, - AnyTrueVecI16x8, - AllTrueVecI16x8, - ShlVecI16x8, - ShrSVecI16x8, - ShrUVecI16x8, - AddVecI16x8, - AddSatSVecI16x8, - AddSatUVecI16x8, - SubVecI16x8, - SubSatSVecI16x8, - SubSatUVecI16x8, - MulVecI16x8, - MinSVecI16x8, - MinUVecI16x8, - MaxSVecI16x8, - MaxUVecI16x8, - DotSVecI16x8ToVecI32x4, - NegVecI32x4, - AnyTrueVecI32x4, - AllTrueVecI32x4, - ShlVecI32x4, - ShrSVecI32x4, - ShrUVecI32x4, - AddVecI32x4, - SubVecI32x4, - MulVecI32x4, - MinSVecI32x4, - MinUVecI32x4, - MaxSVecI32x4, - MaxUVecI32x4, - NegVecI64x2, - AnyTrueVecI64x2, - AllTrueVecI64x2, - ShlVecI64x2, - ShrSVecI64x2, - ShrUVecI64x2, - AddVecI64x2, - SubVecI64x2, - AbsVecF32x4, - NegVecF32x4, - SqrtVecF32x4, - QFMAVecF32x4, - QFMSVecF32x4, - AddVecF32x4, - SubVecF32x4, - MulVecF32x4, - DivVecF32x4, - MinVecF32x4, - MaxVecF32x4, - AbsVecF64x2, - NegVecF64x2, - SqrtVecF64x2, - QFMAVecF64x2, - QFMSVecF64x2, - AddVecF64x2, - SubVecF64x2, - MulVecF64x2, - DivVecF64x2, - MinVecF64x2, - MaxVecF64x2, - TruncSatSVecF32x4ToVecI32x4, - TruncSatUVecF32x4ToVecI32x4, - TruncSatSVecF64x2ToVecI64x2, - TruncSatUVecF64x2ToVecI64x2, - ConvertSVecI32x4ToVecF32x4, - ConvertUVecI32x4ToVecF32x4, - ConvertSVecI64x2ToVecF64x2, - ConvertUVecI64x2ToVecF64x2, - LoadSplatVec8x16, - LoadSplatVec16x8, - LoadSplatVec32x4, - LoadSplatVec64x2, - LoadExtSVec8x8ToVecI16x8, - LoadExtUVec8x8ToVecI16x8, - LoadExtSVec16x4ToVecI32x4, - LoadExtUVec16x4ToVecI32x4, - LoadExtSVec32x2ToVecI64x2, - LoadExtUVec32x2ToVecI64x2, - NarrowSVecI16x8ToVecI8x16, - NarrowUVecI16x8ToVecI8x16, - NarrowSVecI32x4ToVecI16x8, - NarrowUVecI32x4ToVecI16x8, - WidenLowSVecI8x16ToVecI16x8, - WidenHighSVecI8x16ToVecI16x8, - WidenLowUVecI8x16ToVecI16x8, - WidenHighUVecI8x16ToVecI16x8, - WidenLowSVecI16x8ToVecI32x4, - WidenHighSVecI16x8ToVecI32x4, - WidenLowUVecI16x8ToVecI32x4, - WidenHighUVecI16x8ToVecI32x4, - SwizzleVec8x16 -} - -internal external var ClzInt32: Operations - -internal external var CtzInt32: Operations - -internal external var PopcntInt32: Operations - -internal external var NegFloat32: Operations - -internal external var AbsFloat32: Operations - -internal external var CeilFloat32: Operations - -internal external var FloorFloat32: Operations - -internal external var TruncFloat32: Operations - -internal external var NearestFloat32: Operations - -internal external var SqrtFloat32: Operations - -internal external var EqZInt32: Operations - -internal external var ClzInt64: Operations - -internal external var CtzInt64: Operations - -internal external var PopcntInt64: Operations - -internal external var NegFloat64: Operations - -internal external var AbsFloat64: Operations - -internal external var CeilFloat64: Operations - -internal external var FloorFloat64: Operations - -internal external var TruncFloat64: Operations - -internal external var NearestFloat64: Operations - -internal external var SqrtFloat64: Operations - -internal external var EqZInt64: Operations - -internal external var ExtendSInt32: Operations - -internal external var ExtendUInt32: Operations - -internal external var WrapInt64: Operations - -internal external var TruncSFloat32ToInt32: Operations - -internal external var TruncSFloat32ToInt64: Operations - -internal external var TruncUFloat32ToInt32: Operations - -internal external var TruncUFloat32ToInt64: Operations - -internal external var TruncSFloat64ToInt32: Operations - -internal external var TruncSFloat64ToInt64: Operations - -internal external var TruncUFloat64ToInt32: Operations - -internal external var TruncUFloat64ToInt64: Operations - -internal external var TruncSatSFloat32ToInt32: Operations - -internal external var TruncSatSFloat32ToInt64: Operations - -internal external var TruncSatUFloat32ToInt32: Operations - -internal external var TruncSatUFloat32ToInt64: Operations - -internal external var TruncSatSFloat64ToInt32: Operations - -internal external var TruncSatSFloat64ToInt64: Operations - -internal external var TruncSatUFloat64ToInt32: Operations - -internal external var TruncSatUFloat64ToInt64: Operations - -internal external var ReinterpretFloat32: Operations - -internal external var ReinterpretFloat64: Operations - -internal external var ConvertSInt32ToFloat32: Operations - -internal external var ConvertSInt32ToFloat64: Operations - -internal external var ConvertUInt32ToFloat32: Operations - -internal external var ConvertUInt32ToFloat64: Operations - -internal external var ConvertSInt64ToFloat32: Operations - -internal external var ConvertSInt64ToFloat64: Operations - -internal external var ConvertUInt64ToFloat32: Operations - -internal external var ConvertUInt64ToFloat64: Operations - -internal external var PromoteFloat32: Operations - -internal external var DemoteFloat64: Operations - -internal external var ReinterpretInt32: Operations - -internal external var ReinterpretInt64: Operations - -internal external var ExtendS8Int32: Operations - -internal external var ExtendS16Int32: Operations - -internal external var ExtendS8Int64: Operations - -internal external var ExtendS16Int64: Operations - -internal external var ExtendS32Int64: Operations - -internal external var AddInt32: Operations - -internal external var SubInt32: Operations - -internal external var MulInt32: Operations - -internal external var DivSInt32: Operations - -internal external var DivUInt32: Operations - -internal external var RemSInt32: Operations - -internal external var RemUInt32: Operations - -internal external var AndInt32: Operations - -internal external var OrInt32: Operations - -internal external var XorInt32: Operations - -internal external var ShlInt32: Operations - -internal external var ShrUInt32: Operations - -internal external var ShrSInt32: Operations - -internal external var RotLInt32: Operations - -internal external var RotRInt32: Operations - -internal external var EqInt32: Operations - -internal external var NeInt32: Operations - -internal external var LtSInt32: Operations - -internal external var LtUInt32: Operations - -internal external var LeSInt32: Operations - -internal external var LeUInt32: Operations - -internal external var GtSInt32: Operations - -internal external var GtUInt32: Operations - -internal external var GeSInt32: Operations - -internal external var GeUInt32: Operations - -internal external var AddInt64: Operations - -internal external var SubInt64: Operations - -internal external var MulInt64: Operations - -internal external var DivSInt64: Operations - -internal external var DivUInt64: Operations - -internal external var RemSInt64: Operations - -internal external var RemUInt64: Operations - -internal external var AndInt64: Operations - -internal external var OrInt64: Operations - -internal external var XorInt64: Operations - -internal external var ShlInt64: Operations - -internal external var ShrUInt64: Operations - -internal external var ShrSInt64: Operations - -internal external var RotLInt64: Operations - -internal external var RotRInt64: Operations - -internal external var EqInt64: Operations - -internal external var NeInt64: Operations - -internal external var LtSInt64: Operations - -internal external var LtUInt64: Operations - -internal external var LeSInt64: Operations - -internal external var LeUInt64: Operations - -internal external var GtSInt64: Operations - -internal external var GtUInt64: Operations - -internal external var GeSInt64: Operations - -internal external var GeUInt64: Operations - -internal external var AddFloat32: Operations - -internal external var SubFloat32: Operations - -internal external var MulFloat32: Operations - -internal external var DivFloat32: Operations - -internal external var CopySignFloat32: Operations - -internal external var MinFloat32: Operations - -internal external var MaxFloat32: Operations - -internal external var EqFloat32: Operations - -internal external var NeFloat32: Operations - -internal external var LtFloat32: Operations - -internal external var LeFloat32: Operations - -internal external var GtFloat32: Operations - -internal external var GeFloat32: Operations - -internal external var AddFloat64: Operations - -internal external var SubFloat64: Operations - -internal external var MulFloat64: Operations - -internal external var DivFloat64: Operations - -internal external var CopySignFloat64: Operations - -internal external var MinFloat64: Operations - -internal external var MaxFloat64: Operations - -internal external var EqFloat64: Operations - -internal external var NeFloat64: Operations - -internal external var LtFloat64: Operations - -internal external var LeFloat64: Operations - -internal external var GtFloat64: Operations - -internal external var GeFloat64: Operations - -internal external var MemorySize: Operations - -internal external var MemoryGrow: Operations - -internal external var AtomicRMWAdd: Operations - -internal external var AtomicRMWSub: Operations - -internal external var AtomicRMWAnd: Operations - -internal external var AtomicRMWOr: Operations - -internal external var AtomicRMWXor: Operations - -internal external var AtomicRMWXchg: Operations - -internal external var SplatVecI8x16: Operations - -internal external var ExtractLaneSVecI8x16: Operations - -internal external var ExtractLaneUVecI8x16: Operations - -internal external var ReplaceLaneVecI8x16: Operations - -internal external var SplatVecI16x8: Operations - -internal external var ExtractLaneSVecI16x8: Operations - -internal external var ExtractLaneUVecI16x8: Operations - -internal external var ReplaceLaneVecI16x8: Operations - -internal external var SplatVecI32x4: Operations - -internal external var ExtractLaneVecI32x4: Operations - -internal external var ReplaceLaneVecI32x4: Operations - -internal external var SplatVecI64x2: Operations - -internal external var ExtractLaneVecI64x2: Operations - -internal external var ReplaceLaneVecI64x2: Operations - -internal external var SplatVecF32x4: Operations - -internal external var ExtractLaneVecF32x4: Operations - -internal external var ReplaceLaneVecF32x4: Operations - -internal external var SplatVecF64x2: Operations - -internal external var ExtractLaneVecF64x2: Operations - -internal external var ReplaceLaneVecF64x2: Operations - -internal external var EqVecI8x16: Operations - -internal external var NeVecI8x16: Operations - -internal external var LtSVecI8x16: Operations - -internal external var LtUVecI8x16: Operations - -internal external var GtSVecI8x16: Operations - -internal external var GtUVecI8x16: Operations - -internal external var LeSVecI8x16: Operations - -internal external var LeUVecI8x16: Operations - -internal external var GeSVecI8x16: Operations - -internal external var GeUVecI8x16: Operations - -internal external var EqVecI16x8: Operations - -internal external var NeVecI16x8: Operations - -internal external var LtSVecI16x8: Operations - -internal external var LtUVecI16x8: Operations - -internal external var GtSVecI16x8: Operations - -internal external var GtUVecI16x8: Operations - -internal external var LeSVecI16x8: Operations - -internal external var LeUVecI16x8: Operations - -internal external var GeSVecI16x8: Operations - -internal external var GeUVecI16x8: Operations - -internal external var EqVecI32x4: Operations - -internal external var NeVecI32x4: Operations - -internal external var LtSVecI32x4: Operations - -internal external var LtUVecI32x4: Operations - -internal external var GtSVecI32x4: Operations - -internal external var GtUVecI32x4: Operations - -internal external var LeSVecI32x4: Operations - -internal external var LeUVecI32x4: Operations - -internal external var GeSVecI32x4: Operations - -internal external var GeUVecI32x4: Operations - -internal external var EqVecF32x4: Operations - -internal external var NeVecF32x4: Operations - -internal external var LtVecF32x4: Operations - -internal external var GtVecF32x4: Operations - -internal external var LeVecF32x4: Operations - -internal external var GeVecF32x4: Operations - -internal external var EqVecF64x2: Operations - -internal external var NeVecF64x2: Operations - -internal external var LtVecF64x2: Operations - -internal external var GtVecF64x2: Operations - -internal external var LeVecF64x2: Operations - -internal external var GeVecF64x2: Operations - -internal external var NotVec128: Operations - -internal external var AndVec128: Operations - -internal external var OrVec128: Operations - -internal external var XorVec128: Operations - -internal external var AndNotVec128: Operations - -internal external var BitselectVec128: Operations - -internal external var NegVecI8x16: Operations - -internal external var AnyTrueVecI8x16: Operations - -internal external var AllTrueVecI8x16: Operations - -internal external var ShlVecI8x16: Operations - -internal external var ShrSVecI8x16: Operations - -internal external var ShrUVecI8x16: Operations - -internal external var AddVecI8x16: Operations - -internal external var AddSatSVecI8x16: Operations - -internal external var AddSatUVecI8x16: Operations - -internal external var SubVecI8x16: Operations - -internal external var SubSatSVecI8x16: Operations - -internal external var SubSatUVecI8x16: Operations - -internal external var MulVecI8x16: Operations - -internal external var MinSVecI8x16: Operations - -internal external var MinUVecI8x16: Operations - -internal external var MaxSVecI8x16: Operations - -internal external var MaxUVecI8x16: Operations - -internal external var NegVecI16x8: Operations - -internal external var AnyTrueVecI16x8: Operations - -internal external var AllTrueVecI16x8: Operations - -internal external var ShlVecI16x8: Operations - -internal external var ShrSVecI16x8: Operations - -internal external var ShrUVecI16x8: Operations - -internal external var AddVecI16x8: Operations - -internal external var AddSatSVecI16x8: Operations - -internal external var AddSatUVecI16x8: Operations - -internal external var SubVecI16x8: Operations - -internal external var SubSatSVecI16x8: Operations - -internal external var SubSatUVecI16x8: Operations - -internal external var MulVecI16x8: Operations - -internal external var MinSVecI16x8: Operations - -internal external var MinUVecI16x8: Operations - -internal external var MaxSVecI16x8: Operations - -internal external var MaxUVecI16x8: Operations - -internal external var DotSVecI16x8ToVecI32x4: Operations - -internal external var NegVecI32x4: Operations - -internal external var AnyTrueVecI32x4: Operations - -internal external var AllTrueVecI32x4: Operations - -internal external var ShlVecI32x4: Operations - -internal external var ShrSVecI32x4: Operations - -internal external var ShrUVecI32x4: Operations - -internal external var AddVecI32x4: Operations - -internal external var SubVecI32x4: Operations - -internal external var MulVecI32x4: Operations - -internal external var MinSVecI32x4: Operations - -internal external var MinUVecI32x4: Operations - -internal external var MaxSVecI32x4: Operations - -internal external var MaxUVecI32x4: Operations - -internal external var NegVecI64x2: Operations - -internal external var AnyTrueVecI64x2: Operations - -internal external var AllTrueVecI64x2: Operations - -internal external var ShlVecI64x2: Operations - -internal external var ShrSVecI64x2: Operations - -internal external var ShrUVecI64x2: Operations - -internal external var AddVecI64x2: Operations - -internal external var SubVecI64x2: Operations - -internal external var AbsVecF32x4: Operations - -internal external var NegVecF32x4: Operations - -internal external var SqrtVecF32x4: Operations - -internal external var QFMAVecF32x4: Operations - -internal external var QFMSVecF32x4: Operations - -internal external var AddVecF32x4: Operations - -internal external var SubVecF32x4: Operations - -internal external var MulVecF32x4: Operations - -internal external var DivVecF32x4: Operations - -internal external var MinVecF32x4: Operations - -internal external var MaxVecF32x4: Operations - -internal external var AbsVecF64x2: Operations - -internal external var NegVecF64x2: Operations - -internal external var SqrtVecF64x2: Operations - -internal external var QFMAVecF64x2: Operations - -internal external var QFMSVecF64x2: Operations - -internal external var AddVecF64x2: Operations - -internal external var SubVecF64x2: Operations - -internal external var MulVecF64x2: Operations - -internal external var DivVecF64x2: Operations - -internal external var MinVecF64x2: Operations - -internal external var MaxVecF64x2: Operations - -internal external var TruncSatSVecF32x4ToVecI32x4: Operations - -internal external var TruncSatUVecF32x4ToVecI32x4: Operations - -internal external var TruncSatSVecF64x2ToVecI64x2: Operations - -internal external var TruncSatUVecF64x2ToVecI64x2: Operations - -internal external var ConvertSVecI32x4ToVecF32x4: Operations - -internal external var ConvertUVecI32x4ToVecF32x4: Operations - -internal external var ConvertSVecI64x2ToVecF64x2: Operations - -internal external var ConvertUVecI64x2ToVecF64x2: Operations - -internal external var LoadSplatVec8x16: Operations - -internal external var LoadSplatVec16x8: Operations - -internal external var LoadSplatVec32x4: Operations - -internal external var LoadSplatVec64x2: Operations - -internal external var LoadExtSVec8x8ToVecI16x8: Operations - -internal external var LoadExtUVec8x8ToVecI16x8: Operations - -internal external var LoadExtSVec16x4ToVecI32x4: Operations - -internal external var LoadExtUVec16x4ToVecI32x4: Operations - -internal external var LoadExtSVec32x2ToVecI64x2: Operations - -internal external var LoadExtUVec32x2ToVecI64x2: Operations - -internal external var NarrowSVecI16x8ToVecI8x16: Operations - -internal external var NarrowUVecI16x8ToVecI8x16: Operations - -internal external var NarrowSVecI32x4ToVecI16x8: Operations - -internal external var NarrowUVecI32x4ToVecI16x8: Operations - -internal external var WidenLowSVecI8x16ToVecI16x8: Operations - -internal external var WidenHighSVecI8x16ToVecI16x8: Operations - -internal external var WidenLowUVecI8x16ToVecI16x8: Operations - -internal external var WidenHighUVecI8x16ToVecI16x8: Operations - -internal external var WidenLowSVecI16x8ToVecI32x4: Operations - -internal external var WidenHighSVecI16x8ToVecI32x4: Operations - -internal external var WidenLowUVecI16x8ToVecI32x4: Operations - -internal external var WidenHighUVecI16x8ToVecI32x4: Operations - -internal external var SwizzleVec8x16: Operations - -internal external interface `T$2` { - fun get(index: Number, type: Type): ExpressionRef - fun set(index: Number, value: ExpressionRef): ExpressionRef - fun tee(index: Number, value: ExpressionRef, type: Type): ExpressionRef -} - -internal external interface `T$3` { - fun get(name: String, type: Type): ExpressionRef - fun set(name: String, value: ExpressionRef): ExpressionRef -} - -internal external interface `T$4` { - fun size(): ExpressionRef - fun grow(value: ExpressionRef): ExpressionRef - fun init(segment: Number, dest: ExpressionRef, offset: ExpressionRef, size: ExpressionRef): ExpressionRef - fun copy(dest: ExpressionRef, source: ExpressionRef, size: ExpressionRef): ExpressionRef - fun fill(dest: ExpressionRef, value: ExpressionRef, size: ExpressionRef): ExpressionRef -} - -internal external interface `T$5` { - fun drop(segment: Number): ExpressionRef -} - -internal external interface `T$6` { - fun f32(value: ExpressionRef): ExpressionRef - fun f64(value: ExpressionRef): ExpressionRef -} - -internal external interface `T$7` { - fun add(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun sub(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun and(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun or(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun xor(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun xchg(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun cmpxchg(offset: Number, ptr: ExpressionRef, expected: ExpressionRef, replacement: ExpressionRef): ExpressionRef -} - -internal external interface `T$8` { - fun load(offset: Number, ptr: ExpressionRef): ExpressionRef - fun load8_u(offset: Number, ptr: ExpressionRef): ExpressionRef - fun load16_u(offset: Number, ptr: ExpressionRef): ExpressionRef - fun store(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store8(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store16(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - var rmw: `T$7` - var rmw8_u: `T$7` - var rmw16_u: `T$7` - fun wait(ptr: ExpressionRef, expected: ExpressionRef, timeout: ExpressionRef): ExpressionRef -} - -internal external interface `T$9` { - fun load(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load8_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load8_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load16_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load16_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun store(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store8(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store16(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun const(value: Number): ExpressionRef - fun clz(value: ExpressionRef): ExpressionRef - fun ctz(value: ExpressionRef): ExpressionRef - fun popcnt(value: ExpressionRef): ExpressionRef - fun eqz(value: ExpressionRef): ExpressionRef - var trunc_s: `T$6` - var trunc_u: `T$6` - var trunc_s_sat: `T$6` - var trunc_u_sat: `T$6` - fun reinterpret(value: ExpressionRef): ExpressionRef - fun extend8_s(value: ExpressionRef): ExpressionRef - fun extend16_s(value: ExpressionRef): ExpressionRef - fun wrap(value: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun div_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun div_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rem_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rem_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun and(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun or(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun xor(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun shl(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun shr_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun shr_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rotl(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rotr(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - var atomic: `T$8` - fun pop(): ExpressionRef -} - -internal external interface `T$10` { - fun load(offset: Number, ptr: ExpressionRef): ExpressionRef - fun load8_u(offset: Number, ptr: ExpressionRef): ExpressionRef - fun load16_u(offset: Number, ptr: ExpressionRef): ExpressionRef - fun load32_u(offset: Number, ptr: ExpressionRef): ExpressionRef - fun store(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store8(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store16(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store32(offset: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - var rmw: `T$7` - var rmw8_u: `T$7` - var rmw16_u: `T$7` - var rmw32_u: `T$7` - fun wait(ptr: ExpressionRef, expected: ExpressionRef, timeout: ExpressionRef): ExpressionRef -} - -internal external interface `T$11` { - fun load(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load8_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load8_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load16_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load16_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load32_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load32_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun store(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store8(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store16(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun store32(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun const(low: Number, high: Number): ExpressionRef - fun clz(value: ExpressionRef): ExpressionRef - fun ctz(value: ExpressionRef): ExpressionRef - fun popcnt(value: ExpressionRef): ExpressionRef - fun eqz(value: ExpressionRef): ExpressionRef - var trunc_s: `T$6` - var trunc_u: `T$6` - var trunc_s_sat: `T$6` - var trunc_u_sat: `T$6` - fun reinterpret(value: ExpressionRef): ExpressionRef - fun extend8_s(value: ExpressionRef): ExpressionRef - fun extend16_s(value: ExpressionRef): ExpressionRef - fun extend32_s(value: ExpressionRef): ExpressionRef - fun extend_s(value: ExpressionRef): ExpressionRef - fun extend_u(value: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun div_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun div_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rem_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rem_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun and(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun or(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun xor(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun shl(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun shr_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun shr_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rotl(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun rotr(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - var atomic: `T$10` - fun pop(): ExpressionRef -} - -internal external interface `T$12` { - fun load(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun store(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun const(value: Number): ExpressionRef - fun const_bits(value: Number): ExpressionRef - fun neg(value: ExpressionRef): ExpressionRef - fun abs(value: ExpressionRef): ExpressionRef - fun ceil(value: ExpressionRef): ExpressionRef - fun floor(value: ExpressionRef): ExpressionRef - fun trunc(value: ExpressionRef): ExpressionRef - fun nearest(value: ExpressionRef): ExpressionRef - fun sqrt(value: ExpressionRef): ExpressionRef - fun reinterpret(value: ExpressionRef): ExpressionRef - var convert_s: `T$6` - var convert_u: `T$6` - fun demote(value: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun div(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun copysign(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun min(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun max(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun pop(): ExpressionRef -} - -internal external interface `T$13` { - fun load(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun store(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun const(value: Number): ExpressionRef - fun const_bits(low: Number, high: Number): ExpressionRef - fun neg(value: ExpressionRef): ExpressionRef - fun abs(value: ExpressionRef): ExpressionRef - fun ceil(value: ExpressionRef): ExpressionRef - fun floor(value: ExpressionRef): ExpressionRef - fun trunc(value: ExpressionRef): ExpressionRef - fun nearest(value: ExpressionRef): ExpressionRef - fun sqrt(value: ExpressionRef): ExpressionRef - fun reinterpret(value: ExpressionRef): ExpressionRef - var convert_s: `T$6` - var convert_u: `T$6` - fun promote(value: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun div(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun copysign(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun min(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun max(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun pop(): ExpressionRef -} - -internal external interface `T$14` { - fun load(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun store(offset: Number, align: Number, ptr: ExpressionRef, value: ExpressionRef): ExpressionRef - fun const(value: Number): ExpressionRef - fun not(value: ExpressionRef): ExpressionRef - fun and(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun or(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun xor(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun andnot(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun bitselect(left: ExpressionRef, right: ExpressionRef, cond: ExpressionRef): ExpressionRef - fun pop(): ExpressionRef -} - -internal external interface `T$15` { - fun splat(value: ExpressionRef): ExpressionRef - fun extract_lane_s(vec: ExpressionRef, index: ExpressionRef): ExpressionRef - fun extract_lane_u(vec: ExpressionRef, index: ExpressionRef): ExpressionRef - fun replace_lane(vec: ExpressionRef, index: ExpressionRef, value: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun neg(value: ExpressionRef): ExpressionRef - fun any_true(value: ExpressionRef): ExpressionRef - fun all_true(value: ExpressionRef): ExpressionRef - fun shl(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_s(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_u(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun add_saturate_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun add_saturate_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub_saturate_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub_saturate_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun min_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun min_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun max_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun max_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun avgr_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun narrow_i16x8_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun narrow_i16x8_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef -} - -internal external interface `T$16` { - fun splat(value: ExpressionRef): ExpressionRef - fun extract_lane_s(vec: ExpressionRef, index: ExpressionRef): ExpressionRef - fun extract_lane_u(vec: ExpressionRef, index: ExpressionRef): ExpressionRef - fun replace_lane(vec: ExpressionRef, index: ExpressionRef, value: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun neg(value: ExpressionRef): ExpressionRef - fun any_true(value: ExpressionRef): ExpressionRef - fun all_true(value: ExpressionRef): ExpressionRef - fun shl(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_s(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_u(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun add_saturate_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun add_saturate_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub_saturate_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub_saturate_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun min_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun min_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun max_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun max_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun avgr_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun narrow_i32x4_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun narrow_i32x4_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun widen_low_i8x16_s(value: ExpressionRef): ExpressionRef - fun widen_high_i8x16_s(value: ExpressionRef): ExpressionRef - fun widen_low_i8x16_u(value: ExpressionRef): ExpressionRef - fun widen_high_i8x16_u(value: ExpressionRef): ExpressionRef - fun load8x8_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load8x8_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef -} - -internal external interface `T$17` { - fun splat(value: ExpressionRef): ExpressionRef - fun extract_lane(vec: ExpressionRef, index: ExpressionRef): ExpressionRef - fun replace_lane(vec: ExpressionRef, index: ExpressionRef, value: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_s(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge_u(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun neg(value: ExpressionRef): ExpressionRef - fun any_true(value: ExpressionRef): ExpressionRef - fun all_true(value: ExpressionRef): ExpressionRef - fun shl(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_s(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_u(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun trunc_sat_f32x4_s(value: ExpressionRef): ExpressionRef - fun trunc_sat_f32x4_u(value: ExpressionRef): ExpressionRef - fun widen_low_i16x8_s(value: ExpressionRef): ExpressionRef - fun widen_high_i16x8_s(value: ExpressionRef): ExpressionRef - fun widen_low_i16x8_u(value: ExpressionRef): ExpressionRef - fun widen_high_i16x8_u(value: ExpressionRef): ExpressionRef - fun load16x4_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load16x4_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef -} - -internal external interface `T$18` { - fun splat(value: ExpressionRef): ExpressionRef - fun extract_lane(vec: ExpressionRef, index: ExpressionRef): ExpressionRef - fun replace_lane(vec: ExpressionRef, index: ExpressionRef, value: ExpressionRef): ExpressionRef - fun neg(value: ExpressionRef): ExpressionRef - fun any_true(value: ExpressionRef): ExpressionRef - fun all_true(value: ExpressionRef): ExpressionRef - fun shl(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_s(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun shr_u(vec: ExpressionRef, shift: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun trunc_sat_f64x2_s(value: ExpressionRef): ExpressionRef - fun trunc_sat_f64x2_u(value: ExpressionRef): ExpressionRef - fun load32x2_s(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef - fun load32x2_u(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef -} - -internal external interface `T$19` { - fun splat(value: ExpressionRef): ExpressionRef - fun extract_lane(vec: ExpressionRef, index: ExpressionRef): ExpressionRef - fun replace_lane(vec: ExpressionRef, index: ExpressionRef, value: ExpressionRef): ExpressionRef - fun eq(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ne(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun lt(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun gt(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun le(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun ge(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun abs(value: ExpressionRef): ExpressionRef - fun neg(value: ExpressionRef): ExpressionRef - fun sqrt(value: ExpressionRef): ExpressionRef - fun qfma(a: ExpressionRef, b: ExpressionRef, c: ExpressionRef): ExpressionRef - fun qfms(a: ExpressionRef, b: ExpressionRef, c: ExpressionRef): ExpressionRef - fun add(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun sub(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun mul(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun div(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun min(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun max(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun convert_i32x4_s(value: ExpressionRef): ExpressionRef - fun convert_i32x4_u(value: ExpressionRef): ExpressionRef -} - -internal external interface `T$20` { - fun shuffle(left: ExpressionRef, right: ExpressionRef, mask: Array): ExpressionRef - fun swizzle(left: ExpressionRef, right: ExpressionRef): ExpressionRef - fun load_splat(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef -} - -internal external interface `T$21` { - fun load_splat(offset: Number, align: Number, ptr: ExpressionRef): ExpressionRef -} - -internal external interface `T$22` { - fun pop(): ExpressionRef -} - -internal external interface `T$23` { - fun `null`(): ExpressionRef - fun is_null(value: ExpressionRef): ExpressionRef - fun func(name: String): ExpressionRef -} - -internal external interface `T$24` { - fun notify(ptr: ExpressionRef, notifyCount: ExpressionRef): ExpressionRef - fun fence(): ExpressionRef -} - -internal external interface `T$25` { - fun make(elements: Array): ExpressionRef - fun extract(tuple: ExpressionRef, index: Number): ExpressionRef -} - -internal external interface `T$26` { - var imported: Boolean - var segments: Array -} - -internal external interface `T$27` { - var binary: Uint8Array - var sourceMap: String? -} - -internal open external class Module { - open var ptr: Number - open fun block(label: String, children: Array, resultType: Type = definedExternally): ExpressionRef - open fun `if`( - condition: ExpressionRef, - ifTrue: ExpressionRef, - ifFalse: ExpressionRef = definedExternally - ): ExpressionRef - - open fun loop(label: String, body: ExpressionRef): ExpressionRef - open fun br( - label: String, - condition: ExpressionRef = definedExternally, - value: ExpressionRef = definedExternally - ): ExpressionRef - - open fun br_if( - label: String, - condition: ExpressionRef = definedExternally, - value: ExpressionRef = definedExternally - ): ExpressionRef - - open fun switch( - labels: Array, - defaultLabel: String, - condition: ExpressionRef, - value: ExpressionRef = definedExternally - ): ExpressionRef - - open fun call(name: String, operands: Array, returnType: Type): ExpressionRef - open fun return_call(name: String, operands: Array, returnType: Type): ExpressionRef - open fun call_indirect( - target: ExpressionRef, - operands: Array, - params: Type, - results: Type - ): ExpressionRef - - open fun return_call_indirect( - target: ExpressionRef, - operands: Array, - params: Type, - results: Type - ): ExpressionRef - - open var local: `T$2` - open var global: `T$3` - open var memory: `T$4` - open var data: `T$5` - open var i32: `T$9` - open var i64: `T$11` - open var f32: `T$12` - open var f64: `T$13` - open var v128: `T$14` - open var i8x16: `T$15` - open var i16x8: `T$16` - open var i32x4: `T$17` - open var i64x2: `T$18` - open var f32x4: `T$19` - open var f64x2: `T$19` - open var v8x16: `T$20` - open var v16x8: `T$21` - open var v32x4: `T$21` - open var v64x2: `T$21` - open var funcref: `T$22` - open var anyref: `T$22` - open var nullref: `T$22` - open var exnref: `T$22` - open var ref: `T$23` - open var atomic: `T$24` - open var tuple: `T$25` - open fun `try`(body: ExpressionRef, catchBody: ExpressionRef): ExpressionRef - open fun `throw`(event: String, operands: Array): ExpressionRef - open fun rethrow(exnref: ExpressionRef): ExpressionRef - open fun br_on_exn(label: String, event: String, exnref: ExpressionRef): ExpressionRef - open fun push(value: ExpressionRef): ExpressionRef - open fun select( - condition: ExpressionRef, - ifTrue: ExpressionRef, - ifFalse: ExpressionRef, - type: Type = definedExternally - ): ExpressionRef - - open fun drop(value: ExpressionRef): ExpressionRef - open fun `return`(value: ExpressionRef = definedExternally): ExpressionRef - open fun host(op: Operations, name: String, operands: Array): ExpressionRef - open fun nop(): ExpressionRef - open fun unreachable(): ExpressionRef - open fun addFunction(name: String, params: Type, results: Type, vars: Array, body: ExpressionRef): FunctionRef - open fun getFunction(name: String): FunctionRef - open fun removeFunction(name: String) - open fun getNumFunctions(): Number - open fun getFunctionByIndex(index: Number): FunctionRef - open fun addGlobal(name: String, type: Type, mutable: Boolean, init: ExpressionRef): GlobalRef - open fun getGlobal(name: String): GlobalRef - open fun removeGlobal(name: String) - open fun addEvent(name: String, attribute: Number, params: Type, results: Type): EventRef - open fun getEvent(name: String): EventRef - open fun removeEvent(name: String) - open fun addFunctionImport( - internalName: String, - externalModuleName: String, - externalBaseName: String, - params: Type, - results: Type - ) - - open fun addTableImport(internalName: String, externalModuleName: String, externalBaseName: String) - open fun addMemoryImport(internalName: String, externalModuleName: String, externalBaseName: String) - open fun addGlobalImport( - internalName: String, - externalModuleName: String, - externalBaseName: String, - globalType: Type - ) - - open fun addEventImport( - internalName: String, - externalModuleName: String, - externalBaseName: String, - attribute: Number, - params: Type, - results: Type - ) - - open fun addFunctionExport(internalName: String, externalName: String): ExportRef - open fun addTableExport(internalName: String, externalName: String): ExportRef - open fun addMemoryExport(internalName: String, externalName: String): ExportRef - open fun addGlobalExport(internalName: String, externalName: String): ExportRef - open fun removeExport(externalName: String) - open fun getNumExports(): Number - open fun getExportByIndex(index: Number): ExportRef - open fun setFunctionTable( - initial: Number, - maximum: Number, - funcNames: Array, - offset: ExpressionRef = definedExternally - ) - - open fun getFunctionTable(): `T$26` - open fun setMemory( - initial: Number, - maximum: Number, - exportName: String? = definedExternally, - segments: Array? = definedExternally, - flags: Array? = definedExternally, - shared: Boolean = definedExternally - ) - - open fun getNumMemorySegments(): Number - open fun getMemorySegmentInfoByIndex(index: Number): MemorySegmentInfo - open fun setStart(start: FunctionRef) - open fun getFeatures(): Features - open fun setFeatures(features: Features) - open fun addCustomSection(name: String, contents: Uint8Array) - open fun emitText(): String - open fun emitStackIR(optimize: Boolean = definedExternally): String - open fun emitAsmjs(): String - open fun validate(): Number - open fun optimize() - open fun optimizeFunction(func: String) - open fun optimizeFunction(func: FunctionRef) - open fun runPasses(passes: Array) - open fun runPassesOnFunction(func: String, passes: Array) - open fun runPassesOnFunction(func: FunctionRef, passes: Array) - open fun autoDrop() - open fun dispose() - open fun emitBinary(): Uint8Array - open fun emitBinary(sourceMapUrl: String?): `T$27` - open fun interpret() - open fun addDebugInfoFileName(filename: String): Number - open fun getDebugInfoFileName(index: Number): String? - open fun setDebugLocation( - func: FunctionRef, - expr: ExpressionRef, - fileIndex: Number, - lineNumber: Number, - columnNumber: Number - ) - - open fun copyExpression(expr: ExpressionRef): ExpressionRef -} - -internal external interface MemorySegment { - var offset: ExpressionRef - var data: Uint8Array - var passive: Boolean? - get() = definedExternally - set(value) = definedExternally -} - -internal external interface TableElement { - var offset: ExpressionRef - var names: Array -} - -internal external fun wrapModule(ptr: Number): Module - -internal external fun getExpressionId(expression: ExpressionRef): Number - -internal external fun getExpressionType(expression: ExpressionRef): Type - -internal external fun getExpressionInfo(expression: ExpressionRef): ExpressionInfo - -internal external interface MemorySegmentInfo { - var offset: ExpressionRef - var data: Uint8Array - var passive: Boolean -} - -internal external interface ExpressionInfo { - var id: ExpressionIds - var type: Type -} - -internal external interface BlockInfo : ExpressionInfo { - var name: String - var children: Array -} - -internal external interface IfInfo : ExpressionInfo { - var condition: ExpressionRef - var ifTrue: ExpressionRef - var ifFalse: ExpressionRef -} - -internal external interface LoopInfo : ExpressionInfo { - var name: String - var body: ExpressionRef -} - -internal external interface BreakInfo : ExpressionInfo { - var name: String - var condition: ExpressionRef - var value: ExpressionRef -} - -internal external interface SwitchInfo : ExpressionInfo { - var names: Array - var defaultName: String? - var condition: ExpressionRef - var value: ExpressionRef -} - -internal external interface CallInfo : ExpressionInfo { - var isReturn: Boolean - var target: String - var operands: Array -} - -internal external interface CallIndirectInfo : ExpressionInfo { - var isReturn: Boolean - var target: ExpressionRef - var operands: Array -} - -internal external interface LocalGetInfo : ExpressionInfo { - var index: Number -} - -internal external interface LocalSetInfo : ExpressionInfo { - var isTee: Boolean - var index: Number - var value: ExpressionRef -} - -internal external interface GlobalGetInfo : ExpressionInfo { - var name: String -} - -internal external interface GlobalSetInfo : ExpressionInfo { - var name: String - var value: ExpressionRef -} - -internal external interface LoadInfo : ExpressionInfo { - var isAtomic: Boolean - var isSigned: Boolean - var offset: Number - var bytes: Number - var align: Number - var ptr: ExpressionRef -} - -internal external interface StoreInfo : ExpressionInfo { - var isAtomic: Boolean - var offset: Number - var bytes: Number - var align: Number - var ptr: ExpressionRef - var value: ExpressionRef -} - -internal external interface `T$28` { - var low: Number - var high: Number -} - -internal external interface ConstInfo : ExpressionInfo { - var value: dynamic /* Number | `T$28` */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface UnaryInfo : ExpressionInfo { - var op: Operations - var value: ExpressionRef -} - -internal external interface BinaryInfo : ExpressionInfo { - var op: Operations - var left: ExpressionRef - var right: ExpressionRef -} - -internal external interface SelectInfo : ExpressionInfo { - var ifTrue: ExpressionRef - var ifFalse: ExpressionRef - var condition: ExpressionRef -} - -internal external interface DropInfo : ExpressionInfo { - var value: ExpressionRef -} - -internal external interface ReturnInfo : ExpressionInfo { - var value: ExpressionRef -} - -internal external interface NopInfo : ExpressionInfo - -internal external interface UnreachableInfo : ExpressionInfo - -internal external interface HostInfo : ExpressionInfo { - var op: Operations - var nameOperand: String? - var operands: Array -} - -internal external interface AtomicRMWInfo : ExpressionInfo { - var op: Operations - var bytes: Number - var offset: Number - var ptr: ExpressionRef - var value: ExpressionRef -} - -internal external interface AtomicCmpxchgInfo : ExpressionInfo { - var bytes: Number - var offset: Number - var ptr: ExpressionRef - var expected: ExpressionRef - var replacement: ExpressionRef -} - -internal external interface AtomicWaitInfo : ExpressionInfo { - var ptr: ExpressionRef - var expected: ExpressionRef - var timeout: ExpressionRef - var expectedType: Type -} - -internal external interface AtomicNotifyInfo : ExpressionInfo { - var ptr: ExpressionRef - var notifyCount: ExpressionRef -} - -internal external interface AtomicFenceInfo : ExpressionInfo { - var order: Number -} - -internal external interface SIMDExtractInfo : ExpressionInfo { - var op: Operations - var vec: ExpressionRef - var index: ExpressionRef -} - -internal external interface SIMDReplaceInfo : ExpressionInfo { - var op: Operations - var vec: ExpressionRef - var index: ExpressionRef - var value: ExpressionRef -} - -internal external interface SIMDShuffleInfo : ExpressionInfo { - var left: ExpressionRef - var right: ExpressionRef - var mask: Array -} - -internal external interface SIMDTernaryInfo : ExpressionInfo { - var op: Operations - var a: ExpressionRef - var b: ExpressionRef - var c: ExpressionRef -} - -internal external interface SIMDShiftInfo : ExpressionInfo { - var op: Operations - var vec: ExpressionRef - var shift: ExpressionRef -} - -internal external interface SIMDLoadInfo : ExpressionInfo { - var op: Operations - var offset: Number - var align: Number - var ptr: ExpressionRef -} - -internal external interface MemoryInitInfo : ExpressionInfo { - var segment: Number - var dest: ExpressionRef - var offset: ExpressionRef - var size: ExpressionRef -} - -internal external interface MemoryDropInfo : ExpressionInfo { - var segment: Number -} - -internal external interface MemoryCopyInfo : ExpressionInfo { - var dest: ExpressionRef - var source: ExpressionRef - var size: ExpressionRef -} - -internal external interface MemoryFillInfo : ExpressionInfo { - var dest: ExpressionRef - var value: ExpressionRef - var size: ExpressionRef -} - -internal external interface RefNullInfo : ExpressionInfo - -internal external interface RefIsNullInfo : ExpressionInfo { - var value: ExpressionRef -} - -internal external interface RefFuncInfo : ExpressionInfo { - var func: String -} - -internal external interface TryInfo : ExpressionInfo { - var body: ExpressionRef - var catchBody: ExpressionRef -} - -internal external interface ThrowInfo : ExpressionInfo { - var event: String - var operands: Array -} - -internal external interface RethrowInfo : ExpressionInfo { - var exnref: ExpressionRef -} - -internal external interface BrOnExnInfo : ExpressionInfo { - var name: String - var event: String - var exnref: ExpressionRef -} - -internal external interface PopInfo : ExpressionInfo - -internal external interface PushInfo : ExpressionInfo { - var value: ExpressionRef -} - -internal external fun getFunctionInfo(func: FunctionRef): FunctionInfo - -internal external interface FunctionInfo { - var name: String - var module: String? - var base: String? - var params: Type - var results: Type - var vars: Array - var body: ExpressionRef -} - -internal external fun getGlobalInfo(global: GlobalRef): GlobalInfo - -internal external interface GlobalInfo { - var name: String - var module: String? - var base: String? - var type: Type - var mutable: Boolean - var init: ExpressionRef -} - -internal external fun getExportInfo(export_: ExportRef): ExportInfo - -internal external interface ExportInfo { - var kind: ExternalKinds - var name: String - var value: String -} - -internal external fun getEventInfo(event: EventRef): EventInfo - -internal external interface EventInfo { - var name: String - var module: String? - var base: String? - var attribute: Number - var params: Type - var results: Type -} - -internal external fun getSideEffects(expr: ExpressionRef, features: Features): SideEffects - -internal external enum class SideEffects { - None, - Branches, - Calls, - ReadsLocal, - WritesLocal, - ReadsGlobal, - WritesGlobal, - ReadsMemory, - WritesMemory, - ImplicitTrap, - IsAtomic, - Throws, - Any -} - -internal external fun emitText(expression: ExpressionRef): String - -internal external fun emitText(expression: Module): String - -internal external fun readBinary(data: Uint8Array): Module - -internal external fun parseText(text: String): Module - -internal external fun getOptimizeLevel(): Number - -internal external fun setOptimizeLevel(level: Number): Number - -internal external fun getShrinkLevel(): Number - -internal external fun setShrinkLevel(level: Number): Number - -internal external fun getDebugInfo(): Boolean - -internal external fun setDebugInfo(on: Boolean) - -internal external fun getLowMemoryUnused(): Boolean - -internal external fun setLowMemoryUnused(on: Boolean) - -internal external fun getPassArgument(key: String): String? - -internal external fun setPassArgument(key: String, value: String?) - -internal external fun clearPassArguments() - -internal external fun getAlwaysInlineMaxSize(): Number - -internal external fun setAlwaysInlineMaxSize(size: Number) - -internal external fun getFlexibleInlineMaxSize(): Number - -internal external fun setFlexibleInlineMaxSize(size: Number) - -internal external fun getOneCallerInlineMaxSize(): Number - -internal external fun setOneCallerInlineMaxSize(size: Number) - -internal external fun exit(status: Number) - -internal open external class Relooper(module: Module) { - open fun addBlock(expression: ExpressionRef): RelooperBlockRef - open fun addBranch(from: RelooperBlockRef, to: RelooperBlockRef, condition: ExpressionRef, code: ExpressionRef) - open fun addBlockWithSwitch(code: ExpressionRef, condition: ExpressionRef): RelooperBlockRef - open fun addBranchForSwitch( - from: RelooperBlockRef, - to: RelooperBlockRef, - indexes: Array, - code: ExpressionRef - ) - - open fun renderAndDispose(entry: RelooperBlockRef, labelHelper: Number): ExpressionRef -} diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt deleted file mode 100644 index 8e449627c..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/binaryen/index.binaryen.typealiases.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -@file:Suppress("PackageDirectoryMismatch", "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", "KDocMissingDocumentation") - -package space.kscience.kmath.internal.binaryen - -internal typealias Type = Number -internal typealias ExpressionRef = Number -internal typealias FunctionRef = Number -internal typealias GlobalRef = Number -internal typealias ExportRef = Number -internal typealias EventRef = Number -internal typealias RelooperBlockRef = Number diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.kt deleted file mode 100644 index d85857de8..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/emitter/emitter.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 file. - */ - -package space.kscience.kmath.internal.emitter - -internal open external class Emitter { - constructor(obj: Any) - constructor() - - open fun on(event: String, fn: () -> Unit) - open fun off(event: String, fn: () -> Unit) - open fun once(event: String, fn: () -> Unit) - open fun emit(event: String, vararg any: Any) - open fun listeners(event: String): Array<() -> Unit> - open fun hasListeners(event: String): Boolean -} diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt deleted file mode 100644 index 122a3a397..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.extensions.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.internal.estree - -internal fun Program(sourceType: String, vararg body: dynamic) = object : Program { - override var type = "Program" - override var sourceType = sourceType - override var body = body -} - -internal fun VariableDeclaration(kind: String, vararg declarations: VariableDeclarator) = object : VariableDeclaration { - override var type = "VariableDeclaration" - override var declarations = declarations.toList().toTypedArray() - override var kind = kind -} - -internal fun VariableDeclarator(id: dynamic, init: dynamic) = object : VariableDeclarator { - override var type = "VariableDeclarator" - override var id = id - override var init = init -} - -internal fun Identifier(name: String) = object : Identifier { - override var type = "Identifier" - override var name = name -} - -internal fun FunctionExpression(params: Array, body: BlockStatement) = object : FunctionExpression { - override var params = params - override var type = "FunctionExpression" - override var body = body -} - -internal fun BlockStatement(vararg body: dynamic) = object : BlockStatement { - override var type = "BlockStatement" - override var body = body -} - -internal fun ReturnStatement(argument: dynamic) = object : ReturnStatement { - override var type = "ReturnStatement" - override var argument = argument -} - -internal fun SimpleLiteral(value: dynamic) = object : SimpleLiteral { - override var type = "Literal" - override var value = value -} - -internal fun MemberExpression(computed: Boolean, optional: Boolean, `object`: dynamic, property: dynamic) = - object : MemberExpression { - override var type = "MemberExpression" - override var computed = computed - override var optional = optional - override var `object` = `object` - override var property = property - } - -internal fun SimpleCallExpression(optional: Boolean, callee: dynamic, vararg arguments: dynamic) = - object : SimpleCallExpression { - override var type = "CallExpression" - override var optional = optional - override var callee = callee - override var arguments = arguments - } 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 deleted file mode 100644 index ad079dbd0..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/estree/estree.kt +++ /dev/null @@ -1,651 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -@file:Suppress("ClassName") - -package space.kscience.kmath.internal.estree - -import kotlin.js.RegExp - -internal external interface BaseNodeWithoutComments { - var type: String - var loc: SourceLocation? - get() = definedExternally - set(value) = definedExternally - var range: dynamic /* JsTuple */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface BaseNode : BaseNodeWithoutComments { - var leadingComments: Array? - get() = definedExternally - set(value) = definedExternally - var trailingComments: Array? - get() = definedExternally - set(value) = definedExternally -} - -internal external interface Comment : BaseNodeWithoutComments { - override var type: String /* "Line" | "Block" */ - var value: String -} - -internal external interface SourceLocation { - var source: String? - get() = definedExternally - set(value) = definedExternally - var start: Position - var end: Position -} - -internal external interface Position { - var line: Number - var column: Number -} - -internal external interface Program : BaseNode { - override var type: String /* "Program" */ - var sourceType: String /* "script" | "module" */ - var body: Array - var comments: Array? - get() = definedExternally - set(value) = definedExternally -} - -internal external interface Directive : BaseNode { - override var type: String /* "ExpressionStatement" */ - var expression: dynamic /* SimpleLiteral | RegExpLiteral */ - get() = definedExternally - set(value) = definedExternally - var directive: String -} - -internal external interface BaseFunction : BaseNode { - var params: Array - var generator: Boolean? - get() = definedExternally - set(value) = definedExternally - var async: Boolean? - get() = definedExternally - set(value) = definedExternally - var body: dynamic /* BlockStatement | ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface BaseStatement : BaseNode - -internal external interface EmptyStatement : BaseStatement { - override var type: String /* "EmptyStatement" */ -} - -internal external interface BlockStatement : BaseStatement { - override var type: String /* "BlockStatement" */ - var body: Array - var innerComments: Array? - get() = definedExternally - set(value) = definedExternally -} - -internal external interface ExpressionStatement : BaseStatement { - override var type: String /* "ExpressionStatement" */ - var expression: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface IfStatement : BaseStatement { - override var type: String /* "IfStatement" */ - var test: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally - var consequent: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ - get() = definedExternally - set(value) = definedExternally - var alternate: dynamic /* ExpressionStatement? | BlockStatement? | EmptyStatement? | DebuggerStatement? | WithStatement? | ReturnStatement? | LabeledStatement? | BreakStatement? | ContinueStatement? | IfStatement? | SwitchStatement? | ThrowStatement? | TryStatement? | WhileStatement? | DoWhileStatement? | ForStatement? | ForInStatement? | ForOfStatement? | FunctionDeclaration? | VariableDeclaration? | ClassDeclaration? */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface LabeledStatement : BaseStatement { - override var type: String /* "LabeledStatement" */ - var label: Identifier - var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface BreakStatement : BaseStatement { - override var type: String /* "BreakStatement" */ - var label: Identifier? - get() = definedExternally - set(value) = definedExternally -} - -internal external interface ContinueStatement : BaseStatement { - override var type: String /* "ContinueStatement" */ - var label: Identifier? - get() = definedExternally - set(value) = definedExternally -} - -internal external interface WithStatement : BaseStatement { - override var type: String /* "WithStatement" */ - var `object`: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally - var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface SwitchStatement : BaseStatement { - override var type: String /* "SwitchStatement" */ - var discriminant: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally - var cases: Array -} - -internal external interface ReturnStatement : BaseStatement { - override var type: String /* "ReturnStatement" */ - var argument: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface ThrowStatement : BaseStatement { - override var type: String /* "ThrowStatement" */ - var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface TryStatement : BaseStatement { - override var type: String /* "TryStatement" */ - var block: BlockStatement - var handler: CatchClause? - get() = definedExternally - set(value) = definedExternally - var finalizer: BlockStatement? - get() = definedExternally - set(value) = definedExternally -} - -internal external interface WhileStatement : BaseStatement { - override var type: String /* "WhileStatement" */ - var test: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally - var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface DoWhileStatement : BaseStatement { - override var type: String /* "DoWhileStatement" */ - var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ - get() = definedExternally - set(value) = definedExternally - var test: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface ForStatement : BaseStatement { - override var type: String /* "ForStatement" */ - var init: dynamic /* VariableDeclaration? | ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ - get() = definedExternally - set(value) = definedExternally - var test: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ - get() = definedExternally - set(value) = definedExternally - var update: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ - get() = definedExternally - set(value) = definedExternally - var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface BaseForXStatement : BaseStatement { - var left: dynamic /* VariableDeclaration | Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ - get() = definedExternally - set(value) = definedExternally - var right: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally - var body: dynamic /* ExpressionStatement | BlockStatement | EmptyStatement | DebuggerStatement | WithStatement | ReturnStatement | LabeledStatement | BreakStatement | ContinueStatement | IfStatement | SwitchStatement | ThrowStatement | TryStatement | WhileStatement | DoWhileStatement | ForStatement | ForInStatement | ForOfStatement | FunctionDeclaration | VariableDeclaration | ClassDeclaration */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface ForInStatement : BaseForXStatement { - override var type: String /* "ForInStatement" */ -} - -internal external interface DebuggerStatement : BaseStatement { - override var type: String /* "DebuggerStatement" */ -} - -internal external interface BaseDeclaration : BaseStatement - -internal external interface FunctionDeclaration : BaseFunction, BaseDeclaration { - override var type: String /* "FunctionDeclaration" */ - var id: Identifier? - override var body: BlockStatement -} - -internal external interface VariableDeclaration : BaseDeclaration { - override var type: String /* "VariableDeclaration" */ - var declarations: Array - var kind: String /* "var" | "let" | "const" */ -} - -internal external interface VariableDeclarator : BaseNode { - override var type: String /* "VariableDeclarator" */ - var id: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ - get() = definedExternally - set(value) = definedExternally - var init: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface BaseExpression : BaseNode - -internal external interface ChainExpression : BaseExpression { - override var type: String /* "ChainExpression" */ - var expression: dynamic /* SimpleCallExpression | MemberExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface ThisExpression : BaseExpression { - override var type: String /* "ThisExpression" */ -} - -internal external interface ArrayExpression : BaseExpression { - override var type: String /* "ArrayExpression" */ - var elements: Array -} - -internal external interface ObjectExpression : BaseExpression { - override var type: String /* "ObjectExpression" */ - var properties: Array -} - -internal external interface Property : BaseNode { - override var type: String /* "Property" */ - var key: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally - var value: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern */ - get() = definedExternally - set(value) = definedExternally - var kind: String /* "init" | "get" | "set" */ - var method: Boolean - var shorthand: Boolean - var computed: Boolean -} - -internal external interface FunctionExpression : BaseFunction, BaseExpression { - var id: Identifier? - get() = definedExternally - set(value) = definedExternally - override var type: String /* "FunctionExpression" */ - override var body: BlockStatement -} - -internal external interface SequenceExpression : BaseExpression { - override var type: String /* "SequenceExpression" */ - var expressions: Array -} - -internal external interface UnaryExpression : BaseExpression { - override var type: String /* "UnaryExpression" */ - var operator: String /* "-" | "+" | "!" | "~" | "typeof" | "void" | "delete" */ - var prefix: Boolean - var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface BinaryExpression : BaseExpression { - override var type: String /* "BinaryExpression" */ - var operator: String /* "==" | "!=" | "===" | "!==" | "<" | "<=" | ">" | ">=" | "<<" | ">>" | ">>>" | "+" | "-" | "*" | "/" | "%" | "**" | "|" | "^" | "&" | "in" | "instanceof" */ - var left: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally - var right: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface AssignmentExpression : BaseExpression { - override var type: String /* "AssignmentExpression" */ - var operator: String /* "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "**=" | "<<=" | ">>=" | ">>>=" | "|=" | "^=" | "&=" */ - var left: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ - get() = definedExternally - set(value) = definedExternally - var right: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface UpdateExpression : BaseExpression { - override var type: String /* "UpdateExpression" */ - var operator: String /* "++" | "--" */ - var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally - var prefix: Boolean -} - -internal external interface LogicalExpression : BaseExpression { - override var type: String /* "LogicalExpression" */ - var operator: String /* "||" | "&&" | "??" */ - var left: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally - var right: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface ConditionalExpression : BaseExpression { - override var type: String /* "ConditionalExpression" */ - var test: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally - var alternate: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally - var consequent: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface BaseCallExpression : BaseExpression { - var callee: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression | Super */ - get() = definedExternally - set(value) = definedExternally - var arguments: Array -} - -internal external interface SimpleCallExpression : BaseCallExpression { - override var type: String /* "CallExpression" */ - var optional: Boolean -} - -internal external interface NewExpression : BaseCallExpression { - override var type: String /* "NewExpression" */ -} - -internal external interface MemberExpression : BaseExpression, BasePattern { - override var type: String /* "MemberExpression" */ - var `object`: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression | Super */ - get() = definedExternally - set(value) = definedExternally - var property: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally - var computed: Boolean - var optional: Boolean -} - -internal external interface BasePattern : BaseNode - -internal external interface SwitchCase : BaseNode { - override var type: String /* "SwitchCase" */ - var test: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ - get() = definedExternally - set(value) = definedExternally - var consequent: Array -} - -internal external interface CatchClause : BaseNode { - override var type: String /* "CatchClause" */ - var param: dynamic /* Identifier? | ObjectPattern? | ArrayPattern? | RestElement? | AssignmentPattern? | MemberExpression? */ - get() = definedExternally - set(value) = definedExternally - var body: BlockStatement -} - -internal external interface Identifier : BaseNode, BaseExpression, BasePattern { - override var type: String /* "Identifier" */ - var name: String -} - -internal external interface SimpleLiteral : BaseNode, BaseExpression { - override var type: String /* "Literal" */ - var value: dynamic /* String? | Boolean? | Number? */ - get() = definedExternally - set(value) = definedExternally - var raw: String? - get() = definedExternally - set(value) = definedExternally -} - -internal external interface `T$1` { - var pattern: String - var flags: String -} - -internal external interface RegExpLiteral : BaseNode, BaseExpression { - override var type: String /* "Literal" */ - var value: RegExp? - get() = definedExternally - set(value) = definedExternally - var regex: `T$1` - var raw: String? - get() = definedExternally - set(value) = definedExternally -} - -internal external interface ForOfStatement : BaseForXStatement { - override var type: String /* "ForOfStatement" */ - var await: Boolean -} - -internal external interface Super : BaseNode { - override var type: String /* "Super" */ -} - -internal external interface SpreadElement : BaseNode { - override var type: String /* "SpreadElement" */ - var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface ArrowFunctionExpression : BaseExpression, BaseFunction { - override var type: String /* "ArrowFunctionExpression" */ - var expression: Boolean - override var body: dynamic /* BlockStatement | ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface YieldExpression : BaseExpression { - override var type: String /* "YieldExpression" */ - var argument: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ - get() = definedExternally - set(value) = definedExternally - var delegate: Boolean -} - -internal external interface TemplateLiteral : BaseExpression { - override var type: String /* "TemplateLiteral" */ - var quasis: Array - var expressions: Array -} - -internal external interface TaggedTemplateExpression : BaseExpression { - override var type: String /* "TaggedTemplateExpression" */ - var tag: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally - var quasi: TemplateLiteral -} - -internal external interface `T$2` { - var cooked: String - var raw: String -} - -internal external interface TemplateElement : BaseNode { - override var type: String /* "TemplateElement" */ - var tail: Boolean - var value: `T$2` -} - -internal external interface AssignmentProperty : Property { - override var value: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ - get() = definedExternally - set(value) = definedExternally - override var kind: String /* "init" */ - override var method: Boolean -} - -internal external interface ObjectPattern : BasePattern { - override var type: String /* "ObjectPattern" */ - var properties: Array -} - -internal external interface ArrayPattern : BasePattern { - override var type: String /* "ArrayPattern" */ - var elements: Array -} - -internal external interface RestElement : BasePattern { - override var type: String /* "RestElement" */ - var argument: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface AssignmentPattern : BasePattern { - override var type: String /* "AssignmentPattern" */ - var left: dynamic /* Identifier | ObjectPattern | ArrayPattern | RestElement | AssignmentPattern | MemberExpression */ - get() = definedExternally - set(value) = definedExternally - var right: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface BaseClass : BaseNode { - var superClass: dynamic /* ThisExpression? | ArrayExpression? | ObjectExpression? | FunctionExpression? | ArrowFunctionExpression? | YieldExpression? | SimpleLiteral? | RegExpLiteral? | UnaryExpression? | UpdateExpression? | BinaryExpression? | AssignmentExpression? | LogicalExpression? | MemberExpression? | ConditionalExpression? | SimpleCallExpression? | NewExpression? | SequenceExpression? | TemplateLiteral? | TaggedTemplateExpression? | ClassExpression? | MetaProperty? | Identifier? | AwaitExpression? | ImportExpression? | ChainExpression? */ - get() = definedExternally - set(value) = definedExternally - var body: ClassBody -} - -internal external interface ClassBody : BaseNode { - override var type: String /* "ClassBody" */ - var body: Array -} - -internal external interface MethodDefinition : BaseNode { - override var type: String /* "MethodDefinition" */ - var key: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally - var value: FunctionExpression - var kind: String /* "constructor" | "method" | "get" | "set" */ - var computed: Boolean - var static: Boolean -} - -internal external interface ClassDeclaration : BaseClass, BaseDeclaration { - override var type: String /* "ClassDeclaration" */ - var id: Identifier? -} - -internal external interface ClassExpression : BaseClass, BaseExpression { - override var type: String /* "ClassExpression" */ - var id: Identifier? - get() = definedExternally - set(value) = definedExternally -} - -internal external interface MetaProperty : BaseExpression { - override var type: String /* "MetaProperty" */ - var meta: Identifier - var property: Identifier -} - -internal external interface BaseModuleDeclaration : BaseNode - -internal external interface BaseModuleSpecifier : BaseNode { - var local: Identifier -} - -internal external interface ImportDeclaration : BaseModuleDeclaration { - override var type: String /* "ImportDeclaration" */ - var specifiers: Array - var source: dynamic /* SimpleLiteral | RegExpLiteral */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface ImportSpecifier : BaseModuleSpecifier { - override var type: String /* "ImportSpecifier" */ - var imported: Identifier -} - -internal external interface ImportExpression : BaseExpression { - override var type: String /* "ImportExpression" */ - var source: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface ImportDefaultSpecifier : BaseModuleSpecifier { - override var type: String /* "ImportDefaultSpecifier" */ -} - -internal external interface ImportNamespaceSpecifier : BaseModuleSpecifier { - override var type: String /* "ImportNamespaceSpecifier" */ -} - -internal external interface ExportNamedDeclaration : BaseModuleDeclaration { - override var type: String /* "ExportNamedDeclaration" */ - var declaration: dynamic /* FunctionDeclaration? | VariableDeclaration? | ClassDeclaration? */ - get() = definedExternally - set(value) = definedExternally - var specifiers: Array - var source: dynamic /* SimpleLiteral? | RegExpLiteral? */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface ExportSpecifier : BaseModuleSpecifier { - override var type: String /* "ExportSpecifier" */ - var exported: Identifier -} - -internal external interface ExportDefaultDeclaration : BaseModuleDeclaration { - override var type: String /* "ExportDefaultDeclaration" */ - var declaration: dynamic /* FunctionDeclaration | VariableDeclaration | ClassDeclaration | ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface ExportAllDeclaration : BaseModuleDeclaration { - override var type: String /* "ExportAllDeclaration" */ - var source: dynamic /* SimpleLiteral | RegExpLiteral */ - get() = definedExternally - set(value) = definedExternally -} - -internal external interface AwaitExpression : BaseExpression { - override var type: String /* "AwaitExpression" */ - var argument: dynamic /* ThisExpression | ArrayExpression | ObjectExpression | FunctionExpression | ArrowFunctionExpression | YieldExpression | SimpleLiteral | RegExpLiteral | UnaryExpression | UpdateExpression | BinaryExpression | AssignmentExpression | LogicalExpression | MemberExpression | ConditionalExpression | SimpleCallExpression | NewExpression | SequenceExpression | TemplateLiteral | TaggedTemplateExpression | ClassExpression | MetaProperty | Identifier | AwaitExpression | ImportExpression | ChainExpression */ - get() = definedExternally - set(value) = definedExternally -} diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt deleted file mode 100644 index caab91731..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/stream/stream.kt +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.internal.stream - -import space.kscience.kmath.internal.emitter.Emitter - -internal open external class Stream : Emitter { - open fun pipe(dest: Any, options: Any): Any -} diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt deleted file mode 100644 index 5c091e3a1..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es2015.iterable.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.internal.tsstdlib - -internal external interface IteratorYieldResult { - var done: Boolean? - get() = definedExternally - set(value) = definedExternally - var value: TYield -} - -internal external interface IteratorReturnResult { - var done: Boolean - var value: TReturn -} - -internal external interface Iterator { - fun next(vararg args: Any /* JsTuple<> | JsTuple */): dynamic /* IteratorYieldResult | IteratorReturnResult */ - val `return`: ((value: TReturn) -> dynamic)? - val `throw`: ((e: Any) -> dynamic)? -} - -internal typealias Iterator__1 = Iterator - -internal external interface Iterable - -internal external interface IterableIterator : Iterator__1 diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt deleted file mode 100644 index bb7fd44ca..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/tsstdlib/lib.es5.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -@file:Suppress("UNUSED_TYPEALIAS_PARAMETER", "DEPRECATION") - -package space.kscience.kmath.internal.tsstdlib - -import kotlin.js.RegExp - -internal typealias RegExpMatchArray = Array - -internal typealias RegExpExecArray = Array - -internal external interface RegExpConstructor { - @nativeInvoke - operator fun invoke(pattern: RegExp, flags: String = definedExternally): RegExp - - @nativeInvoke - operator fun invoke(pattern: RegExp): RegExp - - @nativeInvoke - operator fun invoke(pattern: String, flags: String = definedExternally): RegExp - - @nativeInvoke - operator fun invoke(pattern: String): RegExp - var prototype: RegExp - var `$1`: String - var `$2`: String - var `$3`: String - var `$4`: String - var `$5`: String - var `$6`: String - var `$7`: String - var `$8`: String - var `$9`: String - var lastMatch: String -} - -internal typealias Record = Any - -internal external interface ConcatArray { - var length: Number - - @nativeGetter - operator fun get(n: Number): T? - - @nativeSetter - operator fun set(n: Number, value: T) - fun join(separator: String = definedExternally): String - fun slice(start: Number = definedExternally, end: Number = definedExternally): Array -} - -internal external interface ArrayConstructor { - fun from(iterable: Iterable): Array - fun from(iterable: ArrayLike): Array - fun from(iterable: Iterable, mapfn: (v: T, k: Number) -> U, thisArg: Any = definedExternally): Array - fun from(iterable: Iterable, mapfn: (v: T, k: Number) -> U): Array - fun from(iterable: ArrayLike, mapfn: (v: T, k: Number) -> U, thisArg: Any = definedExternally): Array - fun from(iterable: ArrayLike, mapfn: (v: T, k: Number) -> U): Array - fun of(vararg items: T): Array - - @nativeInvoke - operator fun invoke(arrayLength: Number = definedExternally): Array - - @nativeInvoke - operator fun invoke(): Array - - @nativeInvoke - operator fun invoke(arrayLength: Number): Array - - @nativeInvoke - operator fun invoke(vararg items: T): Array - fun isArray(arg: Any): Boolean - var prototype: Array -} - -internal external interface ArrayLike { - var length: Number - - @nativeGetter - operator fun get(n: Number): T? - - @nativeSetter - operator fun set(n: Number, value: T) -} - -internal typealias Extract = Any - -internal external interface PromiseLike { - fun then( - onfulfilled: ((value: T) -> Any?)? = definedExternally, - onrejected: ((reason: Any) -> Any?)? = definedExternally - ): PromiseLike -} diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt deleted file mode 100644 index 52dd64a5e..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/lib.dom.WebAssembly.module_dukat.kt +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -@file:JsQualifier("WebAssembly") - -@file:Suppress( - "INTERFACE_WITH_SUPERCLASS", - "OVERRIDING_FINAL_MEMBER", - "RETURN_TYPE_MISMATCH_ON_OVERRIDE", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", - "ClassName", -) - -package space.kscience.kmath.internal.webassembly - -import space.kscience.kmath.internal.tsstdlib.PromiseLike -import org.khronos.webgl.ArrayBuffer -import org.khronos.webgl.ArrayBufferView -import org.khronos.webgl.Uint8Array -import org.w3c.fetch.Response -import kotlin.js.Promise - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -internal external interface CompileError { - companion object { - var prototype: CompileError - } -} - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -internal external interface Global { - var value: Any - fun valueOf(): Any - - companion object { - var prototype: Global - } -} - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -@JsName("Instance") -internal external interface Instance1 { - var exports: Exports - - companion object { - var prototype: Instance - } -} - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -internal external interface LinkError { - companion object { - var prototype: LinkError - } -} - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -internal external interface Memory { - var buffer: ArrayBuffer - fun grow(delta: Number): Number - - companion object { - var prototype: Memory - } -} - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -@JsName("Module") -internal external interface Module1 { - companion object { - var prototype: Module - fun customSections(moduleObject: Module, sectionName: String): Array - fun exports(moduleObject: Module): Array - fun imports(moduleObject: Module): Array - } -} - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -internal external interface RuntimeError { - companion object { - var prototype: RuntimeError - } -} - -@Suppress("NESTED_CLASS_IN_EXTERNAL_INTERFACE") -internal external interface Table { - var length: Number - fun get(index: Number): Function<*>? - fun grow(delta: Number): Number - fun set(index: Number, value: Function<*>?) - - companion object { - var prototype: Table - } -} - -internal external interface GlobalDescriptor { - var mutable: Boolean? - get() = definedExternally - set(value) = definedExternally - var value: String /* "f32" | "f64" | "i32" | "i64" */ -} - -internal external interface MemoryDescriptor { - var initial: Number - var maximum: Number? - get() = definedExternally - set(value) = definedExternally -} - -internal external interface ModuleExportDescriptor { - var kind: String /* "function" | "global" | "memory" | "table" */ - var name: String -} - -internal external interface ModuleImportDescriptor { - var kind: String /* "function" | "global" | "memory" | "table" */ - var module: String - var name: String -} - -internal external interface TableDescriptor { - var element: String /* "anyfunc" */ - var initial: Number - var maximum: Number? - get() = definedExternally - set(value) = definedExternally -} - -internal external interface WebAssemblyInstantiatedSource { - var instance: Instance - var module: Module -} - -internal external fun compile(bytes: ArrayBufferView): Promise - -internal external fun compile(bytes: ArrayBuffer): Promise - -internal external fun compileStreaming(source: Response): Promise - -internal external fun compileStreaming(source: Promise): Promise - -internal external fun instantiate( - bytes: ArrayBufferView, - importObject: Imports = definedExternally, -): Promise - -internal external fun instantiate(bytes: ArrayBufferView): Promise - -internal external fun instantiate( - bytes: ArrayBuffer, - importObject: Imports = definedExternally, -): dynamic /* Promise | Promise */ - -internal external fun instantiate(bytes: ArrayBuffer): dynamic /* Promise | Promise */ - -internal external fun instantiate(moduleObject: Module, importObject: Imports = definedExternally): Promise - -internal external fun instantiate(moduleObject: Module): Promise - -internal external fun instantiateStreaming( - response: Response, - importObject: Imports = definedExternally, -): Promise - -internal external fun instantiateStreaming(response: Response): Promise - -internal external fun instantiateStreaming( - response: PromiseLike, - importObject: Imports = definedExternally, -): Promise - -internal external fun instantiateStreaming(response: PromiseLike): Promise - -internal external fun validate(bytes: ArrayBufferView): Boolean - -internal external fun validate(bytes: ArrayBuffer): Boolean - -internal external interface `T$0` { - var name: String - var kind: String -} - -internal external interface `T$1` { - var module: String - var name: String - var kind: String -} - -internal open external class Module { - constructor(bufferSource: ArrayBuffer) - constructor(bufferSource: Uint8Array) - - companion object { - fun customSections(module: Module, sectionName: String): Array - fun exports(module: Module): Array<`T$0`> - fun imports(module: Module): Array<`T$1`> - } -} - -@JsName("Instance") -internal open external class Instance(module: Module, importObject: Any = definedExternally) { - open var exports: Any -} - -@JsName("Memory") -internal open external class Memory1(memoryDescriptor: MemoryDescriptor) { - open var buffer: ArrayBuffer - open fun grow(numPages: Number): Number -} - -@JsName("Table") -internal open external class Table1(tableDescriptor: TableDescriptor) { - open var length: Number - open fun get(index: Number): Function<*> - open fun grow(numElements: Number): Number - open fun set(index: Number, value: Function<*>) -} - -internal external fun compile(bufferSource: Uint8Array): Promise - -internal external interface ResultObject { - var module: Module - var instance: Instance -} - -internal external fun instantiate( - bufferSource: Uint8Array, - importObject: Any = definedExternally, -): Promise - -internal external fun instantiate(bufferSource: Uint8Array): Promise - -internal external fun validate(bufferSource: Uint8Array): Boolean diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt deleted file mode 100644 index d59a52701..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/internal/webassembly/nonDeclarations.WebAssembly.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -@file:Suppress( - "INTERFACE_WITH_SUPERCLASS", - "OVERRIDING_FINAL_MEMBER", - "RETURN_TYPE_MISMATCH_ON_OVERRIDE", - "CONFLICTING_OVERLOADS", - "NO_EXPLICIT_VISIBILITY_IN_API_MODE_WARNING", -) - -package space.kscience.kmath.internal.webassembly - -import space.kscience.kmath.internal.tsstdlib.Record - -internal typealias Exports = Record | Global | Memory | Table */> - -internal typealias ModuleImports = Record | Global | Memory | Table | Number */> - -internal typealias Imports = Record - -internal typealias CompileError1 = Error - -internal typealias LinkError1 = Error - -internal typealias RuntimeError1 = Error 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 deleted file mode 100644 index 5b6cf65db..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/WasmBuilder.kt +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.wasm.internal - -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.MST.* -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.internal.binaryen.* -import space.kscience.kmath.internal.webassembly.Instance -import space.kscience.kmath.operations.* -import space.kscience.kmath.internal.binaryen.Module as BinaryenModule -import space.kscience.kmath.internal.webassembly.Module as WasmModule - -private val spreader = eval("(obj, args) => obj(...args)") - -@Suppress("UnsafeCastFromDynamic") -internal sealed class WasmBuilder( - val binaryenType: Type, - val algebra: Algebra, - val target: MST, -) where T : Number { - val keys: MutableList = mutableListOf() - lateinit var ctx: BinaryenModule - - open fun visitSymbolic(mst: Symbol): ExpressionRef { - algebra.bindSymbolOrNull(mst)?.let { return visitNumeric(Numeric(it)) } - - var idx = keys.indexOf(mst) - - if (idx == -1) { - keys += mst - idx = keys.lastIndex - } - - return ctx.local.get(idx, binaryenType) - } - - abstract fun visitNumeric(mst: Numeric): ExpressionRef - - open fun visitUnary(mst: Unary): ExpressionRef = - error("Unary operation ${mst.operation} not defined in $this") - - open fun visitBinary(mst: Binary): ExpressionRef = - error("Binary operation ${mst.operation} not defined in $this") - - open fun createModule(): BinaryenModule = js("new \$module\$binaryen.Module()") - - fun visit(mst: MST): ExpressionRef = when (mst) { - is Symbol -> visitSymbolic(mst) - is Numeric -> visitNumeric(mst) - - is Unary -> when { - algebra is NumericAlgebra && mst.value is Numeric -> visitNumeric( - Numeric(algebra.unaryOperationFunction(mst.operation)(algebra.number((mst.value as Numeric).value)))) - - else -> visitUnary(mst) - } - - is Binary -> when { - algebra is NumericAlgebra && mst.left is Numeric && mst.right is Numeric -> visitNumeric(Numeric( - algebra.binaryOperationFunction(mst.operation) - .invoke(algebra.number((mst.left as Numeric).value), algebra.number((mst.right as Numeric).value)) - )) - - else -> visitBinary(mst) - } - } - - val instance by lazy { - val c = WasmModule(with(createModule()) { - ctx = this - val expr = visit(target) - - addFunction( - "executable", - createType(Array(keys.size) { binaryenType }), - binaryenType, - arrayOf(), - expr - ) - - setOptimizeLevel(3) - optimizeFunction("executable") - addFunctionExport("executable", "executable") - val res = emitBinary() - dispose() - res - }) - - val i = Instance(c, js("{}") as Any) - val symbols = keys - keys.clear() - - Expression { args -> - val params = symbols.map(args::getValue).toTypedArray() - spreader(i.exports.asDynamic().executable, params) as T - } - } -} - -internal class DoubleWasmBuilder(target: MST) : WasmBuilder(f64, DoubleField, target) { - override fun createModule(): BinaryenModule = readBinary(f64StandardFunctions) - - override fun visitNumeric(mst: Numeric): ExpressionRef = ctx.f64.const(mst.value) - - override fun visitUnary(mst: Unary): ExpressionRef = when (mst.operation) { - GroupOperations.MINUS_OPERATION -> ctx.f64.neg(visit(mst.value)) - GroupOperations.PLUS_OPERATION -> visit(mst.value) - PowerOperations.SQRT_OPERATION -> ctx.f64.sqrt(visit(mst.value)) - TrigonometricOperations.SIN_OPERATION -> ctx.call("sin", arrayOf(visit(mst.value)), f64) - TrigonometricOperations.COS_OPERATION -> ctx.call("cos", arrayOf(visit(mst.value)), f64) - TrigonometricOperations.TAN_OPERATION -> ctx.call("tan", arrayOf(visit(mst.value)), f64) - TrigonometricOperations.ASIN_OPERATION -> ctx.call("asin", arrayOf(visit(mst.value)), f64) - TrigonometricOperations.ACOS_OPERATION -> ctx.call("acos", arrayOf(visit(mst.value)), f64) - TrigonometricOperations.ATAN_OPERATION -> ctx.call("atan", arrayOf(visit(mst.value)), f64) - ExponentialOperations.SINH_OPERATION -> ctx.call("sinh", arrayOf(visit(mst.value)), f64) - ExponentialOperations.COSH_OPERATION -> ctx.call("cosh", arrayOf(visit(mst.value)), f64) - ExponentialOperations.TANH_OPERATION -> ctx.call("tanh", arrayOf(visit(mst.value)), f64) - ExponentialOperations.ASINH_OPERATION -> ctx.call("asinh", arrayOf(visit(mst.value)), f64) - ExponentialOperations.ACOSH_OPERATION -> ctx.call("acosh", arrayOf(visit(mst.value)), f64) - ExponentialOperations.ATANH_OPERATION -> ctx.call("atanh", arrayOf(visit(mst.value)), f64) - ExponentialOperations.EXP_OPERATION -> ctx.call("exp", arrayOf(visit(mst.value)), f64) - ExponentialOperations.LN_OPERATION -> ctx.call("log", arrayOf(visit(mst.value)), f64) - else -> super.visitUnary(mst) - } - - override fun visitBinary(mst: Binary): ExpressionRef = when (mst.operation) { - GroupOperations.PLUS_OPERATION -> ctx.f64.add(visit(mst.left), visit(mst.right)) - GroupOperations.MINUS_OPERATION -> ctx.f64.sub(visit(mst.left), visit(mst.right)) - RingOperations.TIMES_OPERATION -> ctx.f64.mul(visit(mst.left), visit(mst.right)) - FieldOperations.DIV_OPERATION -> ctx.f64.div(visit(mst.left), visit(mst.right)) - PowerOperations.POW_OPERATION -> ctx.call("pow", arrayOf(visit(mst.left), visit(mst.right)), f64) - else -> super.visitBinary(mst) - } -} - -internal class IntWasmBuilder(target: MST) : WasmBuilder(i32, IntRing, target) { - override fun visitNumeric(mst: Numeric): ExpressionRef = ctx.i32.const(mst.value) - - override fun visitUnary(mst: Unary): ExpressionRef = when (mst.operation) { - GroupOperations.MINUS_OPERATION -> ctx.i32.sub(ctx.i32.const(0), visit(mst.value)) - GroupOperations.PLUS_OPERATION -> visit(mst.value) - else -> super.visitUnary(mst) - } - - override fun visitBinary(mst: Binary): ExpressionRef = when (mst.operation) { - GroupOperations.PLUS_OPERATION -> ctx.i32.add(visit(mst.left), visit(mst.right)) - GroupOperations.MINUS_OPERATION -> ctx.i32.sub(visit(mst.left), visit(mst.right)) - RingOperations.TIMES_OPERATION -> ctx.i32.mul(visit(mst.left), visit(mst.right)) - else -> super.visitBinary(mst) - } -} diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt deleted file mode 100644 index fe9c22c18..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/internal/f64StandardFunctions.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.wasm.internal - -import space.kscience.kmath.internal.base64.toUint8Array - -internal val f64StandardFunctions by lazy { toUint8Array(B) } - -private const val B = - "AGFzbQEAAAABMghgAABgAXwBfGACfHwBfGAFf39/f38Bf2ACfH8Bf2ADfHx/AXxgAnx/AXxgA39/fwF/AxsaAAEBAQEBAQIDBAUBAQEBAQEBAgYBAQUBAQcEBQFwAQEBBQMBAAIGFQN/AUGgnwQLfwBBoJ8EC38AQaAfCwclAwZtZW1vcnkCAAtfX2hlYXBfYmFzZQMBCl9fZGF0YV9lbmQDAgrpaxoCAAvPBQMBfgF/AnwCQAJAAkAgAL0iAUIgiKdB/////wdxIgJBgIDA/wNJDQAgAkGAgMCAfGogAadyRQ0BRAAAAAAAAAAAIAAgAKGjDwsCQAJAIAJB/////gNLDQBEGC1EVPsh+T8hAyACQYGAgOMDSQ0BRAdcFDMmppE8IAAgAKIiAyADIAMgAyADIANECff9DeE9Aj+iRIiyAXXg70k/oKJEO49otSiCpL+gokRVRIgOVcHJP6CiRH1v6wMS1tS/oKJEVVVVVVVVxT+goiADIAMgAyADRIKSLrHFuLM/okRZAY0bbAbmv6CiRMiKWZzlKgBAoKJESy2KHCc6A8CgokQAAAAAAADwP6CjIACioSAAoUQYLURU+yH5P6APCyABQn9XDQJEAAAAAAAA8D8gAKFEAAAAAAAA4D+iIgAgAJ8iBL1CgICAgHCDvyIDIAOioSAEIAOgoyAEIAAgACAAIAAgACAARAn3/Q3hPQI/okSIsgF14O9JP6CiRDuPaLUogqS/oKJEVUSIDlXByT+gokR9b+sDEtbUv6CiRFVVVVVVVcU/oKIgACAAIAAgAESCki6xxbizP6JEWQGNG2wG5r+gokTIilmc5SoAQKCiREstihwnOgPAoKJEAAAAAAAA8D+go6KgIAOgIgAgAKAhAwsgAw8LRBgtRFT7IQlARAAAAAAAAAAAIAFCAFMbDwtEGC1EVPsh+T8gAEQAAAAAAADwP6BEAAAAAAAA4D+iIgCfIgMgAyAAIAAgACAAIAAgAEQJ9/0N4T0CP6JEiLIBdeDvST+gokQ7j2i1KIKkv6CiRFVEiA5Vwck/oKJEfW/rAxLW1L+gokRVVVVVVVXFP6CiIAAgACAAIABEgpIuscW4sz+iRFkBjRtsBua/oKJEyIpZnOUqAECgokRLLYocJzoDwKCiRAAAAAAAAPA/oKOiRAdcFDMmppG8oKChIgAgAKALdwEBfwJAIAC9QjSIp0H/D3EiAUH/B0sNACAARAAAAAAAAPC/oCIAIAAgAKIgACAAoKCfoBARDwsCQCABQZgISw0AIAAgAKBEAAAAAAAA8L8gACAAokQAAAAAAADwv6CfIACgo6AQEA8LIAAQEETvOfr+Qi7mP6AL0gQDAX4BfwN8AkACQAJAAkACQCAAvSIBQiCIp0H/////B3EiAkGAgMD/A0kNACACQYCAwIB8aiABp3JFDQFEAAAAAAAAAAAgACAAoaMPCwJAIAJB/////gNLDQAgAkGAgEBqQYCAgPIDTw0CIAAPC0QAAAAAAADwPyAAmaFEAAAAAAAA4D+iIgAgACAAIAAgACAARAn3/Q3hPQI/okSIsgF14O9JP6CiRDuPaLUogqS/oKJEVUSIDlXByT+gokR9b+sDEtbUv6CiRFVVVVVVVcU/oKIgACAAIAAgAESCki6xxbizP6JEWQGNG2wG5r+gokTIilmc5SoAQKCiREstihwnOgPAoKJEAAAAAAAA8D+goyEDIACfIQQgAkGz5rz/A0kNAkQYLURU+yH5PyAEIAQgA6KgIgAgAKBEB1wUMyamkbygoSEADAMLIABEGC1EVPsh+T+iRAAAAAAAAHA4oA8LIAAgAKIiBCAEIAQgBCAEIARECff9DeE9Aj+iRIiyAXXg70k/oKJEO49otSiCpL+gokRVRIgOVcHJP6CiRH1v6wMS1tS/oKJEVVVVVVVVxT+goiAEIAQgBCAERIKSLrHFuLM/okRZAY0bbAbmv6CiRMiKWZzlKgBAoKJESy2KHCc6A8CgokQAAAAAAADwP6CjIACiIACgDwtEGC1EVPsh6T8gBL1CgICAgHCDvyIFIAWgoSAEIASgIAOiRAdcFDMmppE8IAAgBSAFoqEgBCAFoKMiACAAoKGhoUQYLURU+yHpP6AhAAsgAJogACABQgBTGwvbAQQBfwF+AX8BfCMAQRBrIgEkACAAvSICQv///////////wCDvyEAAkACQCACQjSIp0H/D3EiA0GZCEkNACAAEBBE7zn6/kIu5j+gIQAMAQsCQCADQYAISQ0AIAAgAKBEAAAAAAAA8D8gACAAokQAAAAAAADwP6CfIACgo6AQECEADAELAkAgA0HlB0kNACAAIACiIgQgBEQAAAAAAADwP6CfRAAAAAAAAPA/oKMgAKAQESEADAELIAEgAEQAAAAAAABwR6A5AwgLIAFBEGokACAAmiAAIAJCAFMbC6gEBAF/AX4DfwJ8IwBBEGshASAAvSICQj+IpyEDAkACQAJAIAJCIIinQf////8HcSIEQYCAwKAESQ0AIAJC////////////AINCgICAgICAgPj/AFYNAUQYLURU+yH5v0QYLURU+yH5PyADGw8LAkACQCAEQf//7/4DSw0AQX8hBSAEQf////EDSw0BIARB//8/Sw0CIAEgALY4AgwgAA8LIACZIQACQAJAAkAgBEH//8v/A0sNACAEQf//l/8DSw0BIAAgAKBEAAAAAAAA8L+gIABEAAAAAAAAAECgoyEAQQAhBQwDCyAEQf//jYAESw0BIABEAAAAAAAA+L+gIABEAAAAAAAA+D+iRAAAAAAAAPA/oKMhAEECIQUMAgsgAEQAAAAAAADwv6AgAEQAAAAAAADwP6CjIQBBASEFDAELRAAAAAAAAPC/IACjIQBBAyEFCyAAIAAgAKIiBiAGoiIHIAcgByAHIAdEL2xqLES0or+iRJr93lIt3q2/oKJEbZp0r/Kws7+gokRxFiP+xnG8v6CiRMTrmJmZmcm/oKIgBiAHIAcgByAHIAdEEdoi4zqtkD+iROsNdiRLe6k/oKJEUT3QoGYNsT+gokRuIEzFzUW3P6CiRP+DAJIkScI/oKJEDVVVVVVV1T+goqCiIQcgBUF/TA0BIAVBA3QiBEGACGorAwAgByAEQaAIaisDAKEgAKGhIgCaIAAgAxshAAsgAA8LIAAgB6ELtgEEAX8BfgF/AXwjAEEQayIBJAAgAL0iAkL///////////8Ag78hAAJAAkACQCACQjSIp0H/D3EiA0H9B0sNACADQd4HSw0BIAMNAiABIAC2OAIMDAILIABEAAAAAAAA8D8gAKGjIgAgAKAQEUQAAAAAAADgP6IhAAwBCyAAIACgIgQgBCAAokQAAAAAAADwPyAAoaOgEBFEAAAAAAAA4D+iIQALIAFBEGokACAAmiAAIAJCAFMbC5IBAQN8RAAAAAAAAPA/IAAgAKIiAkQAAAAAAADgP6IiA6EiBEQAAAAAAADwPyAEoSADoSACIAIgAiACRJAVyxmgAfo+okR3UcEWbMFWv6CiRExVVVVVVaU/oKIgAiACoiIDIAOiIAIgAkTUOIi+6fqovaJExLG0vZ7uIT6gokStUpyAT36SvqCioKIgACABoqGgoAuEFgYHfwF8Cn8BfAN/AnwjAEGwBGsiBSQAIAIgAkF9akEYbSIGQQAgBkEAShsiB0FobGohCAJAIARBAnRBwAhqKAIAIgkgA0F/aiICakEASA0AIAkgA2ohCiAHIAJrIQIgB0EBaiADa0ECdEHQCGohCyAFQcACaiEGA0ACQAJAIAJBAEgNACALKAIAtyEMDAELRAAAAAAAAAAAIQwLIAYgDDkDACAGQQhqIQYgC0EEaiELIAJBAWohAiAKQX9qIgoNAAsLIAhBaGohDQJAAkAgA0EBSA0AIAVBwAJqIANBA3RqQXhqIQ5BACEKA0BEAAAAAAAAAAAhDCAAIQIgAyELIA4hBgNAIAwgAisDACAGKwMAoqAhDCACQQhqIQIgBkF4aiEGIAtBf2oiCw0ACyAFIApBA3RqIAw5AwAgDkEIaiEOIAogCUghAiAKQQFqIQogAg0ADAILCyAFQQAgCUEAIAlBAEobQQN0QQhqEBkaC0EXIA1rIQ9BGCANayEQIAVB4ANqIAlBAnRqQXxqIREgBUHgA2pBfGohEiAFQXhqIRMgBUEIciEUIAkhBgN/IAUgBkEDdCIVaisDACEMAkAgBkEBSCIWDQAgEyAVaiECIAVB4ANqIQsgBiEKA0ACQAJAIAxEAAAAAAAAcD6iIheZRAAAAAAAAOBBYw0AQYCAgIB4IQ4MAQsgF6ohDgsCQAJAIAwgDrciF0QAAAAAAABwwaKgIgyZRAAAAAAAAOBBYw0AQYCAgIB4IQ4MAQsgDKohDgsgCyAONgIAIAtBBGohCyACKwMAIBegIQwgAkF4aiECIApBf2oiCg0ACwsCQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAMIA0QEyIMIAxEAAAAAAAAwD+inEQAAAAAAAAgwKKgIgyZRAAAAAAAAOBBYw0AQYCAgIB4IRggDEGAgICAeLehIQwgDUEBSCIZRQ0BDAILIAwgDKoiGLehIQwgDUEBSCIZDQELIAVB4ANqIAZBAnRqQXxqIgIgAigCACICIAIgEHUiAiAQdGsiCzYCACACIBhqIRggCyAPdSIaQQFIDQIMAQsCQCANRQ0AQQIhGiAMRAAAAAAAAOA/ZkEBc0UNAUEAIRogDEQAAAAAAAAAAGENAwwECyAFQeADaiAGQQJ0akF8aigCAEEXdSIaQQFIDQELAkACQCAWDQBBACEWIAVB4ANqIQIgBiEOA0AgAigCACELQf///wchCgJAAkAgFg0AIAtFDQFBASEWQYCAgAghCgsgAiAKIAtrNgIAIAJBBGohAiAOQX9qIg4NAQwDC0EAIRYgAkEEaiECIA5Bf2oiDg0ADAILC0EAIRYLAkACQAJAIBkNACANQQJGDQEgDUEBRw0AIAVB4ANqIAZBAnRqQXxqIgIgAigCAEH///8DcTYCAAsgGEEBaiEYIBpBAkcNAgwBCyAFQeADaiAGQQJ0akF8aiICIAIoAgBB////AXE2AgAgGEEBaiEYIBpBAkcNAQtEAAAAAAAA8D8gDKEhDEECIRogFkUNACAMRAAAAAAAAPA/IA0QE6EiDEQAAAAAAAAAAGENAQwCCyAMRAAAAAAAAAAAYg0BCwJAIAYgCUwNACASIAZBAnRqIQJBACELIAYhCgNAIAIoAgAgC3IhCyACQXxqIQIgCkF/aiIKIAlKDQALIAsNAgsgESECIAYhDgNAIA5BAWohDiACKAIAIQsgAkF8aiECIAtFDQALIAZBAWohAgJAIANBAUgNACAFQcACaiADIAZqQQN0aiEWA0AgBUHAAmogBiADakEDdGogAiIKIAdqQQJ0QdAIaigCALc5AwBEAAAAAAAAAAAhDCAAIQIgFiEGIAMhCwNAIAwgAisDACAGKwMAoqAhDCACQQhqIQIgBkF4aiEGIAtBf2oiCw0ACyAFIApBA3RqIAw5AwAgFkEIaiEWIApBAWohAiAKIQYgCiAOSA0ADAsLCyAUIBVqQQAgDiACIA4gAkobIAZrQQN0EBkaIAcgBmpBAnRB1AhqIQIgBUHAAmogAyAGakEDdGohCwNAIAsgAigCALc5AwAgAkEEaiECIAtBCGohCyAGQQFqIgYgDkgNAAsgDiEGDAoLAkAgDEEAIA1rEBMiDEQAAAAAAABwQWZBAXNFDQAgDJlEAAAAAAAA4EFjDQJBgICAgHghAgwDCyAGQQJ0IQsgDEQAAAAAAABwPqIiF5lEAAAAAAAA4EFjDQNBgICAgHghAgwECyAFQeADaiAGQQJ0akF8aiECIA0hCANAIAZBf2ohBiAIQWhqIQggAigCACELIAJBfGohAiALRQ0AC0EAIQ4gBkEATg0FDAYLIAyqIQILIA0hCAwCCyAXqiECCyAFQeADaiALaiELAkACQCAMIAK3RAAAAAAAAHDBoqAiDJlEAAAAAAAA4EFjDQBBgICAgHghCgwBCyAMqiEKCyALIAo2AgAgBkEBaiEGCyAFQeADaiAGQQJ0aiACNgIAQQAhDiAGQQBIDQELIAZBAWohCkQAAAAAAADwPyAIEBMhDCAFQeADaiAGQQJ0aiECIAUgBkEDdGohCwNAIAsgDCACKAIAt6I5AwAgAkF8aiECIAtBeGohCyAMRAAAAAAAAHA+oiEMIApBf2oiCiAOSg0ACyAGQQBIDQAgBSAGQQN0aiEOIAYhAgNAIAYgAiIDayEWRAAAAAAAAAAAIQxBACECQQAhCwJAA0AgDCACQaAeaisDACAOIAJqKwMAoqAhDCALIAlODQEgAkEIaiECIAsgFkkhCiALQQFqIQsgCg0ACwsgBUGgAWogFkEDdGogDDkDACAOQXhqIQ4gA0F/aiECIANBAEoNAAsLAkACQAJAAkACQAJAAkACQCAEQX9qQQJJDQAgBEUNASAEQQNHDQdEAAAAAAAAAAAhGwJAIAZBAUgNACAFQaABaiAGQQN0aiILQXhqIQIgCysDACEMIAYhCwNAIAIgAisDACIcIAygIhc5AwAgAkEIaiAMIBwgF6GgOQMAIAJBeGohAiAXIQwgC0F/aiILQQBKDQALIAZBAkgNACAFQaABaiAGQQN0aiILQXhqIQIgCysDACEMIAYhCwNAIAIgAisDACIcIAygIhc5AwAgAkEIaiAMIBwgF6GgOQMAIAJBeGohAiAXIQwgC0F/aiILQQFKDQALIAZBAkgNACAFQaABaiAGQQN0aiECRAAAAAAAAAAAIRsDQCAbIAIrAwCgIRsgAkF4aiECIAZBf2oiBkEBSg0ACwsgBSsDoAEhDCAaRQ0EIAEgDJo5AwAgASAFKwOoAZo5AwggASAbmjkDEAwHCyAGQQBIDQEgBkEBaiELIAVBoAFqIAZBA3RqIQJEAAAAAAAAAAAhDANAIAwgAisDAKAhDCACQXhqIQIgC0F/aiILQQBKDQAMAwsLIAZBAEgNAyAGQQFqIQsgBUGgAWogBkEDdGohAkQAAAAAAAAAACEMA0AgDCACKwMAoCEMIAJBeGohAiALQX9qIgtBAEoNAAwFCwtEAAAAAAAAAAAhDAsgASAMmiAMIBobOQMAIAUrA6ABIAyhIQwCQCAGQQFIDQAgBUGgAWpBCHIhAgNAIAwgAisDAKAhDCACQQhqIQIgBkF/aiIGDQALCyABIAyaIAwgGhs5AwgMAwsgASAMOQMAIAEgBSkDqAE3AwggASAbOQMQDAILRAAAAAAAAAAAIQwLIAEgDJogDCAaGzkDAAsgBUGwBGokACAYQQdxDwsgDiEGDAALC8MKBgF/AX4DfwN8AX8BfCMAQTBrIgIkACAAvSIDQj+IpyEEAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCADQiCIpyIFQf////8HcSIGQfrUvYAESw0AIAVB//8/cUH7wyRGDQMgBkH8souABEsNASAERQ0GIAEgAEQAAEBU+yH5P6AiAEQxY2IaYbTQPaAiBzkDACABIAAgB6FEMWNiGmG00D2gOQMIIAJBMGokAEF/DwsCQCAGQbuM8YAESw0AIAZBvPvXgARLDQIgBkH8ssuABEYNAyAERQ0KIAEgAEQAADB/fNkSQKAiAETKlJOnkQ7pPaAiBzkDACABIAAgB6FEypSTp5EO6T2gOQMIIAJBMGokAEF9DwsgBkH6w+SJBE0NAiAGQYCAwP8HSQ0DIAEgACAAoSIAOQMAIAEgADkDCCACQTBqJABBAA8LIARFDQUgASAARAAAQFT7IQlAoCIARDFjYhphtOA9oCIHOQMAIAEgACAHoUQxY2IaYbTgPaA5AwggAkEwaiQAQX4PCyAGQfvD5IAERw0CCyABIAAgAESDyMltMF/kP6JEAAAAAAAAOEOgRAAAAAAAADjDoCIHRAAAQFT7Ifm/oqAiCCAHRDFjYhphtNA9oiIJoSIAOQMAIAZBFHYiCiAAvUI0iKdB/w9xa0ERSCEFAkACQAJAIAeZRAAAAAAAAOBBYw0AQYCAgIB4IQYgBUUNAQwCCyAHqiEGIAUNAQsgASAIIAdEAABgGmG00D2iIgChIgsgB0RzcAMuihmjO6IgCCALoSAAoaEiCaEiADkDAAJAIAogAL1CNIinQf8PcWtBMkgNACABIAsgB0QAAAAuihmjO6IiAKEiCCAHRMFJICWag3s5oiALIAihIAChoSIJoSIAOQMADAELIAshCAsgASAIIAChIAmhOQMIIAJBMGokACAGDwsgA0L/////////B4NCgICAgICAgLDBAIS/IgCZRAAAAAAAAOBBYw0DQYCAgIB4IQUMBAsgBEUNBSABIABEAABAVPshGUCgIgBEMWNiGmG08D2gIgc5AwAgASAAIAehRDFjYhphtPA9oDkDCCACQTBqJABBfA8LIAEgAEQAAEBU+yH5v6AiAEQxY2IaYbTQvaAiBzkDACABIAAgB6FEMWNiGmG00L2gOQMIIAJBMGokAEEBDwsgASAARAAAQFT7IQnAoCIARDFjYhphtOC9oCIHOQMAIAEgACAHoUQxY2IaYbTgvaA5AwggAkEwaiQAQQIPCyAAqiEFCyACIAW3Igc5AxACQAJAIAAgB6FEAAAAAAAAcEGiIgCZRAAAAAAAAOBBYw0AQYCAgIB4IQUMAQsgAKohBQsgAiAFtyIHOQMYIAIgACAHoUQAAAAAAABwQaIiADkDICAARAAAAAAAAAAAYg0CIAJBEGpBCHIhBUECIQoDQCAKQX9qIQogBSsDACEAIAVBeGohBSAARAAAAAAAAAAAYQ0ADAQLCyABIABEAAAwf3zZEsCgIgBEypSTp5EO6b2gIgc5AwAgASAAIAehRMqUk6eRDum9oDkDCCACQTBqJABBAw8LIAEgAEQAAEBU+yEZwKAiAEQxY2IaYbTwvaAiBzkDACABIAAgB6FEMWNiGmG08L2gOQMIIAJBMGokAEEEDwtBAiEKCyACQRBqIAIgBkEUdkHqd2ogCkEBakEBEAghBSACKwMAIQACQCAERQ0AIAEgAJo5AwAgASACKwMImjkDCCACQTBqJABBACAFaw8LIAEgADkDACABIAIpAwg3AwggAkEwaiQAIAULmwEBA3wgACAAoiIDIAMgA6KiIANEfNXPWjrZ5T2iROucK4rm5Vq+oKIgAyADRH3+sVfjHcc+okTVYcEZoAEqv6CiRKb4EBEREYE/oKAhBCADIACiIQUCQCACRQ0AIAAgBURJVVVVVVXFP6IgAyABRAAAAAAAAOA/oiAFIASioaIgAaGgoQ8LIAUgAyAEokRJVVVVVVXFv6CiIACgC5ICAgJ/AXwjAEEQayIBJAACQAJAAkAgAL1CIIinQf////8HcSICQfvDpP8DSw0AIAJBncGa8gNLDQEgASAARAAAAAAAAHBHoDkDACABQRBqJABEAAAAAAAA8D8PCyACQYCAwP8HSQ0BIAFBEGokACAAIAChDwsgAEQAAAAAAAAAABAHIQAgAUEQaiQAIAAPCyAAIAEQCSECIAErAwghACABKwMAIQMCQAJAAkAgAkEDcSICQQJGDQAgAkEBRg0BIAINAiADIAAQByEAIAFBEGokACAADwsgAyAAEAchACABQRBqJAAgAJoPCyADIABBARAKIQAgAUEQaiQAIACaDwsgAyAAQQEQCiEAIAFBEGokACAACyQAIABEi90aFWYglsCgEA5EAAAAAAAAwH+iRAAAAAAAAMB/ogvaAQMBfwF+AX8jAEEQayIBJAAgAL1C////////////AIMiAr8hAAJAAkACQCACQiCIpyIDQcHcmP8DSw0AIANB//+/8gNLDQEgASAARAAAAAAAAHBHoDkDCCABQRBqJABEAAAAAAAA8D8PCyADQcHcmIQESw0BIAAQDiEAIAFBEGokACAARAAAAAAAAPA/IACjoEQAAAAAAADgP6IPCyABQRBqJAAgABAPIgAgAKIgAEQAAAAAAADwP6AiACAAoKNEAAAAAAAA8D+gDwsgABAMIQAgAUEQaiQAIAALoAQEAX8BfgJ/A3wjAEEQayIBJAAgAL0iAkI/iKchAwJAAkACQAJAAkACQAJAAkACQAJAIAJCIIinQf////8HcSIEQavGmIQESQ0AIAJC////////////AINCgICAgICAgPj/AFgNASABQRBqJAAgAA8LIARBw9zY/gNJDQEgBEGyxcL/A08NAyADQQFzIANrIQQMBgsgAETvOfr+Qi6GQGRBAXMNASABQRBqJAAgAEQAAAAAAADgf6IPCyAEQYCAwPEDTQ0CQQAhBEQAAAAAAAAAACEFIAAhBgwFCyAARNK8et0rI4bAY0EBcw0AIAFEAAAAAAAAoLYgAKO2OAIMRAAAAAAAAAAAIQcgAERRMC3VEEmHwGMNBQsgAET+gitlRxX3P6IgA0EDdEHgHmorAwCgIgeZRAAAAAAAAOBBYw0BQYCAgIB4IQQMAgsgASAARAAAAAAAAOB/oDkDACABQRBqJAAgAEQAAAAAAADwP6APCyAHqiEECyAAIAS3IgdEAADg/kIu5r+ioCIAIAdEdjx5Ne856j2iIgWhIQYLIAAgBiAGIAYgBqIiByAHIAcgByAHRNCkvnJpN2Y+okTxa9LFQb27vqCiRCzeJa9qVhE/oKJEk72+FmzBZr+gokQ+VVVVVVXFP6CioSIHokQAAAAAAAAAQCAHoaMgBaGgRAAAAAAAAPA/oCEHIARFDQAgByAEEBMhBwsgAUEQaiQAIAcL2QYEAX8BfgJ/BHwjAEEQayEBIAC9IgJCP4inIQMCQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCACQiCIp0H/////B3EiBEH60I2CBEkNACACQv///////////wCDQoCAgICAgID4/wBYDQEgAA8LIARBw9zY/gNJDQEgBEGxxcL/A0sNAiADRQ0GIABEAADg/kIu5j+gIQVBfyEERHY8eTXvOeq9IQYMCgsgA0UNA0QAAAAAAADwvw8LIARB//+/5ANLDQEgBEH//z9LDQMgASAAtjgCDCAADwsgAET+gitlRxX3P6IhBkQAAAAAAADgvyEFIAMNBgwFC0EAIQQMBwsgAETvOfr+Qi6GQGRFDQIgAEQAAAAAAADgf6IPCyAADwsgAEQAAOD+Qi7mv6AhBUEBIQREdjx5Ne856j0hBgwDCyAARP6CK2VHFfc/oiEGC0QAAAAAAADgPyEFCwJAAkAgBiAFoCIFmUQAAAAAAADgQWMNAEGAgICAeCEEDAELIAWqIQQLIAS3IgVEdjx5Ne856j2iIQYgACAFRAAA4P5CLua/oqAhBQsgBSAFIAahIgChIAahIQYLIAAgAEQAAAAAAADgP6IiB6IiBSAFIAUgBSAFIAVELcMJbrf9ir6iRDlS5obKz9A+oKJEt9uqnhnOFL+gokSFVf4ZoAFaP6CiRPQQEREREaG/oKJEAAAAAAAA8D+gIghEAAAAAAAACEAgByAIoqEiB6FEAAAAAAAAGEAgACAHoqGjoiEHAkACQAJAAkACQCAERQ0AIAAgByAGoaIgBqEgBaEhBSAEQQFGDQEgBEF/Rw0CIAAgBaFEAAAAAAAA4D+iRAAAAAAAAOC/oA8LIAAgACAHoiAFoaEPCyAARAAAAAAAANC/Y0EBcw0BIAUgAEQAAAAAAADgP6ChRAAAAAAAAADAog8LIARB/wdqrUI0hr8hBiAEQTlJDQEgACAFoUQAAAAAAADwP6AiACAAoEQAAAAAAADgf6IgACAGoiAEQYAIRhtEAAAAAAAA8L+gDwsgACAFoSIAIACgRAAAAAAAAPA/oA8LRAAAAAAAAPA/Qf8HIARrrUI0hr8iB6EgACAFIAegoSAEQRRIIgQbIAAgBaFEAAAAAAAA8D8gBBugIAaiC6IDAwF+A38CfAJAAkACQAJAAkAgAL0iAUIAUw0AIAFCIIinIgJB//8/TQ0AIAJB//+//wdLDQNBgIDA/wMhA0GBeCEEIAJBgIDA/wNHDQEgAacNAkQAAAAAAAAAAA8LAkAgAUL///////////8Ag0IAUQ0AIAFCf1cNBCAARAAAAAAAAFBDor0iAUIgiKchA0HLdyEEDAILRAAAAAAAAPC/IAAgAKKjDwsgAiEDCyAEIANB4r4laiICQRR2arciBUQAAOD+Qi7mP6IgAkH//z9xQZ7Bmv8Daq1CIIYgAUL/////D4OEv0QAAAAAAADwv6AiACAFRHY8eTXvOeo9oiAAIABEAAAAAAAAAECgoyIFIAAgAEQAAAAAAADgP6KiIgYgBSAFoiIFIAWiIgAgACAARJ/GeNAJmsM/okSveI4dxXHMP6CiRAT6l5mZmdk/oKIgBSAAIAAgAEREUj7fEvHCP6JE3gPLlmRGxz+gokRZkyKUJEnSP6CiRJNVVVVVVeU/oKKgoKKgIAahoKAhAAsgAA8LIAAgAKFEAAAAAAAAAACjC4kEBAF/AX4BfwN8IwBBEGshASAAvSICQiCIpyEDAkACQAJAAkACQCACQgBTDQAgA0H5hOr+A00NACADQf//v/8HTQ0BIAAPCwJAIANBgIDA/3tJDQAgAEQAAAAAAADwv2INA0QAAAAAAADw/w8LAkAgA0EBdEH////JB0sNACADQYCAwP8HcUUNBCAADwtEAAAAAAAAAAAhBCADQcX9yv57Tw0ARAAAAAAAAAAAIQUMAQtEAAAAAAAAAAAhBAJAIABEAAAAAAAA8D+gIgW9IgJCIIinQeK+JWoiAUEUdkGBeGoiA0E1Sg0AIAAgBaFEAAAAAAAA8D+gIAAgBUQAAAAAAADwv6ChIANBAUobIAWjIQQLIAFB//8/cUGewZr/A2qtQiCGIAJC/////w+DhL9EAAAAAAAA8L+gIQAgA7chBQsgBUQAAOD+Qi7mP6IgACAEIAVEdjx5Ne856j2ioCAAIABEAAAAAAAAAECgoyIFIAAgAEQAAAAAAADgP6KiIgYgBSAFoiIEIASiIgUgBSAFRJ/GeNAJmsM/okSveI4dxXHMP6CiRAT6l5mZmdk/oKIgBCAFIAUgBUREUj7fEvHCP6JE3gPLlmRGxz+gokRZkyKUJEnSP6CiRJNVVVVVVeU/oKKgoKKgIAahoKAPCyAAIAChRAAAAAAAAAAAow8LIAEgALY4AgwgAAvHEAYBfAF+A38BfgV/CHxEAAAAAAAA8D8hAgJAIAG9IgNCIIinIgRB/////wdxIgUgA6ciBnJFDQAgAL0iB0IgiKchCAJAIAenIgkNACAIQYCAwP8DRg0BCwJAAkAgCEH/////B3EiCkGAgMD/B0sNACAJQQBHIApBgIDA/wdGcQ0AIAVBgIDA/wdLDQAgBkUNASAFQYCAwP8HRw0BCyAAIAGgDwtBACELAkACQAJAAkAgCEF/Sg0AQQIhCyAFQf///5kESw0AQQAhCyAFQYCAwP8DSQ0AIAVBFHYhDCAFQYCAgIoESQ0BQQIgBkGzCCAMayILdiIMQQFxa0EAIAwgC3QgBkYbIQsLIAZFDQEMAgtBACELIAYNAUECIAVBkwggDGsiBnYiC0EBcWtBACALIAZ0IAVGGyELCwJAAkACQAJAIAVBgIDA/wdHDQAgCkGAgMCAfGogCXJFDQUgCkGAgMD/A0kNASABRAAAAAAAAAAAIARBf0obDwsCQCAFQYCAwP8DRw0AIARBf0wNAyAADwsgBEGAgICABEcNASAAIACiDwtEAAAAAAAAAAAgAZogBEF/ShsPCyAIQQBIDQEgBEGAgID/A0cNASAAnw8LRAAAAAAAAPA/IACjDwsgAJkhAgJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAkNACAKRQ0BIApBgICAgARyQYCAwP8HRg0BC0QAAAAAAADwPyENIAhBf0oNAyALQQFGDQEgCw0DIAAgAKEiASABow8LRAAAAAAAAPA/IAKjIAIgBEEASBshAiAIQX9KDQsgCyAKQYCAwIB8anJFDQEgApogAiALQQFGGw8LRAAAAAAAAPC/IQ0gBUGBgICPBE8NAgwDCyACIAKhIgEgAaMPCyAFQYGAgI8ESQ0BCwJAIAVBgYDAnwRJDQAgCkH//7//A0sNAkQAAAAAAADwf0QAAAAAAAAAACAEQQBIGw8LIApB/v+//wNLDQIgDUScdQCIPOQ3fqJEnHUAiDzkN36iIA1EWfP4wh9upQGiRFnz+MIfbqUBoiAEQQBIGw8LQQAhBQJAAkAgCkH//z9LDQAgAkQAAAAAAABAQ6IiAr1CIIinIQpBSyEEDAELQQAhBAsgCkH//z9xIgZBgIDA/wNyIQggCkEUdSAEakGBeGohBCAGQY+xDkkNAyAGQfrsLk8NAkEBIQUMAwtEAAAAAAAA8H9EAAAAAAAAAAAgBEEAShsPCyAKQYGAwP8DSQ0CIA1EnHUAiDzkN36iRJx1AIg85Dd+oiANRFnz+MIfbqUBokRZ8/jCH26lAaIgBEEAShsPCyAIQYCAQGohCCAEQQFqIQQLIAVBA3QiBkGQH2orAwAiDiAIrUIghiACvUL/////D4OEvyIPIAZB8B5qKwMAIhChIhFEAAAAAAAA8D8gECAPoKMiEqIiAr1CgICAgHCDvyIAIAAgAKIiE0QAAAAAAAAIQKAgAiAAoCASIBEgACAIQQF1QYCAgIACciAFQRJ0akGAgCBqrUIghr8iFKKhIAAgDyAUIBChoaKhoiIPoiACIAKiIgAgAKIgACAAIAAgACAARO9ORUoofso/okRl28mTSobNP6CiRAFBHalgdNE/oKJETSaPUVVV1T+gokT/q2/btm3bP6CiRAMzMzMzM+M/oKKgIhCgvUKAgICAcIO/IgCiIhEgDyAAoiACIBAgAEQAAAAAAAAIwKAgE6GhoqAiAqC9QoCAgIBwg78iAEQAAADgCcfuP6IiDyAGQYAfaisDACACIAAgEaGhRP0DOtwJx+4/oiAARPUBWxTgLz6+oqCgIhCgoCAEtyICoL1CgICAgHCDvyIAIAKhIA6hIA+hIQ4MAQsgAkQAAAAAAADwv6AiAEQAAABgRxX3P6IiAiAARETfXfgLrlQ+oiAAIACiRAAAAAAAAOA/IAAgAEQAAAAAAADQv6JEVVVVVVVV1T+goqGiRP6CK2VHFfe/oqAiEKC9QoCAgIBwg78iACACoSEOCyAAIANCgICAgHCDvyIPoiICIBAgDqEgAaIgASAPoSAAoqAiAaAiAL0iA6chBQJAAkACQAJAAkAgA0IgiKciCEGAgMCEBEgNACAIQYCAwPt7aiAFckUNASANRJx1AIg85Dd+okScdQCIPOQ3fqIPCyAIQYD4//8HcUGAmMOEBEkNAiAIQYDovPsDaiAFckUNASANRFnz+MIfbqUBokRZ8/jCH26lAaIPCyABRP6CK2VHFZc8oCAAIAKhZEEBcw0BIA1EnHUAiDzkN36iRJx1AIg85Dd+og8LIAEgACACoWVBAXNFDQELQQAhBQJAIAhB/////wdxIgZBgYCA/wNJDQBBAEGAgMAAIAZBFHZBgnhqdiAIaiIGQf//P3FBgIDAAHJBkwggBkEUdkH/D3EiBGt2IgVrIAUgCEEASBshBSABIAJBgIBAIARBgXhqdSAGca1CIIa/oSICoL0hAwsCQCAFQRR0IANCgICAgHCDvyIARAAAAABDLuY/oiIPIAEgACACoaFE7zn6/kIu5j+iIABEOWyoDGFcIL6ioCICoCIBIAEgASABIAGiIgAgACAAIAAgAETQpL5yaTdmPqJE8WvSxUG9u76gokQs3iWvalYRP6CiRJO9vhZswWa/oKJEPlVVVVVVxT+goqEiAKIgAEQAAAAAAAAAwKCjIAIgASAPoaEiACABIACioKGhRAAAAAAAAPA/oCIBvSIDQiCIp2oiCEH//z9KDQAgDSABIAUQE6IPCyANIAitQiCGIANC/////w+DhL+iDwsgDURZ8/jCH26lAaJEWfP4wh9upQGiDwsgAgu4AQEBfwJAAkACQAJAIAFBgAhIDQAgAEQAAAAAAADgf6IhACABQYF4aiICQYAISA0BIAFBgnBqIgFB/wcgAUH/B0gbIQEgAEQAAAAAAADgf6IhAAwDCyABQYF4Sg0CIABEAAAAAAAAYAOiIQAgAUHJB2oiAkGBeEoNASABQZIPaiIBQYJ4IAFBgnhKGyEBIABEAAAAAAAAYAOiIQAMAgsgAiEBDAELIAIhAQsgACABQf8Haq1CNIa/oguiAgICfwF8IwBBEGsiASQAAkACQAJAIAC9QiCIp0H/////B3EiAkH7w6T/A0sNACACQf//v/IDSw0BIAEgAEQAAAAAAABwOKIgAEQAAAAAAABwR6AgAkGAgMAASRs5AwAgAUEQaiQAIAAPCyACQYCAwP8HSQ0BIAFBEGokACAAIAChDwsgAEQAAAAAAAAAAEEAEAohACABQRBqJAAgAA8LIAAgARAJIQIgASsDCCEAIAErAwAhAwJAAkACQCACQQNxIgJBAkYNACACQQFGDQEgAg0CIAMgAEEBEAohACABQRBqJAAgAA8LIAMgAEEBEAohACABQRBqJAAgAJoPCyADIAAQByEAIAFBEGokACAADwsgAyAAEAchACABQRBqJAAgAJoLrgEDAX4CfAF/RAAAAAAAAOC/RAAAAAAAAOA/IAC9IgFCAFMbIQIgAUL///////////8AgyIBvyEDAkACQAJAIAFCIIinIgRBwdyYhARLDQAgAxAPIQMgBEH//7//A0sNAiAEQYCAwPIDSQ0BIAIgAyADoCADIAOiIANEAAAAAAAA8D+go6GiDwsgAiACoCADEAyiIQALIAAPCyACIAMgAyADRAAAAAAAAPA/oKOgoguwAwMBfgJ/A3wCQAJAIAC9IgNCgICAgID/////AINCgYCAgPCE5fI/VCIEDQBEGC1EVPsh6T8gAJogACADQj+IpyIFG6FEB1wUMyamgTwgAZogASAFG6GgIQBEAAAAAAAAAAAhAQwBCwsgACAAIAAgAKIiBqIiB0RjVVVVVVXVP6IgASAGIAEgByAGIAaiIgggCCAIIAggCERzU2Dby3XzvqJEppI3oIh+FD+gokQBZfLy2ERDP6CiRCgDVskibW0/oKJEN9YGhPRklj+gokR6/hARERHBP6AgBiAIIAggCCAIIAhE1Hq/dHAq+z6iROmn8DIPuBI/oKJEaBCNGvcmMD+gokQVg+D+yNtXP6CiRJOEbunjJoI/oKJE/kGzG7qhqz+goqCioKKgoCIGoCEIAkAgBA0AQQEgAkEBdGu3IgEgACAGIAggCKIgCCABoKOhoCIIIAigoSIImiAIIAUbDwsCQCACRQ0ARAAAAAAAAPC/IAijIgEgCL1CgICAgHCDvyIHIAG9QoCAgIBwg78iCKJEAAAAAAAA8D+gIAYgByAAoaEgCKKgoiAIoCEICyAIC8EBAQJ/IwBBEGsiASQAAkACQAJAIAC9QiCIp0H/////B3EiAkH7w6T/A0sNACACQf////EDSw0BIAEgAEQAAAAAAABwOKIgAEQAAAAAAABwR6AgAkGAgMAASRs5AwAgAUEQaiQAIAAPCyACQYCAwP8HSQ0BIAFBEGokACAAIAChDwsgAEQAAAAAAAAAAEEAEBYhACABQRBqJAAgAA8LIAAgARAJIQIgASsDACABKwMIIAJBAXEQFiEAIAFBEGokACAAC4ACAwF/An4BfyMAQRBrIgEkACAAvSICQv///////////wCDIgO/IQACQAJAAkACQCADQiCIpyIEQeunhv8DSQ0AIARBgYDQgQRJDQFEAAAAAAAAAIAgAKNEAAAAAAAA8D+gIQAMAwsgBEGvscH+A0kNASAAIACgEA8iACAARAAAAAAAAABAoKMhAAwCC0QAAAAAAADwP0QAAAAAAAAAQCAAIACgEA9EAAAAAAAAAECgo6EhAAwBCwJAIARBgIDAAEkNACAARAAAAAAAAADAohAPIgCaIABEAAAAAAAAAECgoyEADAELIAEgALY4AgwLIAFBEGokACAAmiAAIAJCAFMbC/wCAgN/AX4CQCACRQ0AIAAgAToAACAAIAJqIgNBf2ogAToAACACQQNJDQAgACABOgACIAAgAToAASADQX1qIAE6AAAgA0F+aiABOgAAIAJBB0kNACAAIAE6AAMgA0F8aiABOgAAIAJBCUkNACAAQQAgAGtBA3EiBGoiAyABQf8BcUGBgoQIbCIBNgIAIAMgAiAEa0F8cSIEaiICQXxqIAE2AgAgBEEJSQ0AIAMgATYCCCADIAE2AgQgAkF4aiABNgIAIAJBdGogATYCACAEQRlJDQAgAyABNgIQIAMgATYCDCADIAE2AhQgAyABNgIYIAJBaGogATYCACACQWRqIAE2AgAgAkFsaiABNgIAIAJBcGogATYCACAEIANBBHFBGHIiBWsiAkEgSQ0AIAGtIgZCIIYgBoQhBiADIAVqIQEDQCABIAY3AwAgAUEIaiAGNwMAIAFBEGogBjcDACABQRhqIAY3AwAgAUEgaiEBIAJBYGoiAkEfSw0ACwsgAAsLqBcBAEGACAugF0+7YQVnrN0/GC1EVPsh6T+b9oHSC3PvPxgtRFT7Ifk/4mUvIn8rejwHXBQzJqaBPL3L8HqIB3A8B1wUMyamkTwDAAAABAAAAAQAAAAGAAAAg/miAERObgD8KRUA0VcnAN009QBi28AAPJmVAEGQQwBjUf4Au96rALdhxQA6biQA0k1CAEkG4AAJ6i4AHJLRAOsd/gApsRwA6D6nAPU1ggBEuy4AnOmEALQmcABBfl8A1pE5AFODOQCc9DkAi1+EACj5vQD4HzsA3v+XAA+YBQARL+8AClqLAG0fbQDPfjYACcsnAEZPtwCeZj8ALepfALondQDl68cAPXvxAPc5BwCSUooA+2vqAB+xXwAIXY0AMANWAHv8RgDwq2sAILzPADb0mgDjqR0AXmGRAAgb5gCFmWUAoBRfAI1AaACA2P8AJ3NNAAYGMQDKVhUAyahzAHviYABrjMAAGcRHAM1nwwAJ6NwAWYMqAIt2xACmHJYARK/dABlX0QClPgUABQf/ADN+PwDCMugAmE/eALt9MgAmPcMAHmvvAJ/4XgA1HzoAf/LKAPGHHQB8kCEAaiR8ANVu+gAwLXcAFTtDALUUxgDDGZ0ArcTCACxNQQAMAF0Ahn1GAONxLQCbxpoAM2IAALTSfAC0p5cAN1XVANc+9gCjEBgATXb8AGSdKgBw16sAY3z4AHqwVwAXFecAwElWADvW2QCnhDgAJCPLANaKdwBaVCMAAB+5APEKGwAZzt8AnzH/AGYeagCZV2EArPtHAH5/2AAiZbcAMuiJAOa/YADvxM0AbDYJAF0/1AAW3tcAWDveAN6bkgDSIigAKIboAOJYTQDGyjIACOMWAOB9ywAXwFAA8x2nABjgWwAuEzQAgxJiAINIAQD1jlsArbB/AB7p8gBISkMAEGfTAKrd2ACuX0IAamHOAAoopADTmbQABqbyAFx3fwCjwoMAYTyIAIpzeACvjFoAb9e9AC2mYwD0v8sAjYHvACbBZwBVykUAytk2ACio0gDCYY0AEsl3AAQmFAASRpsAxFnEAMjFRABNspEAABfzANRDrQApSeUA/dUQAAC+/AAelMwAcM7uABM+9QDs8YAAs+fDAMf4KACTBZQAwXE+AC4JswALRfMAiBKcAKsgewAutZ8AR5LCAHsyLwAMVW0AcqeQAGvnHwAxy5YAeRZKAEF54gD034kA6JSXAOLmhACZMZcAiO1rAF9fNgC7/Q4ASJq0AGekbABxckIAjV0yAJ8VuAC85QkAjTElAPd0OQAwBRwADQwBAEsIaAAs7lgAR6qQAHTnAgC91iQA932mAG5IcgCfFu8AjpSmALSR9gDRU1EAzwryACCYMwD1S34AsmNoAN0+XwBAXQMAhYl/AFVSKQA3ZMAAbdgQADJIMgBbTHUATnHUAEVUbgALCcEAKvVpABRm1QAnB50AXQRQALQ72wDqdsUAh/kXAElrfQAdJ7oAlmkpAMbMrACtFFQAkOJqAIjZiQAsclAABKS+AHcHlADzMHAAAPwnAOpxqABmwkkAZOA9AJfdgwCjP5cAQ5T9AA2GjAAxQd4AkjmdAN1wjAAXt+cACN87ABU3KwBcgKAAWoCTABARkgAP6NgAbICvANv/SwA4kA8AWRh2AGKlFQBhy7sAx4m5ABBAvQDS8gQASXUnAOu29gDbIrsAChSqAIkmLwBkg3YACTszAA6UGgBROqoAHaPCAK/trgBcJhIAbcJNAC16nADAVpcAAz+DAAnw9gArQIwAbTGZADm0BwAMIBUA2MNbAPWSxADGrUsATsqlAKc3zQDmqTYAq5KUAN1CaAAZY94AdozvAGiLUgD82zcArqGrAN8VMQAArqEADPvaAGRNZgDtBbcAKWUwAFdWvwBH/zoAavm5AHW+8wAok98Aq4AwAGaM9gAEyxUA+iIGANnkHQA9s6QAVxuPADbNCQBOQukAE76kADMjtQDwqhoAT2WoANLBpQALPw8AW3jNACP5dgB7iwQAiRdyAMamUwBvbuIA7+sAAJtKWADE2rcAqma6AHbPzwDRAh0AsfEtAIyZwQDDrXcAhkjaAPddoADGgPQArPAvAN3smgA/XLwA0N5tAJDHHwAq27YAoyU6AACvmgCtU5MAtlcEACkttABLgH4A2genAHaqDgB7WaEAFhIqANy3LQD65f0Aidv+AIm+/QDkdmwABqn8AD6AcACFbhUA/Yf/ACg+BwBhZzMAKhiGAE296gCz568Aj21uAJVnOQAxv1sAhNdIADDfFgDHLUMAJWE1AMlwzgAwy7gAv2z9AKQAogAFbOQAWt2gACFvRwBiEtIAuVyEAHBhSQBrVuAAmVIBAFBVNwAe1bcAM/HEABNuXwBdMOQAhS6pAB2ywwChMjYACLekAOqx1AAW9yEAj2nkACf/dwAMA4AAjUAtAE/NoAAgpZkAs6LTAC9dCgC0+UIAEdrLAH2+0ACb28EAqxe9AMqigQAIalwALlUXACcAVQB/FPAA4QeGABQLZACWQY0Ah77eANr9KgBrJbYAe4k0AAXz/gC5v54AaGpPAEoqqABPxFoALfi8ANdamAD0x5UADU2NACA6pgCkV18AFD+xAIA4lQDMIAEAcd2GAMnetgC/YPUATWURAAEHawCMsKwAssDQAFFVSAAe+w4AlXLDAKMGOwDAQDUABtx7AOBFzABOKfoA1srIAOjzQQB8ZN4Am2TYANm+MQCkl8MAd1jUAGnjxQDw2hMAujo8AEYYRgBVdV8A0r31AG6SxgCsLl0ADkTtABw+QgBhxIcAKf3pAOfW8wAifMoAb5E1AAjgxQD/140AbmriALD9xgCTCMEAfF10AGutsgDNbp0APnJ7AMYRagD3z6kAKXPfALXJugC3AFEA4rINAHS6JADlfWAAdNiKAA0VLACBGAwAfmaUAAEpFgCfenYA/f2+AFZF7wDZfjYA7NkTAIu6uQDEl/wAMagnAPFuwwCUxTYA2KhWALSotQDPzA4AEoktAG9XNAAsVokAmc7jANYguQBrXqoAPiqcABFfzAD9C0oA4fT7AI47bQDihiwA6dSEAPy0qQDv7tEALjXJAC85YQA4IUQAG9nIAIH8CgD7SmoALxzYAFO0hABOmYwAVCLMACpV3ADAxtYACxmWABpwuABplWQAJlpgAD9S7gB/EQ8A9LURAPzL9QA0vC0ANLzuAOhdzADdXmAAZ46bAJIz7wDJF7gAYVibAOFXvABRg8YA2D4QAN1xSAAtHN0ArxihACEsRgBZ89cA2XqYAJ5UwABPhvoAVgb8AOV5rgCJIjYAOK0iAGeT3ABV6KoAgiY4AMrnmwBRDaQAmTOxAKnXDgBpBUgAZbLwAH+IpwCITJcA+dE2ACGSswB7gkoAmM8hAECf3ADcR1UA4XQ6AGfrQgD+nd8AXtRfAHtnpAC6rHoAVfaiACuIIwBBulUAWW4IACEqhgA5R4MAiePmAOWe1ABJ+0AA/1bpABwPygDFWYoAlPorANPBxQAPxc8A21quAEfFhgCFQ2IAIYY7ACx5lAAQYYcAKkx7AIAsGgBDvxIAiCaQAHg8iQCoxOQA5dt7AMQ6wgAm9OoA92eKAA2SvwBloysAPZOxAL18CwCkUdwAJ91jAGnh3QCalBkAqCmVAGjOKAAJ7bQARJ8gAE6YygBwgmMAfnwjAA+5MgCn9Y4AFFbnACHxCAC1nSoAb35NAKUZUQC1+asAgt/WAJbdYQAWNgIAxDqfAIOioQBy7W0AOY16AIK4qQBrMlwARidbAAA07QDSAHcA/PRVAAFZTQDgcYAAAAAAAAAAAAAAAABA+yH5PwAAAAAtRHQ+AAAAgJhG+DwAAABgUcx4OwAAAICDG/A5AAAAQCAlejgAAACAIoLjNgAAAAAd82k1AAAAAAAA4D8AAAAAAADgvwAAAAAAAPA/AAAAAAAA+D8AAAAAAAAAAAbQz0Pr/Uw+AAAAAAAAAAAAAABAA7jiPwDsBwRuYW1lAcUBGgARX193YXNtX2NhbGxfY3RvcnMBBGFjb3MCBWFjb3NoAwRhc2luBAVhc2luaAUEYXRhbgYFYXRhbmgHBV9fY29zCBBfX3JlbV9waW8yX2xhcmdlCQpfX3JlbV9waW8yCgVfX3NpbgsDY29zDAdfX2V4cG8yDQRjb3NoDgNleHAPBWV4cG0xEANsb2cRBWxvZzFwEgNwb3cTBnNjYWxibhQDc2luFQRzaW5oFgVfX3RhbhcDdGFuGAR0YW5oGQZtZW1zZXQCnAYaAAABBQACcDABAmwwAgJsMQMCbDIEAmwzAgIAAnAwAQJsMAMGAAJwMAECbDACAmwxAwJsMgQCbDMFAmw0BAUAAnAwAQJsMAICbDEDAmwyBAJsMwUIAAJwMAECbDACAmwxAwJsMgQCbDMFAmw0BgJsNQcCbDYGBQACcDABAmwwAgJsMQMCbDIEAmwzBwUAAnAwAQJwMQICbDADAmwxBAJsMggdAAJwMAECcDECAnAyAwJwMwQCcDQFAmwwBgJsMQcCbDIIAmwzCQJsNAoCbDULAmw2DAJsNw0CbDgOAmw5DwNsMTAQA2wxMREDbDEyEgNsMTMTA2wxNBQDbDE1FQNsMTYWA2wxNxcDbDE4GANsMTkZA2wyMBoDbDIxGwNsMjIcA2wyMwkMAAJwMAECcDECAmwwAwJsMQQCbDIFAmwzBgJsNAcCbDUIAmw2CQJsNwoCbDgLAmw5CgYAAnAwAQJwMQICcDIDAmwwBAJsMQUCbDILBAACcDABAmwwAgJsMQMCbDIMAQACcDANBAACcDABAmwwAgJsMQMCbDIOCAACcDABAmwwAgJsMQMCbDIEAmwzBQJsNAYCbDUHAmw2DwkAAnAwAQJsMAICbDEDAmwyBAJsMwUCbDQGAmw1BwJsNggCbDcQBwACcDABAmwwAgJsMQMCbDIEAmwzBQJsNAYCbDURBwACcDABAmwwAgJsMQMCbDIEAmwzBQJsNAYCbDUSFQACcDABAnAxAgJsMAMCbDEEAmwyBQJsMwYCbDQHAmw1CAJsNgkCbDcKAmw4CwJsOQwDbDEwDQNsMTEOA2wxMg8DbDEzEANsMTQRA2wxNRIDbDE2EwNsMTcUA2wxOBMDAAJwMAECcDECAmwwFAQAAnAwAQJsMAICbDEDAmwyFQUAAnAwAQJsMAICbDEDAmwyBAJsMxYJAAJwMAECcDECAnAyAwJsMAQCbDEFAmwyBgJsMwcCbDQIAmw1FwMAAnAwAQJsMAICbDEYBQACcDABAmwwAgJsMQMCbDIEAmwzGQcAAnAwAQJwMQICcDIDAmwwBAJsMQUCbDIGAmwz" diff --git a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt b/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt deleted file mode 100644 index 5b28b8782..000000000 --- a/kmath-ast/src/jsMain/kotlin/space/kscience/kmath/wasm/wasm.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.wasm - -import space.kscience.kmath.estree.compileWith -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.IntRing -import space.kscience.kmath.wasm.internal.DoubleWasmBuilder -import space.kscience.kmath.wasm.internal.IntWasmBuilder - -/** - * Compiles an [MST] to WASM in the context of reals. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun DoubleField.expression(mst: MST): Expression = - DoubleWasmBuilder(mst).instance - -/** - * Compiles an [MST] to WASM in the context of integers. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun IntRing.expression(mst: MST): Expression = - IntWasmBuilder(mst).instance - -/** - * Create a compiled expression with given [MST] and given [algebra]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compileToExpression(algebra: IntRing): Expression = compileWith(algebra) - - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: IntRing, arguments: Map): Int = - compileToExpression(algebra).invoke(arguments) - - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: IntRing, vararg arguments: Pair): Int = - compileToExpression(algebra)(*arguments) - -/** - * Create a compiled expression with given [MST] and given [algebra]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compileToExpression(algebra: DoubleField): Expression = compileWith(algebra) - - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: DoubleField, arguments: Map): Double = - compileToExpression(algebra).invoke(arguments) - - -/** - * Compile given MST to expression and evaluate it against [arguments]. - * - * @author Iaroslav Postovalov - */ -@UnstableKMathAPI -public fun MST.compile(algebra: DoubleField, vararg arguments: Pair): Double = - compileToExpression(algebra).invoke(*arguments) diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt deleted file mode 100644 index f8c429d5a..000000000 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/TestExecutionTime.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.bindSymbol -import space.kscience.kmath.operations.invoke -import kotlin.math.sin -import kotlin.random.Random -import kotlin.test.Ignore -import kotlin.test.Test -import kotlin.time.measureTime -import space.kscience.kmath.estree.compileToExpression as estreeCompileToExpression -import space.kscience.kmath.wasm.compileToExpression as wasmCompileToExpression - -// TODO move to benchmarks when https://github.com/Kotlin/kotlinx-benchmark/pull/38 or similar feature is merged -@Ignore -internal class TestExecutionTime { - private companion object { - private const val times = 1_000_000 - private val x by symbol - private val algebra = DoubleField - - private val functional = algebra.expressionInExtendedField { - bindSymbol(x) * const(2.0) + const(2.0) / bindSymbol(x) - const(16.0) / sin(bindSymbol(x)) - } - - private val node = MstExtendedField { - x * number(2.0) + number(2.0) / x - number(16.0) / sin(x) - } - - private val mst = node.toExpression(algebra) - private val wasm = node.wasmCompileToExpression(algebra) - private val estree = node.estreeCompileToExpression(algebra) - - // In JavaScript, the expression below is implemented like - // _no_name_provided__125.prototype.invoke_178 = function (args) { - // var tmp = getValue(args, raw$_get_x__3(this._$x$delegate_2)) * 2.0 + 2.0 / getValue(args, raw$_get_x__3(this._$x$delegate_2)); - // var tmp0_sin_0_5 = getValue(args, raw$_get_x__3(this._$x$delegate_2)); - // return tmp - 16.0 / Math.sin(tmp0_sin_0_5); - // }; - - private val raw = Expression { args -> - val x = args[x]!! - algebra { x * 2.0 + 2.0 / x - 16.0 / sin(x) } - } - - private val justCalculate = { args: dynamic -> - val x = args[x].unsafeCast() - x * 2.0 + 2.0 / x - 16.0 / sin(x) - } - } - - private fun invokeAndSum(name: String, expr: Expression) { - println(name) - val rng = Random(0) - var sum = 0.0 - measureTime { - repeat(times) { sum += expr(x to rng.nextDouble()) } - }.also(::println) - } - - /** - * [Expression] created with [expressionInExtendedField]. - */ - @Test - fun functionalExpression() = invokeAndSum("functional", functional) - - /** - * [Expression] created with [mstExpression]. - */ - @Test - fun mstExpression() = invokeAndSum("mst", mst) - - /** - * [Expression] created with [wasmCompileToExpression]. - */ - @Test - fun wasmExpression() = invokeAndSum("wasm", wasm) - - /** - * [Expression] created with [estreeCompileToExpression]. - */ - @Test - fun estreeExpression() = invokeAndSum("estree", wasm) - - /** - * [Expression] implemented manually with `kotlin.math`. - */ - @Test - fun rawExpression() = invokeAndSum("raw", raw) - - /** - * Direct computation w/o [Expression]. - */ - @Test - fun justCalculateExpression() { - println("justCalculate") - val rng = Random(0) - var sum = 0.0 - measureTime { - repeat(times) { - val arg = rng.nextDouble() - val o = js("{}") - o["x"] = arg - sum += justCalculate(o) - } - }.also(::println) - } -} diff --git a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt b/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt deleted file mode 100644 index 3c2a9bd13..000000000 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/ast/utils.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.Expression -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 -import space.kscience.kmath.wasm.compileToExpression as wasmCompileToExpression - -private object WasmCompilerTestContext : CompilerTestContext { - override fun MST.compileToExpression(algebra: IntRing): Expression = wasmCompileToExpression(algebra) - override fun MST.compile(algebra: IntRing, arguments: Map): Int = wasmCompile(algebra, arguments) - override fun MST.compileToExpression(algebra: DoubleField): Expression = wasmCompileToExpression(algebra) - - override fun MST.compile(algebra: DoubleField, arguments: Map): Double = - wasmCompile(algebra, arguments) -} - -private object ESTreeCompilerTestContext : CompilerTestContext { - override fun MST.compileToExpression(algebra: IntRing): Expression = estreeCompileToExpression(algebra) - override fun MST.compile(algebra: IntRing, arguments: Map): Int = estreeCompile(algebra, arguments) - override fun MST.compileToExpression(algebra: DoubleField): Expression = estreeCompileToExpression(algebra) - - override fun MST.compile(algebra: DoubleField, arguments: Map): Double = - estreeCompile(algebra, arguments) -} - -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 deleted file mode 100644 index 6c91df866..000000000 --- a/kmath-ast/src/jsTest/kotlin/space/kscience/kmath/wasm/TestWasmSpecific.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.wasm - -import space.kscience.kmath.expressions.MstExtendedField -import space.kscience.kmath.expressions.MstRing -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.invoke -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class TestWasmSpecific { - @Test - fun int() { - val res = MstRing { number(100000000) + number(10000000) }.compile(IntRing) - assertEquals(110000000, res) - } - - @Test - fun real() { - val res = MstExtendedField { number(100000000) + number(2).pow(10) }.compile(DoubleField) - assertEquals(100001024.0, res) - } - - @Test - fun argsPassing() { - val res = MstExtendedField { y + x.pow(10) }.compile( - DoubleField, - x to 2.0, - y to 100000000.0, - ) - - assertEquals(100001024.0, res) - } - - @Test - fun powFunction() { - val expr = MstExtendedField { x.pow(1.0 / 6.0) }.compileToExpression(DoubleField) - assertEquals(0.9730585187140817, expr(x to 0.8488554755054833)) - } - - private companion object { - private val x by symbol - private val y by symbol - } -} diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt deleted file mode 100644 index 2426d6ee4..000000000 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.asm - -import space.kscience.kmath.asm.internal.AsmBuilder -import space.kscience.kmath.asm.internal.buildName -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.MST.* -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.NumericAlgebra -import space.kscience.kmath.operations.bindSymbolOrNull - -/** - * Compiles given MST to an Expression using AST compiler. - * - * @param type the target type. - * @param algebra the target algebra. - * @return the compiled expression. - * @author Alexander Nozik - */ -@PublishedApi -internal fun MST.compileWith(type: Class, algebra: Algebra): Expression { - fun AsmBuilder.visit(node: MST): Unit = when (node) { - is Symbol -> { - val symbol = algebra.bindSymbolOrNull(node) - - if (symbol != null) - loadObjectConstant(symbol as Any) - else - loadVariable(node.identity) - } - - is Numeric -> loadNumberConstant(node.value) - - is Unary -> when { - algebra is NumericAlgebra && node.value is Numeric -> loadObjectConstant( - algebra.unaryOperationFunction(node.operation)(algebra.number((node.value as Numeric).value))) - - else -> buildCall(algebra.unaryOperationFunction(node.operation)) { visit(node.value) } - } - - is Binary -> when { - algebra is NumericAlgebra && node.left is Numeric && node.right is Numeric -> loadObjectConstant( - algebra.binaryOperationFunction(node.operation).invoke( - algebra.number((node.left as Numeric).value), - algebra.number((node.right as Numeric).value) - ) - ) - - algebra is NumericAlgebra && node.left is Numeric -> buildCall( - algebra.leftSideNumberOperationFunction(node.operation)) { - visit(node.left) - visit(node.right) - } - - algebra is NumericAlgebra && node.right is Numeric -> buildCall( - algebra.rightSideNumberOperationFunction(node.operation)) { - visit(node.left) - visit(node.right) - } - - else -> buildCall(algebra.binaryOperationFunction(node.operation)) { - visit(node.left) - visit(node.right) - } - } - } - - return AsmBuilder(type, buildName(this)) { visit(this@compileWith) }.instance -} - - -/** - * Create a compiled expression with given [MST] and given [algebra]. - */ -public inline fun MST.compileToExpression(algebra: Algebra): Expression = - compileWith(T::class.java, algebra) - - -/** - * Compile given MST to expression and evaluate it against [arguments] - */ -public inline fun MST.compile(algebra: Algebra, arguments: Map): T = - compileToExpression(algebra).invoke(arguments) - -/** - * Compile given MST to expression and evaluate it against [arguments] - */ -public inline fun MST.compile(algebra: Algebra, vararg arguments: Pair): T = - compileToExpression(algebra).invoke(*arguments) diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt deleted file mode 100644 index de7da30df..000000000 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/AsmBuilder.kt +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.asm.internal - -import org.objectweb.asm.* -import org.objectweb.asm.Opcodes.* -import org.objectweb.asm.Type.* -import org.objectweb.asm.commons.InstructionAdapter -import space.kscience.kmath.asm.internal.AsmBuilder.ClassLoader -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.MST -import java.lang.invoke.MethodHandles -import java.lang.invoke.MethodType -import java.util.stream.Collectors.toMap -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -/** - * ASM Builder is a structure that abstracts building a class designated to unwrap [MST] to plain Java expression. - * This class uses [ClassLoader] for loading the generated class, then it is able to instantiate the new class. - * - * @property T the type of AsmExpression to unwrap. - * @property className the unique class name of new loaded class. - * @property callbackAtInvokeL0 the function to apply to this object when generating invoke method, label 0. - * @author Iaroslav Postovalov - */ -internal class AsmBuilder( - classOfT: Class<*>, - private val className: String, - private val callbackAtInvokeL0: AsmBuilder.() -> Unit, -) { - /** - * Internal classloader of [AsmBuilder] with alias to define class from byte array. - */ - private class ClassLoader(parent: java.lang.ClassLoader) : java.lang.ClassLoader(parent) { - fun defineClass(name: String?, b: ByteArray): Class<*> = defineClass(name, b, 0, b.size) - } - - /** - * The instance of [ClassLoader] used by this builder. - */ - private val classLoader: ClassLoader = ClassLoader(javaClass.classLoader) - - /** - * ASM type for [T]. - */ - private val tType: Type = classOfT.asm - - /** - * ASM type for new class. - */ - private val classType: Type = getObjectType(className.replace(oldChar = '.', newChar = '/')) - - /** - * List of constants to provide to the subclass. - */ - private val constants: MutableList = mutableListOf() - - /** - * Method visitor of `invoke` method of the subclass. - */ - private lateinit var invokeMethodVisitor: InstructionAdapter - - /** - * Subclasses, loads and instantiates [Expression] for given parameters. - * - * The built instance is cached. - */ - @Suppress("UNCHECKED_CAST") - val instance: Expression by lazy { - val hasConstants: Boolean - - val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES) { - visit( - V1_8, - ACC_PUBLIC or ACC_FINAL or ACC_SUPER, - classType.internalName, - "${OBJECT_TYPE.descriptor}L${EXPRESSION_TYPE.internalName}<${tType.descriptor}>;", - OBJECT_TYPE.internalName, - arrayOf(EXPRESSION_TYPE.internalName), - ) - - visitMethod( - ACC_PUBLIC or ACC_FINAL, - "invoke", - getMethodDescriptor(tType, MAP_TYPE), - "(L${MAP_TYPE.internalName}<${SYMBOL_TYPE.descriptor}+${tType.descriptor}>;)${tType.descriptor}", - null, - ).instructionAdapter { - invokeMethodVisitor = this - visitCode() - val l0 = label() - callbackAtInvokeL0() - areturn(tType) - val l1 = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - l0, - l1, - 0, - ) - - visitLocalVariable( - "arguments", - MAP_TYPE.descriptor, - "L${MAP_TYPE.internalName}<${STRING_TYPE.descriptor}+${tType.descriptor}>;", - l0, - l1, - 1, - ) - - visitMaxs(0, 2) - visitEnd() - } - - visitMethod( - ACC_PUBLIC or ACC_FINAL or ACC_BRIDGE or ACC_SYNTHETIC, - "invoke", - getMethodDescriptor(OBJECT_TYPE, MAP_TYPE), - null, - null, - ).instructionAdapter { - visitCode() - val l0 = label() - load(0, OBJECT_TYPE) - load(1, MAP_TYPE) - invokevirtual(classType.internalName, "invoke", getMethodDescriptor(tType, MAP_TYPE), false) - areturn(tType) - val l1 = label() - - visitLocalVariable( - "this", - classType.descriptor, - null, - l0, - l1, - 0, - ) - - visitMaxs(0, 2) - visitEnd() - } - - hasConstants = constants.isNotEmpty() - - if (hasConstants) - visitField( - access = ACC_PRIVATE or ACC_FINAL, - name = "constants", - descriptor = OBJECT_ARRAY_TYPE.descriptor, - signature = null, - value = null, - block = FieldVisitor::visitEnd, - ) - - visitMethod( - ACC_PUBLIC, - "", - getMethodDescriptor(VOID_TYPE, *OBJECT_ARRAY_TYPE.wrapToArrayIf { hasConstants }), - null, - null, - ).instructionAdapter { - val l0 = label() - load(0, classType) - invokespecial(OBJECT_TYPE.internalName, "", getMethodDescriptor(VOID_TYPE), false) - label() - load(0, classType) - - if (hasConstants) { - label() - load(0, classType) - load(1, OBJECT_ARRAY_TYPE) - putfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) - } - - label() - visitInsn(RETURN) - val l4 = label() - visitLocalVariable("this", classType.descriptor, null, l0, l4, 0) - - if (hasConstants) - visitLocalVariable("constants", OBJECT_ARRAY_TYPE.descriptor, null, l0, l4, 1) - - visitMaxs(0, 3) - visitEnd() - } - - visitEnd() - } - - val cls = classLoader.defineClass(className, classWriter.toByteArray()) - // java.io.File("dump.class").writeBytes(classWriter.toByteArray()) - val l = MethodHandles.publicLookup() - - if (hasConstants) - l.findConstructor(cls, MethodType.methodType(Void.TYPE, Array::class.java)) - .invoke(constants.toTypedArray()) as Expression - else - l.findConstructor(cls, MethodType.methodType(Void.TYPE)).invoke() as Expression - } - - /** - * Loads [java.lang.Object] constant from constants. - */ - fun loadObjectConstant(value: Any, type: Type = tType): Unit = invokeMethodVisitor.run { - val idx = if (value in constants) constants.indexOf(value) else constants.also { it += value }.lastIndex - invokeMethodVisitor.load(0, classType) - getfield(classType.internalName, "constants", OBJECT_ARRAY_TYPE.descriptor) - iconst(idx) - visitInsn(AALOAD) - if (type != OBJECT_TYPE) checkcast(type) - } - - /** - * Either loads a numeric constant [value] from the class's constants field or boxes a primitive - * constant from the constant pool. - */ - fun loadNumberConstant(value: Number) { - val boxed = value.javaClass.asm - val primitive = BOXED_TO_PRIMITIVES[boxed] - - if (primitive != null) { - when (primitive) { - BYTE_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - DOUBLE_TYPE -> invokeMethodVisitor.dconst(value.toDouble()) - FLOAT_TYPE -> invokeMethodVisitor.fconst(value.toFloat()) - LONG_TYPE -> invokeMethodVisitor.lconst(value.toLong()) - INT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - SHORT_TYPE -> invokeMethodVisitor.iconst(value.toInt()) - } - - val r = PRIMITIVES_TO_BOXED.getValue(primitive) - - invokeMethodVisitor.invokestatic( - r.internalName, - "valueOf", - getMethodDescriptor(r, primitive), - false, - ) - - return - } - - loadObjectConstant(value, boxed) - } - - /** - * Loads a variable [name] from arguments [Map] parameter of [Expression.invoke]. - */ - fun loadVariable(name: String): Unit = invokeMethodVisitor.run { - load(1, MAP_TYPE) - aconst(name) - - invokestatic( - MAP_INTRINSICS_TYPE.internalName, - "getOrFail", - getMethodDescriptor(OBJECT_TYPE, MAP_TYPE, STRING_TYPE), - false, - ) - - checkcast(tType) - } - - inline fun buildCall(function: Function, parameters: AsmBuilder.() -> Unit) { - contract { callsInPlace(parameters, InvocationKind.EXACTLY_ONCE) } - val `interface` = function.javaClass.interfaces.first { Function::class.java in it.interfaces } - - val arity = `interface`.methods.find { it.name == "invoke" }?.parameterCount - ?: error("Provided function object doesn't contain invoke method") - - val type = getType(`interface`) - loadObjectConstant(function, type) - parameters(this) - - invokeMethodVisitor.invokeinterface( - type.internalName, - "invoke", - getMethodDescriptor(OBJECT_TYPE, *Array(arity) { OBJECT_TYPE }), - ) - - invokeMethodVisitor.checkcast(tType) - } - - companion object { - /** - * Maps JVM primitive numbers boxed ASM types to their primitive ASM types. - */ - private val BOXED_TO_PRIMITIVES: Map by lazy { - hashMapOf( - Byte::class.java.asm to BYTE_TYPE, - Short::class.java.asm to SHORT_TYPE, - Integer::class.java.asm to INT_TYPE, - Long::class.java.asm to LONG_TYPE, - Float::class.java.asm to FLOAT_TYPE, - Double::class.java.asm to DOUBLE_TYPE, - ) - } - - /** - * Maps JVM primitive numbers boxed ASM types to their primitive ASM types. - */ - private val PRIMITIVES_TO_BOXED: Map by lazy { - BOXED_TO_PRIMITIVES.entries.stream().collect( - toMap(Map.Entry::value, Map.Entry::key), - ) - } - - /** - * ASM type for [Expression]. - */ - val EXPRESSION_TYPE: Type by lazy { getObjectType("space/kscience/kmath/expressions/Expression") } - - /** - * ASM type for [java.util.Map]. - */ - val MAP_TYPE: Type by lazy { getObjectType("java/util/Map") } - - /** - * ASM type for [java.lang.Object]. - */ - val OBJECT_TYPE: Type by lazy { getObjectType("java/lang/Object") } - - /** - * ASM type for array of [java.lang.Object]. - */ - val OBJECT_ARRAY_TYPE: Type by lazy { getType("[Ljava/lang/Object;") } - - /** - * ASM type for [java.lang.String]. - */ - val STRING_TYPE: Type by lazy { getObjectType("java/lang/String") } - - /** - * ASM type for MapIntrinsics. - */ - val MAP_INTRINSICS_TYPE: Type by lazy { getObjectType("space/kscience/kmath/asm/internal/MapIntrinsics") } - - /** - * ASM Type for [space.kscience.kmath.expressions.Symbol]. - */ - val SYMBOL_TYPE: Type by lazy { getObjectType("space/kscience/kmath/expressions/Symbol") } - } -} 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 deleted file mode 100644 index 5e2e7d8c6..000000000 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/codegenUtils.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.asm.internal - -import org.objectweb.asm.* -import org.objectweb.asm.commons.InstructionAdapter -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.MST -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -/** - * Returns ASM [Type] for given [Class]. - * - * @author Iaroslav Postovalov - */ -internal inline val Class<*>.asm: Type - get() = Type.getType(this) - -/** - * Returns singleton array with this value if the [predicate] is true, returns empty array otherwise. - * - * @author Iaroslav Postovalov - */ -internal inline fun T.wrapToArrayIf(predicate: (T) -> Boolean): Array { - contract { callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) } - return if (predicate(this)) arrayOf(this) else emptyArray() -} - -/** - * Creates an [InstructionAdapter] from this [MethodVisitor]. - * - * @author Iaroslav Postovalov - */ -private fun MethodVisitor.instructionAdapter(): InstructionAdapter = InstructionAdapter(this) - -/** - * Creates an [InstructionAdapter] from this [MethodVisitor] and applies [block] to it. - * - * @author Iaroslav Postovalov - */ -internal inline fun MethodVisitor.instructionAdapter(block: InstructionAdapter.() -> Unit): InstructionAdapter { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return instructionAdapter().apply(block) -} - -/** - * Constructs a [Label], then applies it to this visitor. - * - * @author Iaroslav Postovalov - */ -internal fun MethodVisitor.label(): Label = Label().also(::visitLabel) - -/** - * Creates a class name for [Expression] subclassed to implement [mst] provided. - * - * These methods help to avoid collisions of class name to prevent loading several classes with the same name. If there - * is a colliding class, change [collision] parameter or leave it `0` to check existing classes recursively. - * - * @author Iaroslav Postovalov - */ -internal tailrec fun buildName(mst: MST, collision: Int = 0): String { - val name = "space.kscience.kmath.asm.generated.CompiledExpression_${mst.hashCode()}_$collision" - - try { - Class.forName(name) - } catch (ignored: ClassNotFoundException) { - return name - } - - return buildName(mst, collision + 1) -} - -@Suppress("FunctionName") -internal inline fun ClassWriter(flags: Int, block: ClassWriter.() -> Unit): ClassWriter { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return ClassWriter(flags).apply(block) -} - -/** - * Invokes [visitField] and applies [block] to the [FieldVisitor]. - * - * @author Iaroslav Postovalov - */ -internal inline fun ClassWriter.visitField( - access: Int, - name: String, - descriptor: String, - signature: String?, - value: Any?, - block: FieldVisitor.() -> Unit, -): FieldVisitor { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return visitField(access, name, descriptor, signature, value).apply(block) -} diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.kt deleted file mode 100644 index 56cfa4cbf..000000000 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/asm/internal/mapIntrinsics.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 file. - */ - -@file:JvmName("MapIntrinsics") - -package space.kscience.kmath.asm.internal - -import space.kscience.kmath.expressions.StringSymbol -import space.kscience.kmath.expressions.Symbol - -/** - * Gets value with given [key] or throws [NoSuchElementException] whenever it is not present. - * - * @author Iaroslav Postovalov - */ -internal fun Map.getOrFail(key: String): V = getValue(StringSymbol(key)) diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt b/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt deleted file mode 100644 index 3e5253084..000000000 --- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/rendering/multiplatformToString.kt +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast.rendering - -internal actual fun Double.multiplatformToString(): String = toString() -internal actual fun Float.multiplatformToString(): String = toString() 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 deleted file mode 100644 index a0bdd68a0..000000000 --- a/kmath-ast/src/jvmTest/kotlin/space/kscience/kmath/ast/utils.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ast - -import space.kscience.kmath.expressions.Expression -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 - -private object AsmCompilerTestContext : CompilerTestContext { - override fun MST.compileToExpression(algebra: IntRing): Expression = asmCompileToExpression(algebra) - override fun MST.compile(algebra: IntRing, arguments: Map): Int = asmCompile(algebra, arguments) - override fun MST.compileToExpression(algebra: DoubleField): Expression = asmCompileToExpression(algebra) - - override fun MST.compile(algebra: DoubleField, arguments: Map): Double = - asmCompile(algebra, arguments) -} - -internal actual inline fun runCompilerTest(action: CompilerTestContext.() -> Unit) { - contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - action(AsmCompilerTestContext) -} diff --git a/kmath-commons/build.gradle.kts b/kmath-commons/build.gradle.kts index a208c956c..5ce1b935a 100644 --- a/kmath-commons/build.gradle.kts +++ b/kmath-commons/build.gradle.kts @@ -1,19 +1,13 @@ plugins { - kotlin("jvm") - id("ru.mipt.npm.gradle.common") + id("scientifik.jvm") } description = "Commons math binding for kmath" dependencies { api(project(":kmath-core")) - api(project(":kmath-complex")) api(project(":kmath-coroutines")) - api(project(":kmath-stat")) + api(project(":kmath-prob")) api(project(":kmath-functions")) api("org.apache.commons:commons-math3:3.6.1") -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL } \ No newline at end of file diff --git a/kmath-commons/src/main/kotlin/scientifik/kmath/commons/expressions/DiffExpression.kt b/kmath-commons/src/main/kotlin/scientifik/kmath/commons/expressions/DiffExpression.kt new file mode 100644 index 000000000..d5c038dc4 --- /dev/null +++ b/kmath-commons/src/main/kotlin/scientifik/kmath/commons/expressions/DiffExpression.kt @@ -0,0 +1,141 @@ +package scientifik.kmath.commons.expressions + +import org.apache.commons.math3.analysis.differentiation.DerivativeStructure +import scientifik.kmath.expressions.Expression +import scientifik.kmath.expressions.ExpressionContext +import scientifik.kmath.operations.ExtendedField +import scientifik.kmath.operations.Field +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty + +/** + * A field wrapping commons-math derivative structures + */ +class DerivativeStructureField( + val order: Int, + val parameters: Map +) : ExtendedField { + + override val zero: DerivativeStructure by lazy { DerivativeStructure(order, parameters.size) } + + override val one: DerivativeStructure by lazy { DerivativeStructure(order, parameters.size, 1.0) } + + private val variables: Map = parameters.mapValues { (key, value) -> + DerivativeStructure(parameters.size, order, parameters.keys.indexOf(key), value) + } + + val variable = object : ReadOnlyProperty { + override fun getValue(thisRef: Any?, property: KProperty<*>): DerivativeStructure { + return variables[property.name] ?: error("A variable with name ${property.name} does not exist") + } + } + + fun variable(name: String, default: DerivativeStructure? = null): DerivativeStructure = + variables[name] ?: default ?: error("A variable with name $name does not exist") + + + fun Number.const() = DerivativeStructure(order, parameters.size, toDouble()) + + fun DerivativeStructure.deriv(parName: String, order: Int = 1): Double { + return deriv(mapOf(parName to order)) + } + + fun DerivativeStructure.deriv(orders: Map): Double { + return getPartialDerivative(*parameters.keys.map { orders[it] ?: 0 }.toIntArray()) + } + + fun DerivativeStructure.deriv(vararg orders: Pair): Double = deriv(mapOf(*orders)) + + override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b) + + override fun multiply(a: DerivativeStructure, k: Number): DerivativeStructure = when (k) { + is Double -> a.multiply(k) + is Int -> a.multiply(k) + else -> a.multiply(k.toDouble()) + } + + 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 power(arg: DerivativeStructure, pow: Number): DerivativeStructure = when (pow) { + is Double -> arg.pow(pow) + is Int -> arg.pow(pow) + else -> arg.pow(pow.toDouble()) + } + + fun power(arg: DerivativeStructure, pow: DerivativeStructure): DerivativeStructure = arg.pow(pow) + + override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.exp() + + override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.log() + + operator fun DerivativeStructure.plus(n: Number): DerivativeStructure = add(n.toDouble()) + operator fun DerivativeStructure.minus(n: Number): DerivativeStructure = subtract(n.toDouble()) + operator fun Number.plus(s: DerivativeStructure) = s + this + operator fun Number.minus(s: DerivativeStructure) = s - this +} + +/** + * A constructs that creates a derivative structure with required order on-demand + */ +class DiffExpression(val function: DerivativeStructureField.() -> DerivativeStructure) : Expression { + + override fun invoke(arguments: Map): Double = DerivativeStructureField( + 0, + arguments + ).run(function).value + + /** + * Get the derivative expression with given orders + * TODO make result [DiffExpression] + */ + fun derivative(orders: Map): Expression { + return object : Expression { + override fun invoke(arguments: Map): Double = + DerivativeStructureField(orders.values.max() ?: 0, arguments) + .run { + function().deriv(orders) + } + } + } + + //TODO add gradient and maybe other vector operators +} + +fun DiffExpression.derivative(vararg orders: Pair) = derivative(mapOf(*orders)) +fun DiffExpression.derivative(name: String) = derivative(name to 1) + +/** + * A context for [DiffExpression] (not to be confused with [DerivativeStructure]) + */ +object DiffExpressionContext : ExpressionContext, Field { + override fun variable(name: String, default: Double?) = + DiffExpression { variable(name, default?.const()) } + + override fun const(value: Double): DiffExpression = + DiffExpression { value.const() } + + override fun add(a: DiffExpression, b: DiffExpression) = + DiffExpression { a.function(this) + b.function(this) } + + override val zero = DiffExpression { 0.0.const() } + + override fun multiply(a: DiffExpression, k: Number) = + DiffExpression { a.function(this) * k } + + override val one = DiffExpression { 1.0.const() } + + override fun multiply(a: DiffExpression, b: DiffExpression) = + DiffExpression { a.function(this) * b.function(this) } + + override fun divide(a: DiffExpression, b: DiffExpression) = + DiffExpression { a.function(this) / b.function(this) } +} + + + diff --git a/kmath-commons/src/main/kotlin/scientifik/kmath/commons/linear/CMMatrix.kt b/kmath-commons/src/main/kotlin/scientifik/kmath/commons/linear/CMMatrix.kt new file mode 100644 index 000000000..a17effccc --- /dev/null +++ b/kmath-commons/src/main/kotlin/scientifik/kmath/commons/linear/CMMatrix.kt @@ -0,0 +1,96 @@ +package scientifik.kmath.commons.linear + +import org.apache.commons.math3.linear.* +import org.apache.commons.math3.linear.RealMatrix +import org.apache.commons.math3.linear.RealVector +import scientifik.kmath.linear.* +import scientifik.kmath.structures.Matrix +import scientifik.kmath.structures.NDStructure + +class CMMatrix(val origin: RealMatrix, features: Set? = null) : + FeaturedMatrix { + override val rowNum: Int get() = origin.rowDimension + override val colNum: Int get() = origin.columnDimension + + override val features: Set = features ?: sequence { + if (origin is DiagonalMatrix) yield(DiagonalFeature) + }.toSet() + + override fun suggestFeature(vararg features: MatrixFeature) = + CMMatrix(origin, this.features + features) + + override fun get(i: Int, j: Int): Double = origin.getEntry(i, j) + + override fun equals(other: Any?): Boolean { + return NDStructure.equals(this, other as? NDStructure<*> ?: return false) + } + + override fun hashCode(): Int { + var result = origin.hashCode() + result = 31 * result + features.hashCode() + return result + } +} + +fun Matrix.toCM(): CMMatrix = if (this is CMMatrix) { + this +} else { + //TODO add feature analysis + val array = Array(rowNum) { i -> DoubleArray(colNum) { j -> get(i, j) } } + CMMatrix(Array2DRowRealMatrix(array)) +} + +fun RealMatrix.asMatrix() = CMMatrix(this) + +class CMVector(val origin: RealVector) : Point { + override val size: Int get() = origin.dimension + + override fun get(index: Int): Double = origin.getEntry(index) + + override fun iterator(): Iterator = origin.toArray().iterator() +} + +fun Point.toCM(): CMVector = if (this is CMVector) { + this +} else { + val array = DoubleArray(size) { this[it] } + CMVector(ArrayRealVector(array)) +} + +fun RealVector.toPoint() = CMVector(this) + +object CMMatrixContext : MatrixContext { + override fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> Double): CMMatrix { + val array = Array(rows) { i -> DoubleArray(columns) { j -> initializer(i, j) } } + return CMMatrix(Array2DRowRealMatrix(array)) + } + + override fun Matrix.dot(other: Matrix) = + CMMatrix(this.toCM().origin.multiply(other.toCM().origin)) + + override fun Matrix.dot(vector: Point): CMVector = + CMVector(this.toCM().origin.preMultiply(vector.toCM().origin)) + + override fun Matrix.unaryMinus(): CMMatrix = + produce(rowNum, colNum) { i, j -> -get(i, j) } + + override fun add(a: Matrix, b: Matrix) = + CMMatrix(a.toCM().origin.multiply(b.toCM().origin)) + + override fun Matrix.minus(b: Matrix) = + CMMatrix(this.toCM().origin.subtract(b.toCM().origin)) + + override fun multiply(a: Matrix, k: Number) = + CMMatrix(a.toCM().origin.scalarMultiply(k.toDouble())) + + override fun Matrix.times(value: Double): Matrix = + produce(rowNum, colNum) { i, j -> get(i, j) * value } +} + +operator fun CMMatrix.plus(other: CMMatrix): CMMatrix = + CMMatrix(this.origin.add(other.origin)) +operator fun CMMatrix.minus(other: CMMatrix): CMMatrix = + CMMatrix(this.origin.subtract(other.origin)) + +infix fun CMMatrix.dot(other: CMMatrix): CMMatrix = + CMMatrix(this.origin.multiply(other.origin)) \ No newline at end of file diff --git a/kmath-commons/src/main/kotlin/scientifik/kmath/commons/linear/CMSolver.kt b/kmath-commons/src/main/kotlin/scientifik/kmath/commons/linear/CMSolver.kt new file mode 100644 index 000000000..77b688e31 --- /dev/null +++ b/kmath-commons/src/main/kotlin/scientifik/kmath/commons/linear/CMSolver.kt @@ -0,0 +1,40 @@ +package scientifik.kmath.commons.linear + +import org.apache.commons.math3.linear.* +import scientifik.kmath.linear.Point +import scientifik.kmath.structures.Matrix + +enum class CMDecomposition { + LUP, + QR, + RRQR, + EIGEN, + CHOLESKY +} + + +fun CMMatrixContext.solver(a: Matrix, decomposition: CMDecomposition = CMDecomposition.LUP) = + when (decomposition) { + CMDecomposition.LUP -> LUDecomposition(a.toCM().origin).solver + CMDecomposition.RRQR -> RRQRDecomposition(a.toCM().origin).solver + CMDecomposition.QR -> QRDecomposition(a.toCM().origin).solver + CMDecomposition.EIGEN -> EigenDecomposition(a.toCM().origin).solver + CMDecomposition.CHOLESKY -> CholeskyDecomposition(a.toCM().origin).solver + } + +fun CMMatrixContext.solve( + a: Matrix, + b: Matrix, + decomposition: CMDecomposition = CMDecomposition.LUP +) = solver(a, decomposition).solve(b.toCM().origin).asMatrix() + +fun CMMatrixContext.solve( + a: Matrix, + b: Point, + decomposition: CMDecomposition = CMDecomposition.LUP +) = solver(a, decomposition).solve(b.toCM().origin).toPoint() + +fun CMMatrixContext.inverse( + a: Matrix, + decomposition: CMDecomposition = CMDecomposition.LUP +) = solver(a, decomposition).inverse.asMatrix() diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt b/kmath-commons/src/main/kotlin/scientifik/kmath/commons/transform/Transformations.kt similarity index 64% rename from kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt rename to kmath-commons/src/main/kotlin/scientifik/kmath/commons/transform/Transformations.kt index 1a99e9fc6..bcb3ea87b 100644 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/transform/Transformations.kt +++ b/kmath-commons/src/main/kotlin/scientifik/kmath/commons/transform/Transformations.kt @@ -1,25 +1,20 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.commons.transform +package scientifik.kmath.commons.transform import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import org.apache.commons.math3.transform.* -import space.kscience.kmath.complex.Complex -import space.kscience.kmath.streaming.chunked -import space.kscience.kmath.streaming.spread -import space.kscience.kmath.structures.* - +import scientifik.kmath.operations.Complex +import scientifik.kmath.streaming.chunked +import scientifik.kmath.streaming.spread +import scientifik.kmath.structures.* /** * Streaming and buffer transformations */ -public object Transformations { +object Transformations { + private fun Buffer.toArray(): Array = Array(size) { org.apache.commons.math3.complex.Complex(get(it).re, get(it).im) } @@ -32,41 +27,41 @@ 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) } - public fun fourier( + fun fourier( normalization: DftNormalization = DftNormalization.STANDARD, - direction: TransformType = TransformType.FORWARD, + direction: TransformType = TransformType.FORWARD ): SuspendBufferTransform = { FastFourierTransformer(normalization).transform(it.toArray(), direction).asBuffer() } - public fun realFourier( + fun realFourier( normalization: DftNormalization = DftNormalization.STANDARD, - direction: TransformType = TransformType.FORWARD, + direction: TransformType = TransformType.FORWARD ): SuspendBufferTransform = { FastFourierTransformer(normalization).transform(it.asArray(), direction).asBuffer() } - public fun sine( + fun sine( normalization: DstNormalization = DstNormalization.STANDARD_DST_I, - direction: TransformType = TransformType.FORWARD, + direction: TransformType = TransformType.FORWARD ): SuspendBufferTransform = { FastSineTransformer(normalization).transform(it.asArray(), direction).asBuffer() } - public fun cosine( + fun cosine( normalization: DctNormalization = DctNormalization.STANDARD_DCT_I, - direction: TransformType = TransformType.FORWARD, + direction: TransformType = TransformType.FORWARD ): SuspendBufferTransform = { FastCosineTransformer(normalization).transform(it.asArray(), direction).asBuffer() } - public fun hadamard( - direction: TransformType = TransformType.FORWARD, + fun hadamard( + direction: TransformType = TransformType.FORWARD ): SuspendBufferTransform = { FastHadamardTransformer().transform(it.asArray(), direction).asBuffer() } @@ -76,9 +71,9 @@ public object Transformations { * Process given [Flow] with commons-math fft transformation */ @FlowPreview -public fun Flow>.FFT( +fun Flow>.FFT( normalization: DftNormalization = DftNormalization.STANDARD, - direction: TransformType = TransformType.FORWARD, + direction: TransformType = TransformType.FORWARD ): Flow> { val transform = Transformations.fourier(normalization, direction) return map { transform(it) } @@ -86,27 +81,29 @@ public fun Flow>.FFT( @FlowPreview @JvmName("realFFT") -public fun Flow>.FFT( +fun Flow>.FFT( normalization: DftNormalization = DftNormalization.STANDARD, - direction: TransformType = TransformType.FORWARD, + direction: TransformType = TransformType.FORWARD ): Flow> { val transform = Transformations.realFourier(normalization, direction) return map(transform) } /** - * Process a continuous flow of real numbers in FFT splitting it in chunks of [bufferSize]. + * Process a continous flow of real numbers in FFT splitting it in chunks of [bufferSize]. */ @FlowPreview @JvmName("realFFT") -public fun Flow.FFT( +fun Flow.FFT( bufferSize: Int = Int.MAX_VALUE, normalization: DftNormalization = DftNormalization.STANDARD, - direction: TransformType = TransformType.FORWARD, -): Flow = chunked(bufferSize).FFT(normalization, direction).spread() + direction: TransformType = TransformType.FORWARD +): Flow { + return chunked(bufferSize).FFT(normalization,direction).spread() +} /** * Map a complex flow into real flow by taking real part of each number */ @FlowPreview -public fun Flow.real(): Flow = map { it.re } +fun Flow.real(): Flow = map{it.re} \ No newline at end of file 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 deleted file mode 100644 index 8fafabf19..000000000 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpression.kt +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.commons.expressions - -import org.apache.commons.math3.analysis.differentiation.DerivativeStructure -import space.kscience.kmath.expressions.* -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.NumbersAddOperations - -/** - * A field over commons-math [DerivativeStructure]. - * - * @property order The derivation order. - * @param bindings The map of bindings values. All bindings are considered free parameters - */ -@OptIn(UnstableKMathAPI::class) -public class DerivativeStructureField( - public val order: Int, - bindings: Map, -) : ExtendedField, ExpressionAlgebra, - NumbersAddOperations { - public val numberOfVariables: Int = bindings.size - - override val zero: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order) } - override val one: DerivativeStructure by lazy { DerivativeStructure(numberOfVariables, order, 1.0) } - - override fun number(value: Number): DerivativeStructure = const(value.toDouble()) - - /** - * A class implementing both [DerivativeStructure] and [Symbol]. - */ - public inner class DerivativeStructureSymbol( - size: Int, - index: Int, - symbol: Symbol, - value: Double, - ) : DerivativeStructure(size, order, index, value), Symbol { - 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() - } - - /** - * Identity-based symbol bindings map - */ - private val variables: Map = bindings.entries.mapIndexed { index, (key, value) -> - key.identity to DerivativeStructureSymbol(numberOfVariables, index, key, value) - }.toMap() - - override fun const(value: Double): DerivativeStructure = DerivativeStructure(numberOfVariables, order, 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) - - public fun DerivativeStructure.derivative(symbols: List): Double { - require(symbols.size <= order) { "The order of derivative ${symbols.size} exceeds computed order $order" } - val ordersCount = symbols.map { it.identity }.groupBy { it }.mapValues { it.value.size } - return getPartialDerivative(*variables.keys.map { ordersCount[it] ?: 0 }.toIntArray()) - } - - public fun DerivativeStructure.derivative(vararg symbols: Symbol): Double = derivative(symbols.toList()) - - override fun DerivativeStructure.unaryMinus(): DerivativeStructure = negate() - - override fun add(a: DerivativeStructure, b: DerivativeStructure): DerivativeStructure = a.add(b) - - override fun scale(a: DerivativeStructure, value: Double): DerivativeStructure = a.multiply(value) - - override fun multiply(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() - - 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) - override fun exp(arg: DerivativeStructure): DerivativeStructure = arg.exp() - override fun ln(arg: DerivativeStructure): DerivativeStructure = arg.log() - - 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 - - public companion object : - AutoDiffProcessor> { - override fun process(function: DerivativeStructureField.() -> DerivativeStructure): DifferentiableExpression = - DerivativeStructureExpression(function) - } -} - -/** - * A constructs that creates a derivative structure with required order on-demand - */ -public class DerivativeStructureExpression( - public val function: DerivativeStructureField.() -> DerivativeStructure, -) : DifferentiableExpression { - override operator fun invoke(arguments: Map): Double = - DerivativeStructureField(0, arguments).function().value - - /** - * Get the derivative expression with given orders - */ - 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/integration/CMGaussRuleIntegrator.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt deleted file mode 100644 index 58b69b3d8..000000000 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMGaussRuleIntegrator.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package space.kscience.kmath.commons.integration - -import org.apache.commons.math3.analysis.integration.gauss.GaussIntegrator -import org.apache.commons.math3.analysis.integration.gauss.GaussIntegratorFactory -import space.kscience.kmath.integration.* - -/** - * A simple one-pass integrator based on Gauss rule - */ -public class CMGaussRuleIntegrator( - private val numpoints: Int, - private var type: GaussRule = GaussRule.LEGANDRE, -) : UnivariateIntegrator { - - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { - val range = integrand.getFeature()?.range - ?: error("Integration range is not provided") - val integrator: GaussIntegrator = getIntegrator(range) - //TODO check performance - val res: Double = integrator.integrate(integrand.function) - return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + numpoints) - } - - private fun getIntegrator(range: ClosedRange): GaussIntegrator { - return when (type) { - GaussRule.LEGANDRE -> factory.legendre( - numpoints, - range.start, - range.endInclusive - ) - GaussRule.LEGANDREHP -> factory.legendreHighPrecision( - numpoints, - range.start, - range.endInclusive - ) - GaussRule.UNIFORM -> GaussIntegrator( - getUniformRule( - range.start, - range.endInclusive, - numpoints - ) - ) - } - } - - private fun getUniformRule( - min: Double, - max: Double, - numPoints: Int, - ): org.apache.commons.math3.util.Pair { - assert(numPoints > 2) - val points = DoubleArray(numPoints) - val weights = DoubleArray(numPoints) - val step = (max - min) / (numPoints - 1) - points[0] = min - for (i in 1 until numPoints) { - points[i] = points[i - 1] + step - weights[i] = step - } - return org.apache.commons.math3.util.Pair(points, weights) - } - - public enum class GaussRule { - UNIFORM, LEGANDRE, LEGANDREHP - } - - public companion object { - private val factory: GaussIntegratorFactory = GaussIntegratorFactory() - - public fun integrate( - range: ClosedRange, - numPoints: Int = 100, - type: GaussRule = GaussRule.LEGANDRE, - function: (Double) -> Double, - ): Double = CMGaussRuleIntegrator(numPoints, type).integrate( - UnivariateIntegrand(function, IntegrationRange(range)) - ).valueOrNull!! - } -} \ No newline at end of file diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt deleted file mode 100644 index ee7bda251..000000000 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/integration/CMIntegrator.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.commons.integration - -import org.apache.commons.math3.analysis.integration.IterativeLegendreGaussIntegrator -import org.apache.commons.math3.analysis.integration.SimpsonIntegrator -import space.kscience.kmath.integration.* -import space.kscience.kmath.misc.UnstableKMathAPI - -/** - * Integration wrapper for Common-maths UnivariateIntegrator - */ -public class CMIntegrator( - private val defaultMaxCalls: Int = 200, - public val integratorBuilder: (Integrand) -> org.apache.commons.math3.analysis.integration.UnivariateIntegrator, -) : UnivariateIntegrator { - - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { - val integrator = integratorBuilder(integrand) - val maxCalls = integrand.getFeature()?.maxCalls ?: defaultMaxCalls - val remainingCalls = maxCalls - integrand.calls - val range = integrand.getFeature()?.range - ?: error("Integration range is not provided") - val res = integrator.integrate(remainingCalls, integrand.function, range.start, range.endInclusive) - - return integrand + - IntegrandValue(res) + - IntegrandAbsoluteAccuracy(integrator.absoluteAccuracy) + - IntegrandRelativeAccuracy(integrator.relativeAccuracy) + - IntegrandCallsPerformed(integrator.evaluations + integrand.calls) - } - - - public companion object { - /** - * Create a Simpson integrator based on [SimpsonIntegrator] - */ - public fun simpson(defaultMaxCalls: Int = 200): CMIntegrator = CMIntegrator(defaultMaxCalls) { integrand -> - val absoluteAccuracy = integrand.getFeature()?.accuracy - ?: SimpsonIntegrator.DEFAULT_ABSOLUTE_ACCURACY - val relativeAccuracy = integrand.getFeature()?.accuracy - ?: SimpsonIntegrator.DEFAULT_ABSOLUTE_ACCURACY - val iterations = integrand.getFeature()?.range - ?: SimpsonIntegrator.DEFAULT_MIN_ITERATIONS_COUNT..SimpsonIntegrator.SIMPSON_MAX_ITERATIONS_COUNT - - - SimpsonIntegrator(relativeAccuracy, absoluteAccuracy, iterations.first, iterations.last) - } - - /** - * Create a Gauss-Legandre integrator based on [IterativeLegendreGaussIntegrator] - */ - public fun legandre(numPoints: Int, defaultMaxCalls: Int = numPoints * 5): CMIntegrator = - CMIntegrator(defaultMaxCalls) { integrand -> - val absoluteAccuracy = integrand.getFeature()?.accuracy - ?: IterativeLegendreGaussIntegrator.DEFAULT_ABSOLUTE_ACCURACY - val relativeAccuracy = integrand.getFeature()?.accuracy - ?: IterativeLegendreGaussIntegrator.DEFAULT_ABSOLUTE_ACCURACY - val iterations = integrand.getFeature()?.range - ?: IterativeLegendreGaussIntegrator.DEFAULT_MIN_ITERATIONS_COUNT..IterativeLegendreGaussIntegrator.DEFAULT_MAX_ITERATIONS_COUNT - - IterativeLegendreGaussIntegrator( - numPoints, - relativeAccuracy, - absoluteAccuracy, - iterations.first, - iterations.last - ) - } - } -} - -@UnstableKMathAPI -public var MutableList.targetAbsoluteAccuracy: Double? - get() = filterIsInstance().lastOrNull()?.accuracy - set(value) { - value?.let { add(IntegrandAbsoluteAccuracy(value)) } - } - -@UnstableKMathAPI -public var MutableList.targetRelativeAccuracy: Double? - get() = filterIsInstance().lastOrNull()?.accuracy - set(value) { - value?.let { add(IntegrandRelativeAccuracy(value)) } - } \ No newline at end of file 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 deleted file mode 100644 index 3f8dccf27..000000000 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMMatrix.kt +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.commons.linear - -import org.apache.commons.math3.linear.* -import space.kscience.kmath.linear.* -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.StructureFeature -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.DoubleBuffer -import kotlin.reflect.KClass -import kotlin.reflect.cast - -public class CMMatrix(public val origin: RealMatrix) : Matrix { - override val rowNum: Int get() = origin.rowDimension - override val colNum: Int get() = origin.columnDimension - - override operator fun get(i: Int, j: Int): Double = origin.getEntry(i, j) -} - -public class CMVector(public val origin: RealVector) : Point { - override val size: Int get() = origin.dimension - - override operator fun get(index: Int): Double = origin.getEntry(index) - - override operator fun iterator(): Iterator = origin.toArray().iterator() -} - -public fun RealVector.toPoint(): CMVector = CMVector(this) - -public object CMLinearSpace : LinearSpace { - override val elementAlgebra: DoubleField get() = DoubleField - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: DoubleField.(i: Int, j: Int) -> Double, - ): CMMatrix { - val array = Array(rows) { i -> DoubleArray(columns) { j -> DoubleField.initializer(i, j) } } - return CMMatrix(Array2DRowRealMatrix(array)) - } - - @OptIn(UnstableKMathAPI::class) - public fun Matrix.toCM(): CMMatrix = when (val matrix = origin) { - is CMMatrix -> matrix - else -> { - //TODO add feature analysis - val array = Array(rowNum) { i -> DoubleArray(colNum) { j -> get(i, j) } } - Array2DRowRealMatrix(array).wrap() - } - } - - public fun Point.toCM(): CMVector = if (this is CMVector) this else { - val array = DoubleArray(size) { this[it] } - ArrayRealVector(array).wrap() - } - - internal fun RealMatrix.wrap(): CMMatrix = CMMatrix(this) - internal fun RealVector.wrap(): CMVector = CMVector(this) - - override fun buildVector(size: Int, initializer: DoubleField.(Int) -> Double): Point = - ArrayRealVector(DoubleArray(size) { DoubleField.initializer(it) }).wrap() - - override fun Matrix.plus(other: Matrix): CMMatrix = - toCM().origin.add(other.toCM().origin).wrap() - - override fun Point.plus(other: Point): CMVector = - toCM().origin.add(other.toCM().origin).wrap() - - override fun Point.minus(other: Point): CMVector = - toCM().origin.subtract(other.toCM().origin).wrap() - - override fun Matrix.dot(other: Matrix): CMMatrix = - toCM().origin.multiply(other.toCM().origin).wrap() - - override fun Matrix.dot(vector: Point): CMVector = - toCM().origin.preMultiply(vector.toCM().origin).wrap() - - override operator fun Matrix.minus(other: Matrix): CMMatrix = - toCM().origin.subtract(other.toCM().origin).wrap() - - override operator fun Matrix.times(value: Double): CMMatrix = - toCM().origin.scalarMultiply(value).wrap() - - override fun Double.times(m: Matrix): CMMatrix = - m * this - - override fun Point.times(value: Double): CMVector = - toCM().origin.mapMultiply(value).wrap() - - override fun Double.times(v: Point): CMVector = - v * this - - @UnstableKMathAPI - override fun getFeature(structure: Matrix, type: KClass): F? { - //Return the feature if it is intrinsic to the structure - structure.getFeature(type)?.let { return it } - - val origin = structure.toCM().origin - - return when (type) { - DiagonalFeature::class -> if (origin is DiagonalMatrix) DiagonalFeature else null - - DeterminantFeature::class, LupDecompositionFeature::class -> object : - DeterminantFeature, - LupDecompositionFeature { - private val lup by lazy { LUDecomposition(origin) } - override val determinant: Double by lazy { lup.determinant } - override val l: Matrix by lazy { CMMatrix(lup.l) + LFeature } - override val u: Matrix by lazy { CMMatrix(lup.u) + UFeature } - override val p: Matrix by lazy { CMMatrix(lup.p) } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = CholeskyDecomposition(origin) - CMMatrix(cholesky.l) + LFeature - } - } - - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { QRDecomposition(origin) } - override val q: Matrix by lazy { CMMatrix(qr.q) + OrthogonalFeature } - override val r: Matrix by lazy { CMMatrix(qr.r) + UFeature } - } - - SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { - private val sv by lazy { SingularValueDecomposition(origin) } - override val u: Matrix by lazy { CMMatrix(sv.u) } - override val s: Matrix by lazy { CMMatrix(sv.s) } - override val v: Matrix by lazy { CMMatrix(sv.v) } - override val singularValues: Point by lazy { DoubleBuffer(sv.singularValues) } - } - else -> null - }?.let(type::cast) - } -} - -public operator fun CMMatrix.plus(other: CMMatrix): CMMatrix = CMMatrix(origin.add(other.origin)) - -public operator fun CMMatrix.minus(other: CMMatrix): CMMatrix = CMMatrix(origin.subtract(other.origin)) - -public infix fun CMMatrix.dot(other: CMMatrix): CMMatrix = CMMatrix(origin.multiply(other.origin)) diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt deleted file mode 100644 index c5144c482..000000000 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/linear/CMSolver.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.commons.linear - -import org.apache.commons.math3.linear.* -import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.linear.Point - -public enum class CMDecomposition { - LUP, - QR, - RRQR, - EIGEN, - CHOLESKY -} - -public fun CMLinearSpace.solver( - a: Matrix, - decomposition: CMDecomposition = CMDecomposition.LUP, -): DecompositionSolver = when (decomposition) { - CMDecomposition.LUP -> LUDecomposition(a.toCM().origin).solver - CMDecomposition.RRQR -> RRQRDecomposition(a.toCM().origin).solver - CMDecomposition.QR -> QRDecomposition(a.toCM().origin).solver - CMDecomposition.EIGEN -> EigenDecomposition(a.toCM().origin).solver - CMDecomposition.CHOLESKY -> CholeskyDecomposition(a.toCM().origin).solver -} - -public fun CMLinearSpace.solve( - a: Matrix, - b: Matrix, - decomposition: CMDecomposition = CMDecomposition.LUP, -): CMMatrix = solver(a, decomposition).solve(b.toCM().origin).wrap() - -public fun CMLinearSpace.solve( - a: Matrix, - b: Point, - decomposition: CMDecomposition = CMDecomposition.LUP, -): CMVector = solver(a, decomposition).solve(b.toCM().origin).toPoint() - -public fun CMLinearSpace.inverse( - a: Matrix, - decomposition: CMDecomposition = CMDecomposition.LUP, -): CMMatrix = solver(a, decomposition).inverse.wrap() diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt deleted file mode 100644 index 03a1abafb..000000000 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/CMOptimization.kt +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.commons.optimization - -import org.apache.commons.math3.optim.* -import org.apache.commons.math3.optim.nonlinear.scalar.GoalType -import org.apache.commons.math3.optim.nonlinear.scalar.MultivariateOptimizer -import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunction -import org.apache.commons.math3.optim.nonlinear.scalar.ObjectiveFunctionGradient -import org.apache.commons.math3.optim.nonlinear.scalar.gradient.NonLinearConjugateGradientOptimizer -import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.AbstractSimplex -import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.NelderMeadSimplex -import org.apache.commons.math3.optim.nonlinear.scalar.noderiv.SimplexOptimizer -import space.kscience.kmath.expressions.* -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.optimization.* -import kotlin.collections.set -import kotlin.reflect.KClass - -public operator fun PointValuePair.component1(): DoubleArray = point -public operator fun PointValuePair.component2(): Double = value - -@OptIn(UnstableKMathAPI::class) -public class CMOptimization( - override val symbols: List, -) : FunctionOptimization, NoDerivFunctionOptimization, SymbolIndexer, OptimizationFeature { - - private val optimizationData: HashMap, OptimizationData> = HashMap() - private var optimizerBuilder: (() -> MultivariateOptimizer)? = null - public var convergenceChecker: ConvergenceChecker = SimpleValueChecker( - DEFAULT_RELATIVE_TOLERANCE, - DEFAULT_ABSOLUTE_TOLERANCE, - DEFAULT_MAX_ITER - ) - - override var maximize: Boolean - get() = optimizationData[GoalType::class] == GoalType.MAXIMIZE - set(value) { - optimizationData[GoalType::class] = if (value) GoalType.MAXIMIZE else GoalType.MINIMIZE - } - - public fun addOptimizationData(data: OptimizationData) { - optimizationData[data::class] = data - } - - init { - addOptimizationData(MaxEval.unlimited()) - } - - public fun exportOptimizationData(): List = optimizationData.values.toList() - - override fun initialGuess(map: Map) { - addOptimizationData(InitialGuess(map.toDoubleArray())) - } - - override fun function(expression: Expression) { - val objectiveFunction = ObjectiveFunction { - val args = it.toMap() - expression(args) - } - addOptimizationData(objectiveFunction) - } - - override fun diffFunction(expression: DifferentiableExpression) { - function(expression) - val gradientFunction = ObjectiveFunctionGradient { - val args = it.toMap() - DoubleArray(symbols.size) { index -> - expression.derivative(symbols[index])(args) - } - } - addOptimizationData(gradientFunction) - if (optimizerBuilder == null) { - optimizerBuilder = { - NonLinearConjugateGradientOptimizer( - NonLinearConjugateGradientOptimizer.Formula.FLETCHER_REEVES, - convergenceChecker - ) - } - } - } - - public fun simplex(simplex: AbstractSimplex) { - addOptimizationData(simplex) - //Set optimization builder to simplex if it is not present - if (optimizerBuilder == null) { - optimizerBuilder = { SimplexOptimizer(convergenceChecker) } - } - } - - public fun simplexSteps(steps: Map) { - simplex(NelderMeadSimplex(steps.toDoubleArray())) - } - - public fun goal(goalType: GoalType) { - addOptimizationData(goalType) - } - - public fun optimizer(block: () -> MultivariateOptimizer) { - optimizerBuilder = block - } - - override fun update(result: OptimizationResult) { - initialGuess(result.point) - } - - override fun optimize(): OptimizationResult { - val optimizer = optimizerBuilder?.invoke() ?: error("Optimizer not defined") - val (point, value) = optimizer.optimize(*optimizationData.values.toTypedArray()) - return OptimizationResult(point.toMap(), value, setOf(this)) - } - - public companion object : OptimizationProblemFactory { - public const val DEFAULT_RELATIVE_TOLERANCE: Double = 1e-4 - public const val DEFAULT_ABSOLUTE_TOLERANCE: Double = 1e-4 - public const val DEFAULT_MAX_ITER: Int = 1000 - - override fun build(symbols: List): CMOptimization = CMOptimization(symbols) - } -} - -public fun CMOptimization.initialGuess(vararg pairs: Pair): Unit = initialGuess(pairs.toMap()) -public fun CMOptimization.simplexSteps(vararg pairs: Pair): Unit = simplexSteps(pairs.toMap()) diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt deleted file mode 100644 index 267f2f1f9..000000000 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/optimization/cmFit.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.commons.optimization - -import org.apache.commons.math3.analysis.differentiation.DerivativeStructure -import space.kscience.kmath.commons.expressions.DerivativeStructureField -import space.kscience.kmath.expressions.DifferentiableExpression -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.optimization.FunctionOptimization -import space.kscience.kmath.optimization.OptimizationResult -import space.kscience.kmath.optimization.noDerivOptimizeWith -import space.kscience.kmath.optimization.optimizeWith -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asBuffer - -/** - * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation - */ -public fun FunctionOptimization.Companion.chiSquared( - x: Buffer, - y: Buffer, - yErr: Buffer, - model: DerivativeStructureField.(x: DerivativeStructure) -> DerivativeStructure, -): DifferentiableExpression = chiSquared(DerivativeStructureField, x, y, yErr, model) - -/** - * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic differentiation - */ -public fun FunctionOptimization.Companion.chiSquared( - x: Iterable, - y: Iterable, - yErr: Iterable, - model: DerivativeStructureField.(x: DerivativeStructure) -> DerivativeStructure, -): DifferentiableExpression = chiSquared( - DerivativeStructureField, - x.toList().asBuffer(), - y.toList().asBuffer(), - yErr.toList().asBuffer(), - model -) - -/** - * Optimize expression without derivatives - */ -public fun Expression.optimize( - vararg symbols: Symbol, - configuration: CMOptimization.() -> Unit, -): OptimizationResult = noDerivOptimizeWith(CMOptimization, symbols = symbols, configuration) - -/** - * Optimize differentiable expression - */ -public fun DifferentiableExpression.optimize( - vararg symbols: Symbol, - configuration: CMOptimization.() -> Unit, -): OptimizationResult = optimizeWith(CMOptimization, symbols = symbols, configuration) - -public fun DifferentiableExpression.minimize( - vararg startPoint: Pair, - configuration: CMOptimization.() -> Unit = {}, -): OptimizationResult { - val symbols = startPoint.map { it.first }.toTypedArray() - return optimize(*symbols){ - maximize = false - initialGuess(startPoint.toMap()) - diffFunction(this@minimize) - configuration() - } -} \ No newline at end of file diff --git a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt b/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt deleted file mode 100644 index 28294cf14..000000000 --- a/kmath-commons/src/main/kotlin/space/kscience/kmath/commons/random/CMRandomGeneratorWrapper.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.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()) - - override fun nextBoolean(): Boolean = generator.nextBoolean() - override fun nextFloat(): Float = generator.nextDouble().toFloat() - - override fun setSeed(seed: Int) { - generator = factory(intArrayOf(seed)) - } - - override fun setSeed(seed: IntArray) { - generator = factory(seed) - } - - override fun setSeed(seed: Long) { - setSeed(seed.toIntExact()) - } - - override fun nextBytes(bytes: ByteArray) { - generator.fillBytes(bytes) - } - - 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/test/kotlin/scientifik/kmath/commons/expressions/AutoDiffTest.kt b/kmath-commons/src/test/kotlin/scientifik/kmath/commons/expressions/AutoDiffTest.kt new file mode 100644 index 000000000..c77f30eb7 --- /dev/null +++ b/kmath-commons/src/test/kotlin/scientifik/kmath/commons/expressions/AutoDiffTest.kt @@ -0,0 +1,32 @@ +package scientifik.kmath.commons.expressions + +import scientifik.kmath.expressions.invoke +import kotlin.test.Test +import kotlin.test.assertEquals + +inline fun diff(order: Int, vararg parameters: Pair, block: DerivativeStructureField.() -> R) = + DerivativeStructureField(order, mapOf(*parameters)).run(block) + +class AutoDiffTest { + @Test + fun derivativeStructureFieldTest() { + val res = diff(3, "x" to 1.0, "y" to 1.0) { + val x by variable + val y = variable("y") + val z = x * (-sin(x * y) + y) + z.deriv("x") + } + } + + @Test + fun autoDifTest() { + val f = DiffExpression { + val x by variable + val y by variable + x.pow(2) + 2 * x * y + y.pow(2) + 1 + } + + assertEquals(10.0, f("x" to 1.0, "y" to 2.0)) + assertEquals(6.0, f.derivative("x")("x" to 1.0, "y" to 2.0)) + } +} \ No newline at end of file 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 deleted file mode 100644 index 4ed4f808f..000000000 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/expressions/DerivativeStructureExpressionTest.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.commons.expressions - -import space.kscience.kmath.expressions.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFails - -internal inline fun diff( - order: Int, - vararg parameters: Pair, - block: DerivativeStructureField.() -> Unit, -) { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - DerivativeStructureField(order, mapOf(*parameters)).run(block) -} - -internal class AutoDiffTest { - private val x by symbol - private val y by symbol - - @Test - fun derivativeStructureFieldTest() { - diff(2, x to 1.0, y to 1.0) { - val x = bindSymbol(x)//by binding() - val y = bindSymbol("y") - val z = x * (-sin(x * y) + y) + 2.0 - println(z.derivative(x)) - println(z.derivative(y, x)) - assertEquals(z.derivative(x, y), z.derivative(y, x)) - // check improper order cause failure - assertFails { z.derivative(x, x, y) } - } - } - - @Test - fun autoDifTest() { - val f = DerivativeStructureExpression { - val x by binding() - val y by binding() - x.pow(2) + 2 * x * y + y.pow(2) + 1 - } - - assertEquals(10.0, f(x to 1.0, y to 2.0)) - assertEquals(6.0, f.derivative(x)(x to 1.0, y to 2.0)) - assertEquals(2.0, f.derivative(x, x)(x to 1.234, y to -2.0)) - assertEquals(2.0, f.derivative(x, y)(x to 1.0, y to 2.0)) - } -} diff --git a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt b/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt deleted file mode 100644 index bab3aecb6..000000000 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/integration/IntegrationTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.commons.integration - -import org.junit.jupiter.api.Test -import space.kscience.kmath.integration.integrate -import space.kscience.kmath.integration.value -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField.sin -import kotlin.math.PI -import kotlin.math.abs -import kotlin.test.assertTrue - -@UnstableKMathAPI -internal class IntegrationTest { - private val function: (Double) -> Double = { sin(it) } - - @Test - fun simpson() { - val res = CMIntegrator.simpson().integrate(0.0..2 * PI, function = function).value - assertTrue { abs(res) < 1e-3 } - } - - @Test - fun customSimpson() { - val res = CMIntegrator.simpson().integrate(0.0..PI, { - targetRelativeAccuracy = 1e-4 - targetAbsoluteAccuracy = 1e-4 - }, function).value - assertTrue { abs(res - 2) < 1e-3 } - assertTrue { abs(res - 2) > 1e-12 } - } -} \ No newline at end of file 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 deleted file mode 100644 index 2f7f0c9f2..000000000 --- a/kmath-commons/src/test/kotlin/space/kscience/kmath/commons/optimization/OptimizeTest.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.commons.optimization - -import kotlinx.coroutines.runBlocking -import space.kscience.kmath.commons.expressions.DerivativeStructureExpression -import space.kscience.kmath.distributions.NormalDistribution -import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.optimization.FunctionOptimization -import space.kscience.kmath.stat.RandomGenerator -import kotlin.math.pow -import kotlin.test.Test - -internal class OptimizeTest { - val x by symbol - val y by symbol - - val normal = DerivativeStructureExpression { - exp(-bindSymbol(x).pow(2) / 2) + exp(-bindSymbol(y) - .pow(2) / 2) - } - - @Test - fun testGradientOptimization() { - val result = normal.optimize(x, y) { - initialGuess(x to 1.0, y to 1.0) - // no need to select optimizer. Gradient optimizer is used by default because gradients are provided by function. - } - println(result.point) - println(result.value) - } - - @Test - fun testSimplexOptimization() { - val result = normal.optimize(x, y) { - initialGuess(x to 1.0, y to 1.0) - simplexSteps(x to 2.0, y to 0.5) - //this sets simplex optimizer - } - - println(result.point) - println(result.value) - } - - @Test - fun testCmFit() = runBlocking { - val a by symbol - val b by symbol - val c by symbol - - 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 y = x.map { - it.pow(2) + it + 1 + chain.next() - } - - val yErr = List(x.size) { sigma } - - 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) - println(result) - println("Chi2/dof = ${result.value / (x.size - 3)}") - } -} diff --git a/kmath-complex/README.md b/kmath-complex/README.md deleted file mode 100644 index 110529b72..000000000 --- a/kmath-complex/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Module kmath-complex - -Complex and hypercomplex number systems in KMath. - - - [complex](src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt) : Complex Numbers - - [quaternion](src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt) : Quaternions - - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-complex:0.3.0-dev-14`. - -**Gradle:** -```gradle -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-complex:0.3.0-dev-14' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-complex:0.3.0-dev-14") -} -``` diff --git a/kmath-complex/build.gradle.kts b/kmath-complex/build.gradle.kts deleted file mode 100644 index ea74df646..000000000 --- a/kmath-complex/build.gradle.kts +++ /dev/null @@ -1,31 +0,0 @@ -plugins { - kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") -} - -kotlin.sourceSets { - commonMain { - dependencies { - api(project(":kmath-core")) - } - } -} - -readme { - description = "Complex numbers and quaternions." - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE - propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) - - feature( - id = "complex", - description = "Complex Numbers", - ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt" - ) - - feature( - id = "quaternion", - description = "Quaternions", - ref = "src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt" - ) -} diff --git a/kmath-complex/docs/README-TEMPLATE.md b/kmath-complex/docs/README-TEMPLATE.md deleted file mode 100644 index 106d4aff1..000000000 --- a/kmath-complex/docs/README-TEMPLATE.md +++ /dev/null @@ -1,7 +0,0 @@ -# Module kmath-complex - -Complex and hypercomplex number systems in KMath. - -${features} - -${artifact} 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 deleted file mode 100644 index 08bd12205..000000000 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Complex.kt +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.complex - -import space.kscience.kmath.memory.MemoryReader -import space.kscience.kmath.memory.MemorySpec -import space.kscience.kmath.memory.MemoryWriter -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.Norm -import space.kscience.kmath.operations.NumbersAddOperations -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.MemoryBuffer -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.MutableMemoryBuffer -import kotlin.math.* - -/** - * This complex's conjugate. - */ -public val Complex.conjugate: Complex - get() = Complex(re, -im) - -/** - * This complex's reciprocal. - */ -public val Complex.reciprocal: Complex - get() { - val scale = re * re + im * im - return Complex(re / scale, -im / scale) - } - -/** - * Absolute value of complex number. - */ -public val Complex.r: Double - get() = sqrt(re * re + im * im) - -/** - * An angle between vector represented by complex number and X axis. - */ -public val Complex.theta: Double - get() = atan(im / re) - -private val PI_DIV_2 = Complex(PI / 2, 0) - -/** - * A field of [Complex]. - */ -@OptIn(UnstableKMathAPI::class) -public object ComplexField : ExtendedField, Norm, NumbersAddOperations, - ScaleOperations { - override val zero: Complex = 0.0.toComplex() - override val one: Complex = 1.0.toComplex() - - /** - * The imaginary unit. - */ - public val i: Complex by lazy { Complex(0.0, 1.0) } - - override fun Complex.unaryMinus(): Complex = Complex(-re, -im) - - override fun number(value: Number): Complex = Complex(value.toDouble(), 0.0) - - override fun scale(a: Complex, value: Double): Complex = Complex(a.re * value, a.im * value) - - override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im) -// override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble()) - - override fun multiply(a: Complex, b: Complex): Complex = - Complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re) - - override fun divide(a: Complex, b: Complex): Complex = when { - abs(b.im) < abs(b.re) -> { - val wr = b.im / b.re - val wd = b.re + wr * b.im - - if (wd.isNaN() || wd == 0.0) - throw ArithmeticException("Division by zero or infinity") - else - Complex((a.re + a.im * wr) / wd, (a.im - a.re * wr) / wd) - } - - b.im == 0.0 -> throw ArithmeticException("Division by zero") - - else -> { - val wr = b.re / b.im - val wd = b.im + wr * b.re - - if (wd.isNaN() || wd == 0.0) - throw ArithmeticException("Division by zero or infinity") - else - Complex((a.re * wr + a.im) / wd, (a.im * wr - a.re) / wd) - } - } - - override operator fun Complex.div(k: Number): Complex = Complex(re / k.toDouble(), im / k.toDouble()) - - 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 - - override fun tan(arg: Complex): Complex { - val e1 = exp(-i * arg) - val e2 = exp(i * arg) - return i * (e1 - e2) / (e1 + e2) - } - - 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) - - override fun atan(arg: Complex): Complex { - val iArg = i * arg - return i * (ln(1 - iArg) - ln(1 + iArg)) / 2 - } - - override fun power(arg: Complex, pow: Number): Complex = if (arg.im == 0.0) - arg.re.pow(pow.toDouble()).toComplex() - else - exp(pow * ln(arg)) - - override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im)) - - override fun ln(arg: Complex): Complex = ln(arg.r) + i * atan2(arg.im, arg.re) - - /** - * Adds complex number to real one. - * - * @receiver the augend. - * @param c the addend. - * @return the sum. - */ - public operator fun Double.plus(c: Complex): Complex = add(this.toComplex(), c) - - /** - * Subtracts complex number from real one. - * - * @receiver the minuend. - * @param c the subtrahend. - * @return the difference. - */ - public operator fun Double.minus(c: Complex): Complex = add(this.toComplex(), -c) - - /** - * Adds real number to complex one. - * - * @receiver the augend. - * @param d the addend. - * @return the sum. - */ - public operator fun Complex.plus(d: Double): Complex = d + this - - /** - * Subtracts real number from complex one. - * - * @receiver the minuend. - * @param d the subtrahend. - * @return the difference. - */ - public operator fun Complex.minus(d: Double): Complex = add(this, -d.toComplex()) - - /** - * Multiplies real number by complex one. - * - * @receiver the multiplier. - * @param c the multiplicand. - * @receiver the product. - */ - public operator fun Double.times(c: Complex): Complex = Complex(c.re * this, c.im * this) - - override fun norm(arg: Complex): Complex = sqrt(arg.conjugate * arg) - - override fun bindSymbolOrNull(value: String): Complex? = if (value == "i") i else null -} - -/** - * Represents `double`-based complex number. - * - * @property re The real part. - * @property im The imaginary part. - */ -@OptIn(UnstableKMathAPI::class) -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) - - override fun toString(): String = "($re + i * $im)" - - public companion object : MemorySpec { - override val objectSize: Int - get() = 16 - - override fun MemoryReader.read(offset: Int): Complex = - Complex(readDouble(offset), readDouble(offset + 8)) - - override fun MemoryWriter.write(offset: Int, value: Complex) { - writeDouble(offset, value.re) - writeDouble(offset + 8, value.im) - } - } -} - - -/** - * Creates a complex number with real part equal to this real. - * - * @receiver the real part. - * @return the new complex number. - */ -public fun Number.toComplex(): Complex = Complex(this) - -/** - * Creates a new buffer of complex numbers with the specified [size], where each element is calculated by calling the - * specified [init] function. - */ -public inline fun Buffer.Companion.complex(size: Int, init: (Int) -> Complex): Buffer = - MemoryBuffer.create(Complex, size, init) - -/** - * Creates a new buffer of complex numbers with the specified [size], where each element is calculated by calling the - * specified [init] function. - */ -public inline fun MutableBuffer.Companion.complex(size: Int, init: (Int) -> Complex): MutableBuffer = - MutableMemoryBuffer.create(Complex, size, init) 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 deleted file mode 100644 index ae4e05631..000000000 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/ComplexFieldND.kt +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.complex - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.AlgebraND -import space.kscience.kmath.nd.BufferND -import space.kscience.kmath.nd.BufferedFieldND -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.NumbersAddOperations -import space.kscience.kmath.structures.Buffer -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - - -/** - * An optimized nd-field for complex numbers - */ -@OptIn(UnstableKMathAPI::class) -public class ComplexFieldND( - shape: IntArray, -) : BufferedFieldND(shape, ComplexField, Buffer.Companion::complex), - NumbersAddOperations>, - ExtendedField> { - - override val zero: BufferND by lazy { produce { zero } } - override val one: BufferND by lazy { produce { one } } - - override fun number(value: Number): BufferND { - val d = value.toComplex() // minimize conversions - return produce { d } - } - -// -// @Suppress("OVERRIDE_BY_INLINE") -// override inline fun map( -// arg: AbstractNDBuffer, -// transform: DoubleField.(Double) -> Double, -// ): RealNDElement { -// check(arg) -// val array = RealBuffer(arg.strides.linearSize) { offset -> DoubleField.transform(arg.buffer[offset]) } -// return BufferedNDFieldElement(this, array) -// } -// -// @Suppress("OVERRIDE_BY_INLINE") -// override inline fun produce(initializer: DoubleField.(IntArray) -> Double): RealNDElement { -// val array = RealBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) } -// return BufferedNDFieldElement(this, array) -// } -// -// @Suppress("OVERRIDE_BY_INLINE") -// override inline fun mapIndexed( -// arg: AbstractNDBuffer, -// transform: DoubleField.(index: IntArray, Double) -> Double, -// ): RealNDElement { -// check(arg) -// return BufferedNDFieldElement( -// this, -// RealBuffer(arg.strides.linearSize) { offset -> -// elementContext.transform( -// arg.strides.index(offset), -// arg.buffer[offset] -// ) -// }) -// } -// -// @Suppress("OVERRIDE_BY_INLINE") -// override inline fun combine( -// a: AbstractNDBuffer, -// b: AbstractNDBuffer, -// transform: DoubleField.(Double, Double) -> Double, -// ): RealNDElement { -// check(a, b) -// val buffer = RealBuffer(strides.linearSize) { offset -> -// elementContext.transform(a.buffer[offset], b.buffer[offset]) -// } -// return BufferedNDFieldElement(this, buffer) -// } - - override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) } - - override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } - - override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } - - override fun sin(arg: StructureND): BufferND = arg.map { sin(it) } - override fun cos(arg: StructureND): BufferND = arg.map { cos(it) } - override fun tan(arg: StructureND): BufferND = arg.map { tan(it) } - override fun asin(arg: StructureND): BufferND = arg.map { asin(it) } - override fun acos(arg: StructureND): BufferND = arg.map { acos(it) } - override fun atan(arg: StructureND): BufferND = arg.map { atan(it) } - - override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) } - override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) } - override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) } - override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) } - override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) } - override fun atanh(arg: StructureND): BufferND = arg.map { atanh(it) } -} - - -/** - * Fast element production using function inlining - */ -public inline fun BufferedFieldND.produceInline(initializer: ComplexField.(Int) -> Complex): BufferND { - contract { callsInPlace(initializer, InvocationKind.EXACTLY_ONCE) } - val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.initializer(offset) } - return BufferND(strides, buffer) -} - - -public fun AlgebraND.Companion.complex(vararg shape: Int): ComplexFieldND = ComplexFieldND(shape) - -/** - * Produce a context for n-dimensional operations inside this real field - */ -public inline fun ComplexField.nd(vararg shape: Int, action: ComplexFieldND.() -> R): R { - contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return ComplexFieldND(shape).action() -} diff --git a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt b/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt deleted file mode 100644 index e5d7ebd1e..000000000 --- a/kmath-complex/src/commonMain/kotlin/space/kscience/kmath/complex/Quaternion.kt +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.complex - -import space.kscience.kmath.memory.MemoryReader -import space.kscience.kmath.memory.MemorySpec -import space.kscience.kmath.memory.MemoryWriter -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.MemoryBuffer -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.MutableMemoryBuffer -import kotlin.math.* - -/** - * This quaternion's conjugate. - */ -public val Quaternion.conjugate: Quaternion - get() = QuaternionField { z - x * i - y * j - z * k } - -/** - * This quaternion's reciprocal. - */ -public val Quaternion.reciprocal: Quaternion - get() { - QuaternionField { - val n = norm(this@reciprocal) - return conjugate / (n * n) - } - } - -/** - * Absolute value of the quaternion. - */ -public val Quaternion.r: Double - get() = sqrt(w * w + x * x + y * y + z * z) - -/** - * A field of [Quaternion]. - */ -@OptIn(UnstableKMathAPI::class) -public object QuaternionField : Field, Norm, PowerOperations, - ExponentialOperations, NumbersAddOperations, ScaleOperations { - override val zero: Quaternion = 0.toQuaternion() - override val one: Quaternion = 1.toQuaternion() - - /** - * The `i` quaternion unit. - */ - public val i: Quaternion = Quaternion(0, 1) - - /** - * The `j` quaternion unit. - */ - public val j: Quaternion = Quaternion(0, 0, 1) - - /** - * The `k` quaternion unit. - */ - public val k: Quaternion = Quaternion(0, 0, 0, 1) - - override fun add(a: Quaternion, b: Quaternion): Quaternion = - Quaternion(a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z) - - override fun scale(a: Quaternion, value: Double): Quaternion = - Quaternion(a.w * value, a.x * value, a.y * value, a.z * value) - - override fun multiply(a: Quaternion, b: Quaternion): Quaternion = Quaternion( - a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z, - a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y, - a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x, - a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w, - ) - - override fun divide(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( - (b.w * a.w + b.x * a.x + b.y * a.y + b.z * a.z) / s, - (b.w * a.x - b.x * a.w - b.y * a.z + b.z * a.y) / s, - (b.w * a.y + b.x * a.z - b.y * a.w - b.z * a.x) / s, - (b.w * a.z - b.x * a.y + b.y * a.x - b.z * a.w) / s, - ) - } - - 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)) - } - - private fun pwr(x: Quaternion, a: Int): Quaternion = when { - a < 0 -> -(pwr(x, -a)) - a == 0 -> one - a == 1 -> x - a == 2 -> pwr2(x) - a == 3 -> pwr3(x) - a == 4 -> pwr4(x) - - else -> { - val x4 = pwr4(x) - var y = x4 - repeat((1 until a / 4).count()) { y *= x4 } - if (a % 4 == 3) y *= pwr3(x) - if (a % 4 == 2) y *= pwr2(x) - if (a % 4 == 1) y *= x - y - } - } - - private fun pwr2(x: Quaternion): Quaternion { - val aa = 2 * x.w - return Quaternion(x.w * x.w - (x.x * x.x + x.y * x.y + x.z * x.z), aa * x.x, aa * x.y, aa * x.z) - } - - private fun pwr3(x: Quaternion): Quaternion { - val a2 = x.w * x.w - val n1 = x.x * x.x + x.y * x.y + x.z * x.z - val n2 = 3.0 * a2 - n1 - return Quaternion(x.w * (a2 - 3 * n1), x.x * n2, x.y * n2, x.z * n2) - } - - private fun pwr4(x: Quaternion): Quaternion { - val a2 = x.w * x.w - val n1 = x.x * x.x + x.y * x.y + x.z * x.z - val n2 = 4 * x.w * (a2 - n1) - return Quaternion(a2 * a2 - 6 * a2 * n1 + n1 * n1, x.x * n2, x.y * n2, x.z * n2) - } - - 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) - val ea = exp(arg.w) - val n2 = ea * sin(n1) / n1 - return Quaternion(ea * cos(n1), n2 * arg.x, n2 * arg.y, n2 * arg.z) - } - - 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 { ln(arg.w.toComplex()) } - Quaternion(l.re, l.im, 0, 0) - } - - val a = arg.w - check(nu2 > 0) - val n = sqrt(a * a + nu2) - val th = acos(a / n) / sqrt(nu2) - return Quaternion(ln(n), th * arg.x, th * arg.y, th * arg.z) - } - - override operator fun Number.plus(b: Quaternion): Quaternion = Quaternion(toDouble() + b.w, b.x, b.y, b.z) - - override operator fun Number.minus(b: Quaternion): Quaternion = - Quaternion(toDouble() - b.w, -b.x, -b.y, -b.z) - - override operator fun Quaternion.plus(b: Number): Quaternion = Quaternion(w + b.toDouble(), x, y, z) - override operator fun Quaternion.minus(b: Number): Quaternion = Quaternion(w - b.toDouble(), x, y, z) - - override operator fun Number.times(b: Quaternion): Quaternion = - Quaternion(toDouble() * b.w, toDouble() * b.x, toDouble() * b.y, toDouble() * b.z) - - override fun Quaternion.unaryMinus(): Quaternion = Quaternion(-w, -x, -y, -z) - override fun norm(arg: Quaternion): Quaternion = sqrt(arg.conjugate * arg) - - override fun bindSymbolOrNull(value: String): Quaternion? = when (value) { - "i" -> i - "j" -> j - "k" -> k - else -> null - } - - override fun number(value: Number): Quaternion = value.toQuaternion() - - 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 -} - -/** - * Represents `double`-based quaternion. - * - * @property w The first component. - * @property x The second component. - * @property y The third component. - * @property z The fourth component. - */ -@OptIn(UnstableKMathAPI::class) -public data class Quaternion( - val w: Double, val x: Double, val y: Double, val z: Double, -) { - public constructor(w: Number, x: Number, y: Number, z: Number) : this( - w.toDouble(), - x.toDouble(), - y.toDouble(), - z.toDouble(), - ) - - public constructor(w: Number, x: Number, y: Number) : this(w.toDouble(), x.toDouble(), y.toDouble(), 0.0) - public constructor(w: Number, x: Number) : this(w.toDouble(), x.toDouble(), 0.0, 0.0) - public constructor(w: Number) : this(w.toDouble(), 0.0, 0.0, 0.0) - public constructor(wx: Complex, yz: Complex) : this(wx.re, wx.im, yz.re, yz.im) - public constructor(wx: Complex) : this(wx.re, wx.im, 0, 0) - - init { - require(!w.isNaN()) { "w-component of quaternion is not-a-number" } - require(!x.isNaN()) { "x-component of quaternion is not-a-number" } - require(!y.isNaN()) { "x-component of quaternion is not-a-number" } - require(!z.isNaN()) { "x-component of quaternion is not-a-number" } - } - - /** - * Returns a string representation of this quaternion. - */ - override fun toString(): String = "($w + $x * i + $y * j + $z * k)" - - public companion object : MemorySpec { - override val objectSize: Int - get() = 32 - - override fun MemoryReader.read(offset: Int): Quaternion = - Quaternion(readDouble(offset), readDouble(offset + 8), readDouble(offset + 16), readDouble(offset + 24)) - - override fun MemoryWriter.write(offset: Int, value: Quaternion) { - writeDouble(offset, value.w) - writeDouble(offset + 8, value.x) - writeDouble(offset + 16, value.y) - writeDouble(offset + 24, value.z) - } - } -} - -/** - * Creates a quaternion with real part equal to this real. - * - * @receiver the real part. - * @return a new quaternion. - */ -public fun Number.toQuaternion(): Quaternion = Quaternion(this) - -/** - * Creates a quaternion with `w`-component equal to `re`-component of given complex and `x`-component equal to - * `im`-component of given complex. - * - * @receiver the complex number. - * @return a new quaternion. - */ -public fun Complex.toQuaternion(): Quaternion = Quaternion(this) - -/** - * Creates a new buffer of quaternions with the specified [size], where each element is calculated by calling the - * specified [init] function. - */ -public inline fun Buffer.Companion.quaternion(size: Int, init: (Int) -> Quaternion): Buffer = - MemoryBuffer.create(Quaternion, size, init) - -/** - * Creates a new buffer of quaternions with the specified [size], where each element is calculated by calling the - * specified [init] function. - */ -public inline fun MutableBuffer.Companion.quaternion(size: Int, init: (Int) -> Quaternion): MutableBuffer = - MutableMemoryBuffer.create(Quaternion, size, init) diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt deleted file mode 100644 index 90e624343..000000000 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexFieldTest.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.complex - -import space.kscience.kmath.operations.invoke -import kotlin.math.PI -import kotlin.math.abs -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -internal class ComplexFieldTest { - // TODO make verifier classes available in this source set - // @Test - // fun verify() = ComplexField { FieldVerifier(this, 42.0 * i, 66.0 + 28 * i, 2.0 + 0 * i, 5).verify() } - - @Test - fun testAddition() { - assertEquals(Complex(42, 42), ComplexField { Complex(16, 16) + Complex(26, 26) }) - assertEquals(Complex(42, 16), ComplexField { Complex(16, 16) + 26 }) - assertEquals(Complex(42, 16), ComplexField { 26 + Complex(16, 16) }) - } - - @Test - fun testSubtraction() { - assertEquals(Complex(42, 42), ComplexField { Complex(86, 55) - Complex(44, 13) }) - assertEquals(Complex(42, 56), ComplexField { Complex(86, 56) - 44 }) - assertEquals(Complex(42, 56), ComplexField { 86 - Complex(44, -56) }) - } - - @Test - fun testMultiplication() { - assertEquals(Complex(42, 42), ComplexField { Complex(4.2, 0) * Complex(10, 10) }) - assertEquals(Complex(42, 21), ComplexField { Complex(4.2, 2.1) * 10 }) - assertEquals(Complex(42, 21), ComplexField { 10 * Complex(4.2, 2.1) }) - } - - @Test - fun testDivision() { - assertEquals(Complex(42, 42), ComplexField { Complex(0, 168) / Complex(2, 2) }) - assertEquals(Complex(42, 56), ComplexField { Complex(86, 56) - 44 }) - assertEquals(Complex(42, 56), ComplexField { 86 - Complex(44, -56) }) - } - - @Test - fun testSine() { - assertEquals(ComplexField { i * sinh(one) }, ComplexField { sin(i) }) - assertEquals(ComplexField { i * sinh(PI.toComplex()) }, ComplexField { sin(i * PI.toComplex()) }) - } - - @Test - fun testInverseSine() { - assertEquals(Complex(0, -0.0), ComplexField { asin(zero) }) - assertTrue(abs(ComplexField { i * asinh(one) }.r - ComplexField { asin(i) }.r) < 0.000000000000001) - } - - @Test - fun testInverseHyperbolicSine() { - assertEquals( - ComplexField { i * PI.toComplex() / 2 }, - ComplexField { asinh(i) }) - } - - @Test - fun testPower() { - assertEquals(ComplexField.zero, ComplexField { zero pow 2 }) - assertEquals(ComplexField.zero, ComplexField { zero pow 2 }) - - assertEquals( - ComplexField { i * 8 }.let { it.im.toInt() to it.re.toInt() }, - ComplexField { Complex(2, 2) pow 2 }.let { it.im.toInt() to it.re.toInt() }) - } - - @Test - fun testNorm() { - assertEquals(2.toComplex(), ComplexField { norm(2 * i) }) - } -} diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt deleted file mode 100644 index a37006f75..000000000 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.complex - -import space.kscience.kmath.operations.invoke -import kotlin.math.sqrt -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -internal class ComplexTest { - @Test - fun conjugate() = ComplexField { assertEquals(Complex(0, 42), Complex(0, -42).conjugate) } - - @Test - fun reciprocal() = ComplexField { assertTrue((Complex(0.5, -0.0) - 2.toComplex().reciprocal).r < 1e-10) } - - @Test - fun r() = ComplexField { assertEquals(sqrt(2.0), (i + 1.0.toComplex()).r) } - - @Test - fun theta() = assertEquals(0.0, 1.toComplex().theta) - - @Test - fun toComplex() { - assertEquals(Complex(42), 42.toComplex()) - assertEquals(Complex(42.0), 42.0.toComplex()) - assertEquals(Complex(42f), 42f.toComplex()) - assertEquals(Complex(42.0), 42.0.toComplex()) - assertEquals(Complex(42.toByte()), 42.toByte().toComplex()) - assertEquals(Complex(42.toShort()), 42.toShort().toComplex()) - } -} diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt deleted file mode 100644 index 00ae5ede1..000000000 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ExpressionFieldForComplexTest.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.complex - -import space.kscience.kmath.expressions.FunctionalExpressionField -import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.operations.bindSymbol -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class ExpressionFieldForComplexTest { - val x by symbol - - @Test - fun testComplex() { - val expression = FunctionalExpressionField(ComplexField).run { - val x = bindSymbol(x) - x * x + 2 * x + one - } - - assertEquals(expression(x to Complex(1.0, 0.0)), Complex(4.0, 0.0)) - } -} diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt b/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt deleted file mode 100644 index 319460c74..000000000 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/QuaternionFieldTest.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.complex - -import space.kscience.kmath.operations.invoke -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class QuaternionFieldTest { - @Test - fun testAddition() { - assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(16, 16) + Quaternion(26, 26) }) - assertEquals(Quaternion(42, 16), QuaternionField { Quaternion(16, 16) + 26 }) - assertEquals(Quaternion(42, 16), QuaternionField { 26 + Quaternion(16, 16) }) - } - -// @Test -// fun testSubtraction() { -// assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(86, 55) - Quaternion(44, 13) }) -// assertEquals(Quaternion(42, 56), QuaternionField { Quaternion(86, 56) - 44 }) -// assertEquals(Quaternion(42, 56), QuaternionField { 86 - Quaternion(44, -56) }) -// } - - @Test - fun testMultiplication() { - assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(4.2, 0) * Quaternion(10, 10) }) - assertEquals(Quaternion(42, 21), QuaternionField { Quaternion(4.2, 2.1) * 10 }) - assertEquals(Quaternion(42, 21), QuaternionField { 10 * Quaternion(4.2, 2.1) }) - } - -// @Test -// fun testDivision() { -// assertEquals(Quaternion(42, 42), QuaternionField { Quaternion(0, 168) / Quaternion(2, 2) }) -// assertEquals(Quaternion(42, 56), QuaternionField { Quaternion(86, 56) - 44 }) -// assertEquals(Quaternion(42, 56) , QuaternionField { 86 - Quaternion(44, -56) }) -// } - - @Test - fun testPower() { - assertEquals(QuaternionField.zero, QuaternionField { zero pow 2 }) - assertEquals(QuaternionField.zero, QuaternionField { zero pow 2 }) - - assertEquals( - QuaternionField { i * 8 }.let { it.x.toInt() to it.w.toInt() }, - QuaternionField { Quaternion(2, 2) pow 2 }.let { it.x.toInt() to it.w.toInt() }) - } -} diff --git a/kmath-core/README.md b/kmath-core/README.md deleted file mode 100644 index 4ea493f44..000000000 --- a/kmath-core/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Module kmath-core - -The core interfaces of KMath. - - - [algebras](src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields. - - [nd](src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt) : Many-dimensional structures and operations on them. - - [linear](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. - - [buffers](src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt) : One-dimensional structure - - [expressions](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. - - [domains](src/commonMain/kotlin/space/kscience/kmath/domains) : Domains - - [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-14`. - -**Gradle:** -```gradle -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-core:0.3.0-dev-14' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-core:0.3.0-dev-14") -} -``` diff --git a/kmath-core/api/kmath-core.api b/kmath-core/api/kmath-core.api deleted file mode 100644 index b424b59ff..000000000 --- a/kmath-core/api/kmath-core.api +++ /dev/null @@ -1,1985 +0,0 @@ -public final class space/kscience/kmath/data/ColumnarDataKt { -} - -public final class space/kscience/kmath/data/XYColumnarDataKt { - public static synthetic fun asXYData$default (Lspace/kscience/kmath/nd/Structure2D;IIILjava/lang/Object;)Lspace/kscience/kmath/data/XYColumnarData; -} - -public abstract interface class space/kscience/kmath/domains/Domain { - public abstract fun contains (Lspace/kscience/kmath/structures/Buffer;)Z - public abstract fun getDimension ()I -} - -public abstract interface class space/kscience/kmath/expressions/AutoDiffProcessor { - public abstract fun process (Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/DifferentiableExpression; -} - -public class space/kscience/kmath/expressions/AutoDiffValue { - public fun (Ljava/lang/Object;)V - public final fun getValue ()Ljava/lang/Object; -} - -public final class space/kscience/kmath/expressions/DerivationResult { - public fun (Ljava/lang/Object;Ljava/util/Map;Lspace/kscience/kmath/operations/Field;)V - public final fun derivative (Lspace/kscience/kmath/expressions/Symbol;)Ljava/lang/Object; - public final fun div ()Ljava/lang/Object; - public final fun getContext ()Lspace/kscience/kmath/operations/Field; - public final fun getValue ()Ljava/lang/Object; -} - -public abstract interface class space/kscience/kmath/expressions/DifferentiableExpression : space/kscience/kmath/expressions/Expression { - public abstract fun derivativeOrNull (Ljava/util/List;)Lspace/kscience/kmath/expressions/Expression; -} - -public final class space/kscience/kmath/expressions/DifferentiableExpressionKt { - public static final fun derivative (Lspace/kscience/kmath/expressions/DifferentiableExpression;Ljava/lang/String;)Lspace/kscience/kmath/expressions/Expression; - public static final fun derivative (Lspace/kscience/kmath/expressions/DifferentiableExpression;Ljava/util/List;)Lspace/kscience/kmath/expressions/Expression; - public static final fun derivative (Lspace/kscience/kmath/expressions/DifferentiableExpression;[Lspace/kscience/kmath/expressions/Symbol;)Lspace/kscience/kmath/expressions/Expression; -} - -public abstract interface class space/kscience/kmath/expressions/Expression { - public abstract fun invoke (Ljava/util/Map;)Ljava/lang/Object; -} - -public abstract interface class space/kscience/kmath/expressions/ExpressionAlgebra : space/kscience/kmath/operations/Algebra { - public abstract fun const (Ljava/lang/Object;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/expressions/ExpressionKt { - public static final fun binding (Lspace/kscience/kmath/expressions/ExpressionAlgebra;)Lkotlin/properties/ReadOnlyProperty; - public static final fun callByString (Lspace/kscience/kmath/expressions/Expression;[Lkotlin/Pair;)Ljava/lang/Object; - public static final fun callBySymbol (Lspace/kscience/kmath/expressions/Expression;[Lkotlin/Pair;)Ljava/lang/Object; - public static final fun invoke (Lspace/kscience/kmath/expressions/Expression;)Ljava/lang/Object; -} - -public abstract class space/kscience/kmath/expressions/FirstDerivativeExpression : space/kscience/kmath/expressions/DifferentiableExpression { - public fun ()V - public final fun derivativeOrNull (Ljava/util/List;)Lspace/kscience/kmath/expressions/Expression; - public abstract fun derivativeOrNull (Lspace/kscience/kmath/expressions/Symbol;)Lspace/kscience/kmath/expressions/Expression; -} - -public abstract class space/kscience/kmath/expressions/FunctionalExpressionAlgebra : space/kscience/kmath/expressions/ExpressionAlgebra { - public fun (Lspace/kscience/kmath/operations/Algebra;)V - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Expression; - public synthetic fun const (Ljava/lang/Object;)Ljava/lang/Object; - public fun const (Ljava/lang/Object;)Lspace/kscience/kmath/expressions/Expression; - public final fun getAlgebra ()Lspace/kscience/kmath/operations/Algebra; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; -} - -public final class space/kscience/kmath/expressions/FunctionalExpressionAlgebraKt { - public static final fun expressionInExtendedField (Lspace/kscience/kmath/operations/ExtendedField;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression; - public static final fun expressionInField (Lspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression; - public static final fun expressionInRing (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression; - public static final fun expressionInSpace (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/Expression; -} - -public class space/kscience/kmath/expressions/FunctionalExpressionExtendedField : space/kscience/kmath/expressions/FunctionalExpressionField, space/kscience/kmath/operations/ExtendedField { - public fun (Lspace/kscience/kmath/operations/ExtendedField;)V - public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; - public fun acos (Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object; - public fun asin (Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; - public fun atan (Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public synthetic fun bindSymbol (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbol (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Expression; - public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; - public fun cos (Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; - public fun exp (Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object; - public fun ln (Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/expressions/Expression; - public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun power (Lspace/kscience/kmath/expressions/Expression;Ljava/lang/Number;)Lspace/kscience/kmath/expressions/Expression; - public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; - public fun sin (Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object; - public fun sqrt (Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; -} - -public class space/kscience/kmath/expressions/FunctionalExpressionField : space/kscience/kmath/expressions/FunctionalExpressionRing, space/kscience/kmath/operations/Field, space/kscience/kmath/operations/ScaleOperations { - public fun (Lspace/kscience/kmath/operations/Field;)V - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Expression; - public final fun div (Ljava/lang/Object;Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public final fun div (Lspace/kscience/kmath/expressions/Expression;Ljava/lang/Object;)Lspace/kscience/kmath/expressions/Expression; - public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun divide (Lspace/kscience/kmath/expressions/Expression;Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale (Lspace/kscience/kmath/expressions/Expression;D)Lspace/kscience/kmath/expressions/Expression; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; -} - -public class space/kscience/kmath/expressions/FunctionalExpressionGroup : space/kscience/kmath/expressions/FunctionalExpressionAlgebra, space/kscience/kmath/operations/Group { - public fun (Lspace/kscience/kmath/operations/Group;)V - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add (Lspace/kscience/kmath/expressions/Expression;Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Lspace/kscience/kmath/expressions/Expression; - public final fun minus (Ljava/lang/Object;Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public final fun minus (Lspace/kscience/kmath/expressions/Expression;Ljava/lang/Object;)Lspace/kscience/kmath/expressions/Expression; - public final fun plus (Ljava/lang/Object;Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public final fun plus (Lspace/kscience/kmath/expressions/Expression;Ljava/lang/Object;)Lspace/kscience/kmath/expressions/Expression; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; -} - -public class space/kscience/kmath/expressions/FunctionalExpressionRing : space/kscience/kmath/expressions/FunctionalExpressionGroup, space/kscience/kmath/operations/Ring { - public fun (Lspace/kscience/kmath/operations/Ring;)V - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Lspace/kscience/kmath/expressions/Expression; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (Lspace/kscience/kmath/expressions/Expression;Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public final fun times (Ljava/lang/Object;Lspace/kscience/kmath/expressions/Expression;)Lspace/kscience/kmath/expressions/Expression; - public final fun times (Lspace/kscience/kmath/expressions/Expression;Ljava/lang/Object;)Lspace/kscience/kmath/expressions/Expression; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; -} - -public abstract interface class space/kscience/kmath/expressions/MST { -} - -public final class space/kscience/kmath/expressions/MST$Binary : space/kscience/kmath/expressions/MST { - public fun (Ljava/lang/String;Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)V - public final fun component1 ()Ljava/lang/String; - public final fun component2 ()Lspace/kscience/kmath/expressions/MST; - public final fun component3 ()Lspace/kscience/kmath/expressions/MST; - public final fun copy (Ljava/lang/String;Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; - public static synthetic fun copy$default (Lspace/kscience/kmath/expressions/MST$Binary;Ljava/lang/String;Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;ILjava/lang/Object;)Lspace/kscience/kmath/expressions/MST$Binary; - public fun equals (Ljava/lang/Object;)Z - public final fun getLeft ()Lspace/kscience/kmath/expressions/MST; - public final fun getOperation ()Ljava/lang/String; - public final fun getRight ()Lspace/kscience/kmath/expressions/MST; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class space/kscience/kmath/expressions/MST$Numeric : space/kscience/kmath/expressions/MST { - public fun (Ljava/lang/Number;)V - public final fun component1 ()Ljava/lang/Number; - public final fun copy (Ljava/lang/Number;)Lspace/kscience/kmath/expressions/MST$Numeric; - public static synthetic fun copy$default (Lspace/kscience/kmath/expressions/MST$Numeric;Ljava/lang/Number;ILjava/lang/Object;)Lspace/kscience/kmath/expressions/MST$Numeric; - public fun equals (Ljava/lang/Object;)Z - public final fun getValue ()Ljava/lang/Number; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class space/kscience/kmath/expressions/MST$Unary : space/kscience/kmath/expressions/MST { - public fun (Ljava/lang/String;Lspace/kscience/kmath/expressions/MST;)V - public final fun component1 ()Ljava/lang/String; - public final fun component2 ()Lspace/kscience/kmath/expressions/MST; - public final fun copy (Ljava/lang/String;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public static synthetic fun copy$default (Lspace/kscience/kmath/expressions/MST$Unary;Ljava/lang/String;Lspace/kscience/kmath/expressions/MST;ILjava/lang/Object;)Lspace/kscience/kmath/expressions/MST$Unary; - public fun equals (Ljava/lang/Object;)Z - public final fun getOperation ()Ljava/lang/String; - public final fun getValue ()Lspace/kscience/kmath/expressions/MST; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class space/kscience/kmath/expressions/MSTKt { - public static final fun evaluate (Lspace/kscience/kmath/operations/Algebra;Lspace/kscience/kmath/expressions/MST;)Ljava/lang/Object; - public static final fun interpret (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/operations/Algebra;Ljava/util/Map;)Ljava/lang/Object; - public static final fun interpret (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/operations/Algebra;[Lkotlin/Pair;)Ljava/lang/Object; - public static final fun toExpression (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/operations/Algebra;)Lspace/kscience/kmath/expressions/Expression; -} - -public final class space/kscience/kmath/expressions/MstExtendedField : space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/NumericAlgebra { - public static final field INSTANCE Lspace/kscience/kmath/expressions/MstExtendedField; - public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; - public fun acos (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun acosh (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; - public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object; - public fun asin (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun asinh (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; - public fun atan (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun atanh (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol; - public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; - public fun cos (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun cosh (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun divide (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; - public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; - public fun exp (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Lspace/kscience/kmath/expressions/MST$Numeric; - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Lspace/kscience/kmath/expressions/MST$Numeric; - public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object; - public fun ln (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun minus (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/expressions/MST$Numeric; - public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun power (Lspace/kscience/kmath/expressions/MST;Ljava/lang/Number;)Lspace/kscience/kmath/expressions/MST$Binary; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale (Lspace/kscience/kmath/expressions/MST;D)Lspace/kscience/kmath/expressions/MST; - public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; - public fun sin (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun sinh (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object; - public fun sqrt (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST; - public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; - public fun tan (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun tanh (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; - public synthetic fun unaryPlus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryPlus (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; -} - -public final class space/kscience/kmath/expressions/MstField : space/kscience/kmath/operations/Field, space/kscience/kmath/operations/NumbersAddOperations, space/kscience/kmath/operations/ScaleOperations { - public static final field INSTANCE Lspace/kscience/kmath/expressions/MstField; - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol; - public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun divide (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Lspace/kscience/kmath/expressions/MST$Numeric; - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Lspace/kscience/kmath/expressions/MST$Numeric; - public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun minus (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/expressions/MST$Numeric; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale (Lspace/kscience/kmath/expressions/MST;D)Lspace/kscience/kmath/expressions/MST$Binary; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; - public synthetic fun unaryPlus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryPlus (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; -} - -public final class space/kscience/kmath/expressions/MstGroup : space/kscience/kmath/operations/Group, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/ScaleOperations { - public static final field INSTANCE Lspace/kscience/kmath/expressions/MstGroup; - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol; - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Lspace/kscience/kmath/expressions/MST$Numeric; - public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun minus (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/expressions/MST$Numeric; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale (Lspace/kscience/kmath/expressions/MST;D)Lspace/kscience/kmath/expressions/MST$Binary; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; - public synthetic fun unaryPlus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryPlus (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; -} - -public final class space/kscience/kmath/expressions/MstNumericAlgebra : space/kscience/kmath/operations/NumericAlgebra { - public static final field INSTANCE Lspace/kscience/kmath/expressions/MstNumericAlgebra; - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public synthetic fun bindSymbol (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbol (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol; - public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/expressions/MST$Numeric; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; -} - -public final class space/kscience/kmath/expressions/MstRing : space/kscience/kmath/operations/NumbersAddOperations, space/kscience/kmath/operations/Ring, space/kscience/kmath/operations/ScaleOperations { - public static final field INSTANCE Lspace/kscience/kmath/expressions/MstRing; - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/Symbol; - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Lspace/kscience/kmath/expressions/MST$Numeric; - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Lspace/kscience/kmath/expressions/MST$Numeric; - public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun minus (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (Lspace/kscience/kmath/expressions/MST;Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Binary; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/expressions/MST$Numeric; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale (Lspace/kscience/kmath/expressions/MST;D)Lspace/kscience/kmath/expressions/MST$Binary; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; - public synthetic fun unaryPlus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryPlus (Lspace/kscience/kmath/expressions/MST;)Lspace/kscience/kmath/expressions/MST$Unary; -} - -public final class space/kscience/kmath/expressions/SimpleAutoDiffExpression : space/kscience/kmath/expressions/FirstDerivativeExpression { - public fun (Lspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function1;)V - public fun derivativeOrNull (Lspace/kscience/kmath/expressions/Symbol;)Lspace/kscience/kmath/expressions/Expression; - public final fun getField ()Lspace/kscience/kmath/operations/Field; - public final fun getFunction ()Lkotlin/jvm/functions/Function1; - public fun invoke (Ljava/util/Map;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/expressions/SimpleAutoDiffExtendedField : space/kscience/kmath/expressions/SimpleAutoDiffField, space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/ScaleOperations { - public fun (Lspace/kscience/kmath/operations/ExtendedField;Ljava/util/Map;)V - public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; - public fun acos (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun acosh (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object; - public fun asin (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun asinh (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; - public fun atan (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun atanh (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun bindSymbol (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbol (Ljava/lang/String;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; - public fun cos (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun cosh (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; - public fun exp (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object; - public fun ln (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public final fun pow (Lspace/kscience/kmath/expressions/AutoDiffValue;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun power (Lspace/kscience/kmath/expressions/AutoDiffValue;Ljava/lang/Number;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale (Lspace/kscience/kmath/expressions/AutoDiffValue;D)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; - public fun sin (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun sinh (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public final fun sqr (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object; - public fun sqrt (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; - public fun tan (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun tanh (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; -} - -public class space/kscience/kmath/expressions/SimpleAutoDiffField : space/kscience/kmath/expressions/ExpressionAlgebra, space/kscience/kmath/operations/Field, space/kscience/kmath/operations/NumbersAddOperations { - public fun (Lspace/kscience/kmath/operations/Field;Ljava/util/Map;)V - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add (Lspace/kscience/kmath/expressions/AutoDiffValue;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbolOrNull (Ljava/lang/String;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun const (Ljava/lang/Object;)Ljava/lang/Object; - public fun const (Ljava/lang/Object;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public final fun const (Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public final fun derive (Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; - public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun divide (Lspace/kscience/kmath/expressions/AutoDiffValue;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public final fun getContext ()Lspace/kscience/kmath/operations/Field; - public final fun getD (Lspace/kscience/kmath/expressions/AutoDiffValue;)Ljava/lang/Object; - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (Lspace/kscience/kmath/expressions/AutoDiffValue;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale (Lspace/kscience/kmath/expressions/AutoDiffValue;D)Lspace/kscience/kmath/expressions/AutoDiffValue; - public final fun setD (Lspace/kscience/kmath/expressions/AutoDiffValue;Ljava/lang/Object;)V - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; -} - -public final class space/kscience/kmath/expressions/SimpleAutoDiffKt { - public static final fun acos (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun acosh (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun asin (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun asinh (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun atan (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun atanh (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun cos (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun cosh (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun exp (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun grad (Lspace/kscience/kmath/expressions/DerivationResult;[Lspace/kscience/kmath/expressions/Symbol;)Lspace/kscience/kmath/structures/Buffer; - public static final fun ln (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun pow (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;D)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun pow (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;I)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun pow (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun simpleAutoDiff (Lspace/kscience/kmath/operations/Field;)Lspace/kscience/kmath/expressions/AutoDiffProcessor; - public static final fun simpleAutoDiff (Lspace/kscience/kmath/operations/Field;Ljava/util/Map;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/DerivationResult; - public static final fun simpleAutoDiff (Lspace/kscience/kmath/operations/Field;[Lkotlin/Pair;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/expressions/DerivationResult; - public static final fun sin (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun sinh (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun sqr (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun sqrt (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun tan (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; - public static final fun tanh (Lspace/kscience/kmath/expressions/SimpleAutoDiffField;Lspace/kscience/kmath/expressions/AutoDiffValue;)Lspace/kscience/kmath/expressions/AutoDiffValue; -} - -public final class space/kscience/kmath/expressions/StringSymbol : space/kscience/kmath/expressions/Symbol { - public static final synthetic fun box-impl (Ljava/lang/String;)Lspace/kscience/kmath/expressions/StringSymbol; - public static fun constructor-impl (Ljava/lang/String;)Ljava/lang/String; - public fun equals (Ljava/lang/Object;)Z - public static fun equals-impl (Ljava/lang/String;Ljava/lang/Object;)Z - public static final fun equals-impl0 (Ljava/lang/String;Ljava/lang/String;)Z - public fun getIdentity ()Ljava/lang/String; - public fun hashCode ()I - public static fun hashCode-impl (Ljava/lang/String;)I - public fun toString ()Ljava/lang/String; - public static fun toString-impl (Ljava/lang/String;)Ljava/lang/String; - public final synthetic fun unbox-impl ()Ljava/lang/String; -} - -public abstract interface class space/kscience/kmath/expressions/Symbol : space/kscience/kmath/expressions/MST { - public static final field Companion Lspace/kscience/kmath/expressions/Symbol$Companion; - public abstract fun getIdentity ()Ljava/lang/String; -} - -public final class space/kscience/kmath/expressions/Symbol$Companion { - public final fun getX-uKgCeAI ()Ljava/lang/String; - public final fun getY-uKgCeAI ()Ljava/lang/String; - public final fun getZ-uKgCeAI ()Ljava/lang/String; -} - -public final class space/kscience/kmath/expressions/SymbolIndexerKt { -} - -public final class space/kscience/kmath/expressions/SymbolKt { - public static final fun get (Ljava/util/Map;Ljava/lang/String;)Ljava/lang/Object; - public static final fun get (Ljava/util/Map;Lspace/kscience/kmath/expressions/Symbol;)Ljava/lang/Object; - public static final fun getSymbol ()Lkotlin/properties/ReadOnlyProperty; - public static final fun set (Ljava/util/Map;Ljava/lang/String;Ljava/lang/Object;)V - public static final fun set (Ljava/util/Map;Lspace/kscience/kmath/expressions/Symbol;Ljava/lang/Object;)V -} - -public final class space/kscience/kmath/linear/BufferedLinearSpace : space/kscience/kmath/linear/LinearSpace { - public fun (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;)V - public fun buildMatrix (IILkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/Structure2D; - public fun buildVector (ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer; - public fun dot (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public fun dot (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public fun getElementAlgebra ()Lspace/kscience/kmath/operations/Ring; - public fun minus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public fun plus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public fun times (Lspace/kscience/kmath/nd/Structure2D;Ljava/lang/Object;)Lspace/kscience/kmath/nd/Structure2D; - public fun unaryMinus (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; -} - -public abstract interface class space/kscience/kmath/linear/CholeskyDecompositionFeature : space/kscience/kmath/linear/MatrixFeature { - public abstract fun getL ()Lspace/kscience/kmath/nd/Structure2D; -} - -public abstract interface class space/kscience/kmath/linear/DeterminantFeature : space/kscience/kmath/linear/MatrixFeature { - public abstract fun getDeterminant ()Ljava/lang/Object; -} - -public abstract interface class space/kscience/kmath/linear/DiagonalFeature : space/kscience/kmath/linear/MatrixFeature { - public static final field Companion Lspace/kscience/kmath/linear/DiagonalFeature$Companion; -} - -public final class space/kscience/kmath/linear/DiagonalFeature$Companion : space/kscience/kmath/linear/DiagonalFeature { -} - -public abstract interface class space/kscience/kmath/linear/InverseMatrixFeature : space/kscience/kmath/linear/MatrixFeature { - public abstract fun getInverse ()Lspace/kscience/kmath/nd/Structure2D; -} - -public final class space/kscience/kmath/linear/LFeature : space/kscience/kmath/linear/MatrixFeature { - public static final field INSTANCE Lspace/kscience/kmath/linear/LFeature; -} - -public abstract interface class space/kscience/kmath/linear/LUDecompositionFeature : space/kscience/kmath/linear/MatrixFeature { - public abstract fun getL ()Lspace/kscience/kmath/nd/Structure2D; - public abstract fun getU ()Lspace/kscience/kmath/nd/Structure2D; -} - -public abstract interface class space/kscience/kmath/linear/LinearSolver { - public abstract fun inverse (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public abstract fun solve (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public fun solve (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; -} - -public final class space/kscience/kmath/linear/LinearSolverKt { - public static final fun asMatrix (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/linear/VirtualMatrix; - public static final fun asVector (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/structures/Buffer; -} - -public abstract interface class space/kscience/kmath/linear/LinearSpace { - public static final field Companion Lspace/kscience/kmath/linear/LinearSpace$Companion; - public abstract fun buildMatrix (IILkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/Structure2D; - public abstract fun buildVector (ILkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/structures/Buffer; - public fun dot (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public fun dot (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public abstract fun getElementAlgebra ()Lspace/kscience/kmath/operations/Ring; - public fun minus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public fun minus (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public fun plus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public fun plus (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public fun times (Ljava/lang/Object;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public fun times (Ljava/lang/Object;Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public fun times (Lspace/kscience/kmath/nd/Structure2D;Ljava/lang/Object;)Lspace/kscience/kmath/nd/Structure2D; - public fun times (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Object;)Lspace/kscience/kmath/structures/Buffer; - public fun unaryMinus (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public fun unaryMinus (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; -} - -public final class space/kscience/kmath/linear/LinearSpace$Companion { - public final fun buffered (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/linear/LinearSpace; - public static synthetic fun buffered$default (Lspace/kscience/kmath/linear/LinearSpace$Companion;Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lspace/kscience/kmath/linear/LinearSpace; - public final fun getReal ()Lspace/kscience/kmath/linear/LinearSpace; -} - -public final class space/kscience/kmath/linear/LinearSpaceKt { - public static final fun invoke (Lspace/kscience/kmath/linear/LinearSpace;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/linear/LupDecomposition : space/kscience/kmath/linear/DeterminantFeature, space/kscience/kmath/linear/LupDecompositionFeature { - public fun (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/operations/Field;Lspace/kscience/kmath/nd/Structure2D;[IZ)V - public final fun getContext ()Lspace/kscience/kmath/linear/LinearSpace; - public fun getDeterminant ()Ljava/lang/Object; - public final fun getElementContext ()Lspace/kscience/kmath/operations/Field; - public fun getL ()Lspace/kscience/kmath/nd/Structure2D; - public final fun getLu ()Lspace/kscience/kmath/nd/Structure2D; - public fun getP ()Lspace/kscience/kmath/nd/Structure2D; - public final fun getPivot ()[I - public fun getU ()Lspace/kscience/kmath/nd/Structure2D; -} - -public abstract interface class space/kscience/kmath/linear/LupDecompositionFeature : space/kscience/kmath/linear/MatrixFeature { - public abstract fun getL ()Lspace/kscience/kmath/nd/Structure2D; - public abstract fun getP ()Lspace/kscience/kmath/nd/Structure2D; - public abstract fun getU ()Lspace/kscience/kmath/nd/Structure2D; -} - -public final class space/kscience/kmath/linear/LupDecompositionKt { - public static final fun abs (Lspace/kscience/kmath/linear/LinearSpace;Ljava/lang/Comparable;)Ljava/lang/Comparable; - public static final fun inverseWithLup (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public static final fun lup (Lspace/kscience/kmath/linear/LinearSpace;Lkotlin/jvm/functions/Function2;Lspace/kscience/kmath/nd/Structure2D;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/linear/LupDecomposition; - public static final fun lup (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/linear/LupDecomposition; - public static final fun solveWithLup (Lspace/kscience/kmath/linear/LinearSpace;Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public static final fun solveWithLup (Lspace/kscience/kmath/linear/LupDecomposition;Lkotlin/jvm/functions/Function2;Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; -} - -public final class space/kscience/kmath/linear/MatrixBuilder { - public fun (Lspace/kscience/kmath/linear/LinearSpace;II)V - public final fun getColumns ()I - public final fun getLinearSpace ()Lspace/kscience/kmath/linear/LinearSpace; - public final fun getRows ()I - public final fun invoke ([Ljava/lang/Object;)Lspace/kscience/kmath/nd/Structure2D; -} - -public final class space/kscience/kmath/linear/MatrixBuilderKt { - public static final fun column (Lspace/kscience/kmath/linear/LinearSpace;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/Structure2D; - public static final fun column (Lspace/kscience/kmath/linear/LinearSpace;[Ljava/lang/Object;)Lspace/kscience/kmath/nd/Structure2D; - public static final fun row (Lspace/kscience/kmath/linear/LinearSpace;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/Structure2D; - public static final fun row (Lspace/kscience/kmath/linear/LinearSpace;[Ljava/lang/Object;)Lspace/kscience/kmath/nd/Structure2D; -} - -public abstract interface class space/kscience/kmath/linear/MatrixFeature : space/kscience/kmath/nd/StructureFeature { -} - -public final class space/kscience/kmath/linear/MatrixFeaturesKt { - public static final fun DeterminantFeature (Ljava/lang/Object;)Lspace/kscience/kmath/linear/DeterminantFeature; -} - -public final class space/kscience/kmath/linear/MatrixWrapper : space/kscience/kmath/nd/Structure2D { - public fun elements ()Lkotlin/sequences/Sequence; - public fun get (II)Ljava/lang/Object; - public fun get ([I)Ljava/lang/Object; - public fun getColNum ()I - public fun getColumns ()Ljava/util/List; - public fun getDimension ()I - public final fun getFeatures ()Ljava/util/Set; - public final fun getOrigin ()Lspace/kscience/kmath/nd/Structure2D; - public fun getRowNum ()I - public fun getRows ()Ljava/util/List; - public fun getShape ()[I - public fun toString ()Ljava/lang/String; -} - -public final class space/kscience/kmath/linear/MatrixWrapperKt { - public static final fun getOrigin (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public static final fun one (Lspace/kscience/kmath/linear/LinearSpace;II)Lspace/kscience/kmath/nd/Structure2D; - public static final fun plus (Lspace/kscience/kmath/nd/Structure2D;Ljava/util/Collection;)Lspace/kscience/kmath/linear/MatrixWrapper; - public static final fun plus (Lspace/kscience/kmath/nd/Structure2D;Lspace/kscience/kmath/linear/MatrixFeature;)Lspace/kscience/kmath/linear/MatrixWrapper; - public static final fun transpose (Lspace/kscience/kmath/nd/Structure2D;)Lspace/kscience/kmath/nd/Structure2D; - public static final fun zero (Lspace/kscience/kmath/linear/LinearSpace;II)Lspace/kscience/kmath/nd/Structure2D; -} - -public final class space/kscience/kmath/linear/OrthogonalFeature : space/kscience/kmath/linear/MatrixFeature { - public static final field INSTANCE Lspace/kscience/kmath/linear/OrthogonalFeature; -} - -public abstract interface class space/kscience/kmath/linear/QRDecompositionFeature : space/kscience/kmath/linear/MatrixFeature { - public abstract fun getQ ()Lspace/kscience/kmath/nd/Structure2D; - public abstract fun getR ()Lspace/kscience/kmath/nd/Structure2D; -} - -public abstract interface class space/kscience/kmath/linear/SingularValueDecompositionFeature : space/kscience/kmath/linear/MatrixFeature { - public abstract fun getS ()Lspace/kscience/kmath/nd/Structure2D; - public abstract fun getSingularValues ()Lspace/kscience/kmath/structures/Buffer; - public abstract fun getU ()Lspace/kscience/kmath/nd/Structure2D; - public abstract fun getV ()Lspace/kscience/kmath/nd/Structure2D; -} - -public final class space/kscience/kmath/linear/TransposedFeature : space/kscience/kmath/linear/MatrixFeature { - public fun (Lspace/kscience/kmath/nd/Structure2D;)V - public final fun getOriginal ()Lspace/kscience/kmath/nd/Structure2D; -} - -public final class space/kscience/kmath/linear/UFeature : space/kscience/kmath/linear/MatrixFeature { - public static final field INSTANCE Lspace/kscience/kmath/linear/UFeature; -} - -public final class space/kscience/kmath/linear/UnitFeature : space/kscience/kmath/linear/DiagonalFeature { - public static final field INSTANCE Lspace/kscience/kmath/linear/UnitFeature; -} - -public final class space/kscience/kmath/linear/VirtualMatrix : space/kscience/kmath/nd/Structure2D { - public fun (IILkotlin/jvm/functions/Function2;)V - public fun get (II)Ljava/lang/Object; - public fun getColNum ()I - public final fun getGenerator ()Lkotlin/jvm/functions/Function2; - public fun getRowNum ()I - public fun getShape ()[I -} - -public final class space/kscience/kmath/linear/ZeroFeature : space/kscience/kmath/linear/DiagonalFeature { - public static final field INSTANCE Lspace/kscience/kmath/linear/ZeroFeature; -} - -public final class space/kscience/kmath/misc/CumulativeKt { - public static final fun cumulative (Ljava/lang/Iterable;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Iterable; - public static final fun cumulative (Ljava/util/Iterator;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/util/Iterator; - public static final fun cumulative (Ljava/util/List;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/util/List; - public static final fun cumulative (Lkotlin/sequences/Sequence;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Lkotlin/sequences/Sequence; - public static final fun cumulativeSum (Ljava/lang/Iterable;Lspace/kscience/kmath/operations/Ring;)Ljava/lang/Iterable; - public static final fun cumulativeSum (Ljava/util/List;Lspace/kscience/kmath/operations/Ring;)Ljava/util/List; - public static final fun cumulativeSum (Lkotlin/sequences/Sequence;Lspace/kscience/kmath/operations/Ring;)Lkotlin/sequences/Sequence; - public static final fun cumulativeSumOfDouble (Ljava/lang/Iterable;)Ljava/lang/Iterable; - public static final fun cumulativeSumOfDouble (Ljava/util/List;)Ljava/util/List; - public static final fun cumulativeSumOfDouble (Lkotlin/sequences/Sequence;)Lkotlin/sequences/Sequence; - public static final fun cumulativeSumOfInt (Ljava/lang/Iterable;)Ljava/lang/Iterable; - public static final fun cumulativeSumOfInt (Ljava/util/List;)Ljava/util/List; - public static final fun cumulativeSumOfInt (Lkotlin/sequences/Sequence;)Lkotlin/sequences/Sequence; - public static final fun cumulativeSumOfLong (Ljava/lang/Iterable;)Ljava/lang/Iterable; - public static final fun cumulativeSumOfLong (Ljava/util/List;)Ljava/util/List; - public static final fun cumulativeSumOfLong (Lkotlin/sequences/Sequence;)Lkotlin/sequences/Sequence; -} - -public abstract interface annotation class space/kscience/kmath/misc/PerformancePitfall : java/lang/annotation/Annotation { -} - -public abstract interface annotation class space/kscience/kmath/misc/UnstableKMathAPI : java/lang/annotation/Annotation { -} - -public abstract interface class space/kscience/kmath/nd/AlgebraND { - public static final field Companion Lspace/kscience/kmath/nd/AlgebraND$Companion; - public abstract fun combine (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; - public abstract fun getElementContext ()Lspace/kscience/kmath/operations/Algebra; - public abstract fun getShape ()[I - public fun invoke (Lkotlin/jvm/functions/Function1;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public abstract fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; - public abstract fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; - public abstract fun produce (Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; -} - -public final class space/kscience/kmath/nd/AlgebraND$Companion { -} - -public abstract interface class space/kscience/kmath/nd/BufferAlgebraND : space/kscience/kmath/nd/AlgebraND { - public fun combine (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun combine (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; - public fun getBuffer (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/structures/Buffer; - public abstract fun getBufferFactory ()Lkotlin/jvm/functions/Function2; - public abstract fun getStrides ()Lspace/kscience/kmath/nd/Strides; - public fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; - public fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; - public fun produce (Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun produce (Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; -} - -public final class space/kscience/kmath/nd/BufferAlgebraNDKt { - public static final fun field (Lspace/kscience/kmath/nd/AlgebraND$Companion;Lspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function2;[I)Lspace/kscience/kmath/nd/BufferedFieldND; - public static final fun group (Lspace/kscience/kmath/nd/AlgebraND$Companion;Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;[I)Lspace/kscience/kmath/nd/BufferedGroupND; - public static final fun ndField (Lspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function2;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object; - public static final fun ndGroup (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object; - public static final fun ndRing (Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object; - public static final fun ring (Lspace/kscience/kmath/nd/AlgebraND$Companion;Lspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;[I)Lspace/kscience/kmath/nd/BufferedRingND; -} - -public class space/kscience/kmath/nd/BufferND : space/kscience/kmath/nd/StructureND { - public fun (Lspace/kscience/kmath/nd/Strides;Lspace/kscience/kmath/structures/Buffer;)V - public fun elements ()Lkotlin/sequences/Sequence; - public fun get ([I)Ljava/lang/Object; - public final fun getBuffer ()Lspace/kscience/kmath/structures/Buffer; - public fun getShape ()[I - public final fun getStrides ()Lspace/kscience/kmath/nd/Strides; - public fun toString ()Ljava/lang/String; -} - -public class space/kscience/kmath/nd/BufferedFieldND : space/kscience/kmath/nd/BufferedRingND, space/kscience/kmath/nd/FieldND { - public fun ([ILspace/kscience/kmath/operations/Field;Lkotlin/jvm/functions/Function2;)V - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/StructureND; -} - -public class space/kscience/kmath/nd/BufferedGroupND : space/kscience/kmath/nd/BufferAlgebraND, space/kscience/kmath/nd/GroupND { - public fun ([ILspace/kscience/kmath/operations/Group;Lkotlin/jvm/functions/Function2;)V - public final fun getBufferFactory ()Lkotlin/jvm/functions/Function2; - public synthetic fun getElementContext ()Lspace/kscience/kmath/operations/Algebra; - public final fun getElementContext ()Lspace/kscience/kmath/operations/Group; - public final fun getShape ()[I - public fun getStrides ()Lspace/kscience/kmath/nd/Strides; - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Lspace/kscience/kmath/nd/BufferND; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; -} - -public class space/kscience/kmath/nd/BufferedRingND : space/kscience/kmath/nd/BufferedGroupND, space/kscience/kmath/nd/RingND { - public fun ([ILspace/kscience/kmath/operations/Ring;Lkotlin/jvm/functions/Function2;)V - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Lspace/kscience/kmath/nd/BufferND; -} - -public final class space/kscience/kmath/nd/DefaultStrides : space/kscience/kmath/nd/Strides { - public static final field Companion Lspace/kscience/kmath/nd/DefaultStrides$Companion; - public synthetic fun ([ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun equals (Ljava/lang/Object;)Z - public fun getLinearSize ()I - public fun getShape ()[I - public fun getStrides ()[I - public fun hashCode ()I - public fun index (I)[I -} - -public final class space/kscience/kmath/nd/DefaultStrides$Companion { - public final fun invoke ([I)Lspace/kscience/kmath/nd/Strides; -} - -public final class space/kscience/kmath/nd/DoubleFieldND : space/kscience/kmath/nd/BufferedFieldND, space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/NumbersAddOperations, space/kscience/kmath/operations/ScaleOperations { - public fun ([I)V - public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; - public fun acos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun acosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object; - public fun asin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun asinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; - public fun atan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun atanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; - public fun combine (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun combine (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; - public fun cos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun cosh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; - public fun exp (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun getBuffer (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/structures/Buffer; - public fun getBuffer-Udx-57Q (Lspace/kscience/kmath/nd/StructureND;)[D - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Lspace/kscience/kmath/nd/BufferND; - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Lspace/kscience/kmath/nd/BufferND; - public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object; - public fun ln (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; - public fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; - public fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun power (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/nd/BufferND; - public fun produce (Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun produce (Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; - public fun sin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun sinh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; - public fun tan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; - public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun tanh (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/BufferND; -} - -public final class space/kscience/kmath/nd/DoubleFieldNDKt { - public static final fun nd (Lspace/kscience/kmath/operations/DoubleField;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object; - public static final fun real (Lspace/kscience/kmath/nd/AlgebraND$Companion;[I)Lspace/kscience/kmath/nd/DoubleFieldND; -} - -public abstract interface class space/kscience/kmath/nd/FieldND : space/kscience/kmath/nd/RingND, space/kscience/kmath/operations/Field, space/kscience/kmath/operations/ScaleOperations { - public fun div (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public fun div (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND; - public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun divide (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; -} - -public abstract interface class space/kscience/kmath/nd/GroupND : space/kscience/kmath/nd/AlgebraND, space/kscience/kmath/operations/Group { - public static final field Companion Lspace/kscience/kmath/nd/GroupND$Companion; - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public fun minus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public fun minus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND; - public fun plus (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public fun plus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND; -} - -public final class space/kscience/kmath/nd/GroupND$Companion { -} - -public final class space/kscience/kmath/nd/MutableBufferND : space/kscience/kmath/nd/BufferND, space/kscience/kmath/nd/MutableStructureND { - public fun (Lspace/kscience/kmath/nd/Strides;Lspace/kscience/kmath/structures/MutableBuffer;)V - public final fun getMutableBuffer ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun set ([ILjava/lang/Object;)V -} - -public abstract interface class space/kscience/kmath/nd/MutableStructure1D : space/kscience/kmath/nd/MutableStructureND, space/kscience/kmath/nd/Structure1D, space/kscience/kmath/structures/MutableBuffer { - public fun set ([ILjava/lang/Object;)V -} - -public abstract interface class space/kscience/kmath/nd/MutableStructure2D : space/kscience/kmath/nd/MutableStructureND, space/kscience/kmath/nd/Structure2D { - public fun getColumns ()Ljava/util/List; - public fun getRows ()Ljava/util/List; - public abstract fun set (IILjava/lang/Object;)V -} - -public abstract interface class space/kscience/kmath/nd/MutableStructureND : space/kscience/kmath/nd/StructureND { - public abstract fun set ([ILjava/lang/Object;)V -} - -public abstract interface class space/kscience/kmath/nd/RingND : space/kscience/kmath/nd/GroupND, space/kscience/kmath/operations/Ring { - public static final field Companion Lspace/kscience/kmath/nd/RingND$Companion; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public fun times (Ljava/lang/Object;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public fun times (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND; -} - -public final class space/kscience/kmath/nd/RingND$Companion { -} - -public final class space/kscience/kmath/nd/ShapeMismatchException : java/lang/RuntimeException { - public fun ([I[I)V - public final fun getActual ()[I - public final fun getExpected ()[I -} - -public final class space/kscience/kmath/nd/ShortRingND : space/kscience/kmath/nd/BufferedRingND, space/kscience/kmath/operations/NumbersAddOperations { - public fun ([I)V - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Lspace/kscience/kmath/nd/BufferND; - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Lspace/kscience/kmath/nd/BufferND; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/nd/BufferND; -} - -public final class space/kscience/kmath/nd/ShortRingNDKt { - public static final fun nd (Lspace/kscience/kmath/operations/ShortRing;[ILkotlin/jvm/functions/Function1;)Ljava/lang/Object; - public static final fun produceInline (Lspace/kscience/kmath/nd/BufferedRingND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/BufferND; -} - -public abstract interface class space/kscience/kmath/nd/Strides { - public abstract fun getLinearSize ()I - public abstract fun getShape ()[I - public abstract fun getStrides ()[I - public abstract fun index (I)[I - public fun indices ()Lkotlin/sequences/Sequence; - public fun offset ([I)I -} - -public abstract interface class space/kscience/kmath/nd/Structure1D : space/kscience/kmath/nd/StructureND, space/kscience/kmath/structures/Buffer { - public static final field Companion Lspace/kscience/kmath/nd/Structure1D$Companion; - public fun get ([I)Ljava/lang/Object; - public fun getDimension ()I - public fun iterator ()Ljava/util/Iterator; -} - -public final class space/kscience/kmath/nd/Structure1D$Companion { -} - -public final class space/kscience/kmath/nd/Structure1DKt { - public static final fun as1D (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructure1D; - public static final fun as1D (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Structure1D; - public static final fun asND (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/nd/Structure1D; -} - -public abstract interface class space/kscience/kmath/nd/Structure2D : space/kscience/kmath/nd/StructureND { - public static final field Companion Lspace/kscience/kmath/nd/Structure2D$Companion; - public fun elements ()Lkotlin/sequences/Sequence; - public abstract fun get (II)Ljava/lang/Object; - public fun get ([I)Ljava/lang/Object; - public abstract fun getColNum ()I - public fun getColumns ()Ljava/util/List; - public abstract fun getRowNum ()I - public fun getRows ()Ljava/util/List; - public fun getShape ()[I -} - -public final class space/kscience/kmath/nd/Structure2D$Companion { -} - -public final class space/kscience/kmath/nd/Structure2DKt { - public static final fun as2D (Lspace/kscience/kmath/nd/MutableStructureND;)Lspace/kscience/kmath/nd/MutableStructure2D; - public static final fun as2D (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/Structure2D; -} - -public abstract interface class space/kscience/kmath/nd/StructureFeature { -} - -public abstract interface class space/kscience/kmath/nd/StructureND { - public static final field Companion Lspace/kscience/kmath/nd/StructureND$Companion; - public abstract fun elements ()Lkotlin/sequences/Sequence; - public abstract fun get ([I)Ljava/lang/Object; - public fun getDimension ()I - public abstract fun getShape ()[I -} - -public final class space/kscience/kmath/nd/StructureND$Companion { - public final fun auto (Lkotlin/reflect/KClass;Lspace/kscience/kmath/nd/Strides;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND; - public final fun auto (Lkotlin/reflect/KClass;[ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND; - public final fun buffered (Lspace/kscience/kmath/nd/Strides;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND; - public final fun buffered ([ILkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/nd/BufferND; - public static synthetic fun buffered$default (Lspace/kscience/kmath/nd/StructureND$Companion;Lspace/kscience/kmath/nd/Strides;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/kmath/nd/BufferND; - public static synthetic fun buffered$default (Lspace/kscience/kmath/nd/StructureND$Companion;[ILkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/kmath/nd/BufferND; - public final fun contentEquals (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Z - public final fun toString (Lspace/kscience/kmath/nd/StructureND;)Ljava/lang/String; -} - -public final class space/kscience/kmath/nd/StructureNDKt { - public static final fun get (Lspace/kscience/kmath/nd/StructureND;[I)Ljava/lang/Object; - public static final fun mapInPlace (Lspace/kscience/kmath/nd/MutableStructureND;Lkotlin/jvm/functions/Function2;)V -} - -public abstract interface class space/kscience/kmath/operations/Algebra { - public fun binaryOperation (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public fun bindSymbol (Ljava/lang/String;)Ljava/lang/Object; - public fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun unaryOperation (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; -} - -public final class space/kscience/kmath/operations/AlgebraElementsKt { -} - -public final class space/kscience/kmath/operations/AlgebraExtensionsKt { - public static final fun abs (Lspace/kscience/kmath/operations/Ring;Ljava/lang/Comparable;)Ljava/lang/Comparable; - public static final fun average (Lspace/kscience/kmath/operations/Ring;Ljava/lang/Iterable;)Ljava/lang/Object; - public static final fun average (Lspace/kscience/kmath/operations/Ring;Lkotlin/sequences/Sequence;)Ljava/lang/Object; - public static final fun averageWith (Ljava/lang/Iterable;Lspace/kscience/kmath/operations/Ring;)Ljava/lang/Object; - public static final fun averageWith (Lkotlin/sequences/Sequence;Lspace/kscience/kmath/operations/Ring;)Ljava/lang/Object; - public static final fun power (Lspace/kscience/kmath/operations/Field;Ljava/lang/Object;I)Ljava/lang/Object; - public static final fun power-jXDDuk8 (Lspace/kscience/kmath/operations/Ring;Ljava/lang/Object;I)Ljava/lang/Object; - public static final fun sum (Lspace/kscience/kmath/operations/Ring;Ljava/lang/Iterable;)Ljava/lang/Object; - public static final fun sum (Lspace/kscience/kmath/operations/Ring;Lkotlin/sequences/Sequence;)Ljava/lang/Object; - public static final fun sumWith (Ljava/lang/Iterable;Lspace/kscience/kmath/operations/Ring;)Ljava/lang/Object; - public static final fun sumWith (Lkotlin/sequences/Sequence;Lspace/kscience/kmath/operations/Ring;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/operations/AlgebraKt { - public static final fun bindSymbol (Lspace/kscience/kmath/operations/Algebra;Lspace/kscience/kmath/expressions/Symbol;)Ljava/lang/Object; - public static final fun bindSymbolOrNull (Lspace/kscience/kmath/operations/Algebra;Lspace/kscience/kmath/expressions/Symbol;)Ljava/lang/Object; - public static final fun invoke (Lspace/kscience/kmath/operations/Algebra;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/operations/BigInt : java/lang/Comparable { - public static final field BASE J - public static final field BASE_SIZE I - public static final field Companion Lspace/kscience/kmath/operations/BigInt$Companion; - public final fun abs ()Lspace/kscience/kmath/operations/BigInt; - public final fun and (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; - public synthetic fun compareTo (Ljava/lang/Object;)I - public fun compareTo (Lspace/kscience/kmath/operations/BigInt;)I - public final fun div (I)Lspace/kscience/kmath/operations/BigInt; - public final fun div (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; - public final fun div-WZ4Q5Ns (I)Lspace/kscience/kmath/operations/BigInt; - public fun equals (Ljava/lang/Object;)Z - public fun hashCode ()I - public final fun minus (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; - public final fun modPow (Lspace/kscience/kmath/operations/BigInt;Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; - public final fun or (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; - public final fun plus (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; - public final fun pow-WZ4Q5Ns (I)Lspace/kscience/kmath/operations/BigInt; - public final fun rem (I)I - public final fun rem (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; - public final fun shl (I)Lspace/kscience/kmath/operations/BigInt; - public final fun shr (I)Lspace/kscience/kmath/operations/BigInt; - public final fun times (I)Lspace/kscience/kmath/operations/BigInt; - public final fun times (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; - public final fun times-WZ4Q5Ns (I)Lspace/kscience/kmath/operations/BigInt; - public fun toString ()Ljava/lang/String; - public final fun unaryMinus ()Lspace/kscience/kmath/operations/BigInt; -} - -public final class space/kscience/kmath/operations/BigInt$Companion { - public final fun getONE ()Lspace/kscience/kmath/operations/BigInt; - public final fun getZERO ()Lspace/kscience/kmath/operations/BigInt; -} - -public final class space/kscience/kmath/operations/BigIntField : space/kscience/kmath/operations/Field, space/kscience/kmath/operations/NumbersAddOperations, space/kscience/kmath/operations/ScaleOperations { - public static final field INSTANCE Lspace/kscience/kmath/operations/BigIntField; - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add (Lspace/kscience/kmath/operations/BigInt;Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; - public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun divide (Lspace/kscience/kmath/operations/BigInt;Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Lspace/kscience/kmath/operations/BigInt; - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Lspace/kscience/kmath/operations/BigInt; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (Lspace/kscience/kmath/operations/BigInt;Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/operations/BigInt; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale (Lspace/kscience/kmath/operations/BigInt;D)Lspace/kscience/kmath/operations/BigInt; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public final fun unaryMinus (Ljava/lang/String;)Lspace/kscience/kmath/operations/BigInt; - public fun unaryMinus (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; - public final fun unaryPlus (Ljava/lang/String;)Lspace/kscience/kmath/operations/BigInt; -} - -public final class space/kscience/kmath/operations/BigIntKt { - public static final fun abs (Lspace/kscience/kmath/operations/BigInt;)Lspace/kscience/kmath/operations/BigInt; - public static final fun bigInt (Lspace/kscience/kmath/nd/AlgebraND$Companion;[I)Lspace/kscience/kmath/nd/BufferedRingND; - public static final fun bigInt (Lspace/kscience/kmath/structures/Buffer$Companion;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; - public static final fun bigInt (Lspace/kscience/kmath/structures/MutableBuffer$Companion;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer; - public static final fun parseBigInteger (Ljava/lang/String;)Lspace/kscience/kmath/operations/BigInt; - public static final fun toBigInt (I)Lspace/kscience/kmath/operations/BigInt; - public static final fun toBigInt (J)Lspace/kscience/kmath/operations/BigInt; - public static final fun toBigInt-LpG4sQ0 ([IB)Lspace/kscience/kmath/operations/BigInt; - public static final fun toBigInt-VKZWuLQ (J)Lspace/kscience/kmath/operations/BigInt; - public static final fun toBigInt-WZ4Q5Ns (I)Lspace/kscience/kmath/operations/BigInt; -} - -public final class space/kscience/kmath/operations/ByteRing : space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring { - public static final field INSTANCE Lspace/kscience/kmath/operations/ByteRing; - public fun add (BB)Ljava/lang/Byte; - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun getOne ()Ljava/lang/Byte; - public synthetic fun getOne ()Ljava/lang/Object; - public fun getZero ()Ljava/lang/Byte; - public synthetic fun getZero ()Ljava/lang/Object; - public fun minus (BB)Ljava/lang/Byte; - public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (BB)Ljava/lang/Byte; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun norm (B)Ljava/lang/Byte; - public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Ljava/lang/Byte; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun plus (BB)Ljava/lang/Byte; - public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun times (BB)Ljava/lang/Byte; - public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (B)Ljava/lang/Byte; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/operations/DoubleField : space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/ScaleOperations { - public static final field INSTANCE Lspace/kscience/kmath/operations/DoubleField; - public fun acos (D)Ljava/lang/Double; - public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; - public fun acosh (D)Ljava/lang/Double; - public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun add (DD)Ljava/lang/Double; - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun asin (D)Ljava/lang/Double; - public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object; - public fun asinh (D)Ljava/lang/Double; - public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun atan (D)Ljava/lang/Double; - public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; - public fun atanh (D)Ljava/lang/Double; - public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public fun cos (D)Ljava/lang/Double; - public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; - public fun cosh (D)Ljava/lang/Double; - public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun div (DD)Ljava/lang/Double; - public synthetic fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun divide (DD)Ljava/lang/Double; - public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun exp (D)Ljava/lang/Double; - public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; - public fun getOne ()Ljava/lang/Double; - public synthetic fun getOne ()Ljava/lang/Object; - public fun getZero ()Ljava/lang/Double; - public synthetic fun getZero ()Ljava/lang/Object; - public fun ln (D)Ljava/lang/Double; - public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object; - public fun minus (DD)Ljava/lang/Double; - public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (DD)Ljava/lang/Double; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun norm (D)Ljava/lang/Double; - public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Ljava/lang/Double; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun plus (DD)Ljava/lang/Double; - public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun power (DLjava/lang/Number;)Ljava/lang/Double; - public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun scale (DD)Ljava/lang/Double; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun sin (D)Ljava/lang/Double; - public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; - public fun sinh (D)Ljava/lang/Double; - public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun tan (D)Ljava/lang/Double; - public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; - public fun tanh (D)Ljava/lang/Double; - public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun times (DD)Ljava/lang/Double; - public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (D)Ljava/lang/Double; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; -} - -public abstract interface class space/kscience/kmath/operations/ExponentialOperations : space/kscience/kmath/operations/Algebra { - public static final field ACOSH_OPERATION Ljava/lang/String; - public static final field ASINH_OPERATION Ljava/lang/String; - public static final field ATANH_OPERATION Ljava/lang/String; - public static final field COSH_OPERATION Ljava/lang/String; - public static final field Companion Lspace/kscience/kmath/operations/ExponentialOperations$Companion; - public static final field EXP_OPERATION Ljava/lang/String; - public static final field LN_OPERATION Ljava/lang/String; - public static final field SINH_OPERATION Ljava/lang/String; - public static final field TANH_OPERATION Ljava/lang/String; - public abstract fun acosh (Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun asinh (Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun atanh (Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun cosh (Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun exp (Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun ln (Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun tanh (Ljava/lang/Object;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/operations/ExponentialOperations$Companion { - public static final field ACOSH_OPERATION Ljava/lang/String; - public static final field ASINH_OPERATION Ljava/lang/String; - public static final field ATANH_OPERATION Ljava/lang/String; - public static final field COSH_OPERATION Ljava/lang/String; - public static final field EXP_OPERATION Ljava/lang/String; - public static final field LN_OPERATION Ljava/lang/String; - public static final field SINH_OPERATION Ljava/lang/String; - public static final field TANH_OPERATION Ljava/lang/String; -} - -public abstract interface class space/kscience/kmath/operations/ExtendedField : space/kscience/kmath/operations/ExtendedFieldOperations, space/kscience/kmath/operations/Field, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/ScaleOperations { - public fun acosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun asinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun atanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun cosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun rightSideNumberOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun tanh (Ljava/lang/Object;)Ljava/lang/Object; -} - -public abstract interface class space/kscience/kmath/operations/ExtendedFieldOperations : space/kscience/kmath/operations/ExponentialOperations, space/kscience/kmath/operations/FieldOperations, space/kscience/kmath/operations/PowerOperations, space/kscience/kmath/operations/TrigonometricOperations { - public fun tan (Ljava/lang/Object;)Ljava/lang/Object; - public fun tanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; -} - -public abstract interface class space/kscience/kmath/operations/Field : space/kscience/kmath/operations/FieldOperations, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring, space/kscience/kmath/operations/ScaleOperations { - public fun number (Ljava/lang/Number;)Ljava/lang/Object; -} - -public abstract interface class space/kscience/kmath/operations/FieldOperations : space/kscience/kmath/operations/RingOperations { - public static final field Companion Lspace/kscience/kmath/operations/FieldOperations$Companion; - public static final field DIV_OPERATION Ljava/lang/String; - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/operations/FieldOperations$Companion { - public static final field DIV_OPERATION Ljava/lang/String; -} - -public final class space/kscience/kmath/operations/FloatField : space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/Norm { - public static final field INSTANCE Lspace/kscience/kmath/operations/FloatField; - public fun acos (F)Ljava/lang/Float; - public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; - public fun acosh (F)Ljava/lang/Float; - public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun add (FF)Ljava/lang/Float; - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun asin (F)Ljava/lang/Float; - public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object; - public fun asinh (F)Ljava/lang/Float; - public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun atan (F)Ljava/lang/Float; - public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; - public fun atanh (F)Ljava/lang/Float; - public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public fun cos (F)Ljava/lang/Float; - public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; - public fun cosh (F)Ljava/lang/Float; - public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun div (FF)Ljava/lang/Float; - public synthetic fun div (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun divide (FF)Ljava/lang/Float; - public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun exp (F)Ljava/lang/Float; - public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; - public fun getOne ()Ljava/lang/Float; - public synthetic fun getOne ()Ljava/lang/Object; - public fun getZero ()Ljava/lang/Float; - public synthetic fun getZero ()Ljava/lang/Object; - public fun ln (F)Ljava/lang/Float; - public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object; - public fun minus (FF)Ljava/lang/Float; - public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (FF)Ljava/lang/Float; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun norm (F)Ljava/lang/Float; - public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Ljava/lang/Float; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun plus (FF)Ljava/lang/Float; - public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun power (FLjava/lang/Number;)Ljava/lang/Float; - public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun scale (FD)Ljava/lang/Float; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun sin (F)Ljava/lang/Float; - public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; - public fun sinh (F)Ljava/lang/Float; - public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun tan (F)Ljava/lang/Float; - public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; - public fun tanh (F)Ljava/lang/Float; - public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun times (FF)Ljava/lang/Float; - public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (F)Ljava/lang/Float; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; -} - -public abstract interface class space/kscience/kmath/operations/Group : space/kscience/kmath/operations/GroupOperations { - public abstract fun getZero ()Ljava/lang/Object; -} - -public abstract interface class space/kscience/kmath/operations/GroupOperations : space/kscience/kmath/operations/Algebra { - public static final field Companion Lspace/kscience/kmath/operations/GroupOperations$Companion; - public static final field MINUS_OPERATION Ljava/lang/String; - public static final field PLUS_OPERATION Ljava/lang/String; - public abstract fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function1; - public fun unaryPlus (Ljava/lang/Object;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/operations/GroupOperations$Companion { - public static final field MINUS_OPERATION Ljava/lang/String; - public static final field PLUS_OPERATION Ljava/lang/String; -} - -public final class space/kscience/kmath/operations/IntRing : space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring { - public static final field INSTANCE Lspace/kscience/kmath/operations/IntRing; - public fun add (II)Ljava/lang/Integer; - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun getOne ()Ljava/lang/Integer; - public synthetic fun getOne ()Ljava/lang/Object; - public fun getZero ()Ljava/lang/Integer; - public synthetic fun getZero ()Ljava/lang/Object; - public fun minus (II)Ljava/lang/Integer; - public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (II)Ljava/lang/Integer; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun norm (I)Ljava/lang/Integer; - public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Ljava/lang/Integer; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun plus (II)Ljava/lang/Integer; - public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun times (II)Ljava/lang/Integer; - public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (I)Ljava/lang/Integer; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/operations/JBigDecimalField : space/kscience/kmath/operations/JBigDecimalFieldBase { - public static final field Companion Lspace/kscience/kmath/operations/JBigDecimalField$Companion; - public fun ()V - public fun (Ljava/math/MathContext;)V - public synthetic fun (Ljava/math/MathContext;ILkotlin/jvm/internal/DefaultConstructorMarker;)V -} - -public final class space/kscience/kmath/operations/JBigDecimalField$Companion : space/kscience/kmath/operations/JBigDecimalFieldBase { -} - -public abstract class space/kscience/kmath/operations/JBigDecimalFieldBase : space/kscience/kmath/operations/Field, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/PowerOperations, space/kscience/kmath/operations/ScaleOperations { - public fun ()V - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add (Ljava/math/BigDecimal;Ljava/math/BigDecimal;)Ljava/math/BigDecimal; - public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun divide (Ljava/math/BigDecimal;Ljava/math/BigDecimal;)Ljava/math/BigDecimal; - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Ljava/math/BigDecimal; - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Ljava/math/BigDecimal; - public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun minus (Ljava/math/BigDecimal;Ljava/math/BigDecimal;)Ljava/math/BigDecimal; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (Ljava/math/BigDecimal;Ljava/math/BigDecimal;)Ljava/math/BigDecimal; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Ljava/math/BigDecimal; - public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun power (Ljava/math/BigDecimal;Ljava/lang/Number;)Ljava/math/BigDecimal; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale (Ljava/math/BigDecimal;D)Ljava/math/BigDecimal; - public synthetic fun sqrt (Ljava/lang/Object;)Ljava/lang/Object; - public fun sqrt (Ljava/math/BigDecimal;)Ljava/math/BigDecimal; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (Ljava/math/BigDecimal;)Ljava/math/BigDecimal; -} - -public final class space/kscience/kmath/operations/JBigIntegerField : space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring { - public static final field INSTANCE Lspace/kscience/kmath/operations/JBigIntegerField; - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add (Ljava/math/BigInteger;Ljava/math/BigInteger;)Ljava/math/BigInteger; - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Ljava/math/BigInteger; - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Ljava/math/BigInteger; - public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun minus (Ljava/math/BigInteger;Ljava/math/BigInteger;)Ljava/math/BigInteger; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (Ljava/math/BigInteger;Ljava/math/BigInteger;)Ljava/math/BigInteger; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Ljava/math/BigInteger; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (Ljava/math/BigInteger;)Ljava/math/BigInteger; -} - -public abstract interface annotation class space/kscience/kmath/operations/KMathContext : java/lang/annotation/Annotation { -} - -public final class space/kscience/kmath/operations/LogicAlgebra$Companion { - public final fun getFALSE ()Lspace/kscience/kmath/expressions/Symbol; - public final fun getTRUE ()Lspace/kscience/kmath/expressions/Symbol; -} - -public final class space/kscience/kmath/operations/LongRing : space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring { - public static final field INSTANCE Lspace/kscience/kmath/operations/LongRing; - public fun add (JJ)Ljava/lang/Long; - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun getOne ()Ljava/lang/Long; - public synthetic fun getOne ()Ljava/lang/Object; - public fun getZero ()Ljava/lang/Long; - public synthetic fun getZero ()Ljava/lang/Object; - public fun minus (JJ)Ljava/lang/Long; - public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (JJ)Ljava/lang/Long; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun norm (J)Ljava/lang/Long; - public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Ljava/lang/Long; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun plus (JJ)Ljava/lang/Long; - public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun times (JJ)Ljava/lang/Long; - public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (J)Ljava/lang/Long; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; -} - -public abstract interface class space/kscience/kmath/operations/Norm { - public abstract fun norm (Ljava/lang/Object;)Ljava/lang/Object; -} - -public abstract interface class space/kscience/kmath/operations/NumericAlgebra : space/kscience/kmath/operations/Algebra { - public fun bindSymbolOrNull (Ljava/lang/String;)Ljava/lang/Object; - public fun leftSideNumberOperation (Ljava/lang/String;Ljava/lang/Number;Ljava/lang/Object;)Ljava/lang/Object; - public fun leftSideNumberOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public abstract fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun rightSideNumberOperation (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun rightSideNumberOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; -} - -public final class space/kscience/kmath/operations/NumericAlgebraKt { - public static final fun getE (Lspace/kscience/kmath/operations/NumericAlgebra;)Ljava/lang/Object; - public static final fun getPi (Lspace/kscience/kmath/operations/NumericAlgebra;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/operations/OptionalOperationsKt { -} - -public abstract interface class space/kscience/kmath/operations/PowerOperations : space/kscience/kmath/operations/Algebra { - public static final field Companion Lspace/kscience/kmath/operations/PowerOperations$Companion; - public static final field POW_OPERATION Ljava/lang/String; - public static final field SQRT_OPERATION Ljava/lang/String; - public fun pow (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public abstract fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun sqrt (Ljava/lang/Object;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/operations/PowerOperations$Companion { - public static final field POW_OPERATION Ljava/lang/String; - public static final field SQRT_OPERATION Ljava/lang/String; -} - -public abstract interface class space/kscience/kmath/operations/Ring : space/kscience/kmath/operations/Group, space/kscience/kmath/operations/RingOperations { - public abstract fun getOne ()Ljava/lang/Object; -} - -public abstract interface class space/kscience/kmath/operations/RingOperations : space/kscience/kmath/operations/GroupOperations { - public static final field Companion Lspace/kscience/kmath/operations/RingOperations$Companion; - public static final field TIMES_OPERATION Ljava/lang/String; - public fun binaryOperationFunction (Ljava/lang/String;)Lkotlin/jvm/functions/Function2; - public abstract fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/operations/RingOperations$Companion { - public static final field TIMES_OPERATION Ljava/lang/String; -} - -public abstract interface class space/kscience/kmath/operations/ScaleOperations : space/kscience/kmath/operations/Algebra { - public fun div (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public abstract fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun times (Ljava/lang/Number;Ljava/lang/Object;)Ljava/lang/Object; - public fun times (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/operations/ShortRing : space/kscience/kmath/operations/Norm, space/kscience/kmath/operations/NumericAlgebra, space/kscience/kmath/operations/Ring { - public static final field INSTANCE Lspace/kscience/kmath/operations/ShortRing; - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add (SS)Ljava/lang/Short; - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Ljava/lang/Short; - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Ljava/lang/Short; - public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun minus (SS)Ljava/lang/Short; - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply (SS)Ljava/lang/Short; - public synthetic fun norm (Ljava/lang/Object;)Ljava/lang/Object; - public fun norm (S)Ljava/lang/Short; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Ljava/lang/Short; - public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun plus (SS)Ljava/lang/Short; - public synthetic fun times (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun times (SS)Ljava/lang/Short; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (S)Ljava/lang/Short; -} - -public abstract interface class space/kscience/kmath/operations/TrigonometricOperations : space/kscience/kmath/operations/Algebra { - public static final field ACOS_OPERATION Ljava/lang/String; - public static final field ASIN_OPERATION Ljava/lang/String; - public static final field ATAN_OPERATION Ljava/lang/String; - public static final field COS_OPERATION Ljava/lang/String; - public static final field Companion Lspace/kscience/kmath/operations/TrigonometricOperations$Companion; - public static final field SIN_OPERATION Ljava/lang/String; - public static final field TAN_OPERATION Ljava/lang/String; - public abstract fun acos (Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun asin (Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun atan (Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun cos (Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun sin (Ljava/lang/Object;)Ljava/lang/Object; - public abstract fun tan (Ljava/lang/Object;)Ljava/lang/Object; -} - -public final class space/kscience/kmath/operations/TrigonometricOperations$Companion { - public static final field ACOS_OPERATION Ljava/lang/String; - public static final field ASIN_OPERATION Ljava/lang/String; - public static final field ATAN_OPERATION Ljava/lang/String; - public static final field COS_OPERATION Ljava/lang/String; - public static final field SIN_OPERATION Ljava/lang/String; - public static final field TAN_OPERATION Ljava/lang/String; -} - -public final class space/kscience/kmath/structures/ArrayBuffer : space/kscience/kmath/structures/MutableBuffer { - public fun ([Ljava/lang/Object;)V - public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun get (I)Ljava/lang/Object; - public fun getSize ()I - public fun iterator ()Ljava/util/Iterator; - public fun set (ILjava/lang/Object;)V -} - -public abstract interface class space/kscience/kmath/structures/Buffer { - public static final field Companion Lspace/kscience/kmath/structures/Buffer$Companion; - public abstract fun get (I)Ljava/lang/Object; - public abstract fun getSize ()I - public abstract fun iterator ()Ljava/util/Iterator; -} - -public final class space/kscience/kmath/structures/Buffer$Companion { - public final fun auto (Lkotlin/reflect/KClass;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; - public final fun boxing (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; - public final fun contentEquals (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)Z -} - -public final class space/kscience/kmath/structures/BufferKt { - public static final fun asBuffer (Ljava/util/List;)Lspace/kscience/kmath/structures/ListBuffer; - public static final fun asBuffer ([Ljava/lang/Object;)Lspace/kscience/kmath/structures/ArrayBuffer; - public static final fun asMutableBuffer (Ljava/util/List;)Ljava/util/List; - public static final fun asReadOnly (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; - public static final fun getIndices (Lspace/kscience/kmath/structures/Buffer;)Lkotlin/ranges/IntRange; -} - -public final class space/kscience/kmath/structures/BufferOperationKt { - public static final fun asIterable (Lspace/kscience/kmath/structures/Buffer;)Ljava/lang/Iterable; - public static final fun asSequence (Lspace/kscience/kmath/structures/Buffer;)Lkotlin/sequences/Sequence; - public static final fun fold (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; - public static final fun map (Lspace/kscience/kmath/structures/Buffer;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/Buffer; - public static final fun toList (Lspace/kscience/kmath/structures/Buffer;)Ljava/util/List; -} - -public final class space/kscience/kmath/structures/DoubleBuffer : space/kscience/kmath/structures/MutableBuffer { - public static final synthetic fun box-impl ([D)Lspace/kscience/kmath/structures/DoubleBuffer; - public static fun constructor-impl ([D)[D - public synthetic fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun copy-Dv3HvWU ()[D - public static fun copy-Dv3HvWU ([D)[D - public fun equals (Ljava/lang/Object;)Z - public static fun equals-impl ([DLjava/lang/Object;)Z - public static final fun equals-impl0 ([D[D)Z - public fun get (I)Ljava/lang/Double; - public synthetic fun get (I)Ljava/lang/Object; - public static fun get-impl ([DI)Ljava/lang/Double; - public final fun getArray ()[D - public fun getSize ()I - public static fun getSize-impl ([D)I - public fun hashCode ()I - public static fun hashCode-impl ([D)I - public synthetic fun iterator ()Ljava/util/Iterator; - public fun iterator ()Lkotlin/collections/DoubleIterator; - public static fun iterator-impl ([D)Lkotlin/collections/DoubleIterator; - public fun set (ID)V - public synthetic fun set (ILjava/lang/Object;)V - public static fun set-impl ([DID)V - public fun toString ()Ljava/lang/String; - public static fun toString-impl ([D)Ljava/lang/String; - public final synthetic fun unbox-impl ()[D -} - -public final class space/kscience/kmath/structures/DoubleBufferField : space/kscience/kmath/operations/ExtendedField { - public fun (I)V - public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; - public fun acos-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun acosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object; - public fun asin-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun asinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; - public fun atan-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun atanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; - public fun cos-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun cosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun divide-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; - public fun exp-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Lspace/kscience/kmath/structures/Buffer; - public final fun getSize ()I - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Lspace/kscience/kmath/structures/Buffer; - public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object; - public fun ln-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/structures/Buffer; - public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun power-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Number;)[D - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;D)[D - public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; - public fun sin-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun sinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; - public fun tan-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun tanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (Lspace/kscience/kmath/structures/Buffer;)Lspace/kscience/kmath/structures/Buffer; -} - -public final class space/kscience/kmath/structures/DoubleBufferFieldOperations : space/kscience/kmath/operations/ExtendedFieldOperations { - public static final field INSTANCE Lspace/kscience/kmath/structures/DoubleBufferFieldOperations; - public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; - public fun acos-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun acosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun acosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun add-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object; - public fun asin-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun asinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun asinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; - public fun atan-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun atanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun atanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; - public fun cos-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun cosh (Ljava/lang/Object;)Ljava/lang/Object; - public fun cosh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun divide (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun divide-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; - public fun exp-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object; - public fun ln-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun multiply (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun multiply-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun power-CZ9oacQ (Lspace/kscience/kmath/structures/Buffer;Ljava/lang/Number;)[D - public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; - public fun sin-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun sinh (Ljava/lang/Object;)Ljava/lang/Object; - public fun sinh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; - public fun tan-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun tanh (Ljava/lang/Object;)Ljava/lang/Object; - public fun tanh-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus-Udx-57Q (Lspace/kscience/kmath/structures/Buffer;)[D -} - -public final class space/kscience/kmath/structures/DoubleBufferKt { - public static final fun DoubleBuffer (ILkotlin/jvm/functions/Function1;)[D - public static final fun DoubleBuffer ([D)[D - public static final fun asBuffer ([D)[D - public static final fun contentEquals-2c9zdjM ([D[D)Z - public static final fun toDoubleArray (Lspace/kscience/kmath/structures/Buffer;)[D -} - -public abstract interface class space/kscience/kmath/structures/FlaggedBuffer : space/kscience/kmath/structures/Buffer { - public abstract fun getFlag (I)B -} - -public final class space/kscience/kmath/structures/FlaggedBufferKt { - public static final fun forEachValid (Lspace/kscience/kmath/structures/FlaggedDoubleBuffer;Lkotlin/jvm/functions/Function1;)V - public static final fun hasFlag (Lspace/kscience/kmath/structures/FlaggedBuffer;ILspace/kscience/kmath/structures/ValueFlag;)Z - public static final fun isMissing (Lspace/kscience/kmath/structures/FlaggedBuffer;I)Z - public static final fun isValid (Lspace/kscience/kmath/structures/FlaggedBuffer;I)Z -} - -public final class space/kscience/kmath/structures/FlaggedDoubleBuffer : space/kscience/kmath/structures/Buffer, space/kscience/kmath/structures/FlaggedBuffer { - public fun ([D[B)V - public fun get (I)Ljava/lang/Double; - public synthetic fun get (I)Ljava/lang/Object; - public fun getFlag (I)B - public final fun getFlags ()[B - public fun getSize ()I - public final fun getValues ()[D - public fun iterator ()Ljava/util/Iterator; -} - -public final class space/kscience/kmath/structures/FloatBuffer : space/kscience/kmath/structures/MutableBuffer { - public static final synthetic fun box-impl ([F)Lspace/kscience/kmath/structures/FloatBuffer; - public static fun constructor-impl ([F)[F - public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public static fun copy-impl ([F)Lspace/kscience/kmath/structures/MutableBuffer; - public fun equals (Ljava/lang/Object;)Z - public static fun equals-impl ([FLjava/lang/Object;)Z - public static final fun equals-impl0 ([F[F)Z - public fun get (I)Ljava/lang/Float; - public synthetic fun get (I)Ljava/lang/Object; - public static fun get-impl ([FI)Ljava/lang/Float; - public final fun getArray ()[F - public fun getSize ()I - public static fun getSize-impl ([F)I - public fun hashCode ()I - public static fun hashCode-impl ([F)I - public synthetic fun iterator ()Ljava/util/Iterator; - public fun iterator ()Lkotlin/collections/FloatIterator; - public static fun iterator-impl ([F)Lkotlin/collections/FloatIterator; - public fun set (IF)V - public synthetic fun set (ILjava/lang/Object;)V - public static fun set-impl ([FIF)V - public fun toString ()Ljava/lang/String; - public static fun toString-impl ([F)Ljava/lang/String; - public final synthetic fun unbox-impl ()[F -} - -public final class space/kscience/kmath/structures/FloatBufferKt { - public static final fun FloatBuffer (ILkotlin/jvm/functions/Function1;)[F - public static final fun FloatBuffer ([F)[F - public static final fun asBuffer ([F)[F - public static final fun toFloatArray (Lspace/kscience/kmath/structures/Buffer;)[F -} - -public final class space/kscience/kmath/structures/IntBuffer : space/kscience/kmath/structures/MutableBuffer { - public static final synthetic fun box-impl ([I)Lspace/kscience/kmath/structures/IntBuffer; - public static fun constructor-impl ([I)[I - public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public static fun copy-impl ([I)Lspace/kscience/kmath/structures/MutableBuffer; - public fun equals (Ljava/lang/Object;)Z - public static fun equals-impl ([ILjava/lang/Object;)Z - public static final fun equals-impl0 ([I[I)Z - public fun get (I)Ljava/lang/Integer; - public synthetic fun get (I)Ljava/lang/Object; - public static fun get-impl ([II)Ljava/lang/Integer; - public final fun getArray ()[I - public fun getSize ()I - public static fun getSize-impl ([I)I - public fun hashCode ()I - public static fun hashCode-impl ([I)I - public synthetic fun iterator ()Ljava/util/Iterator; - public fun iterator ()Lkotlin/collections/IntIterator; - public static fun iterator-impl ([I)Lkotlin/collections/IntIterator; - public fun set (II)V - public synthetic fun set (ILjava/lang/Object;)V - public static fun set-impl ([III)V - public fun toString ()Ljava/lang/String; - public static fun toString-impl ([I)Ljava/lang/String; - public final synthetic fun unbox-impl ()[I -} - -public final class space/kscience/kmath/structures/IntBufferKt { - public static final fun IntBuffer (ILkotlin/jvm/functions/Function1;)[I - public static final fun IntBuffer ([I)[I - public static final fun asBuffer ([I)[I - public static final fun toIntArray (Lspace/kscience/kmath/structures/Buffer;)[I -} - -public final class space/kscience/kmath/structures/ListBuffer : space/kscience/kmath/structures/Buffer { - public fun (ILkotlin/jvm/functions/Function1;)V - public fun (Ljava/util/List;)V - public fun get (I)Ljava/lang/Object; - public final fun getList ()Ljava/util/List; - public fun getSize ()I - public fun iterator ()Ljava/util/Iterator; -} - -public final class space/kscience/kmath/structures/LongBuffer : space/kscience/kmath/structures/MutableBuffer { - public static final synthetic fun box-impl ([J)Lspace/kscience/kmath/structures/LongBuffer; - public static fun constructor-impl ([J)[J - public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public static fun copy-impl ([J)Lspace/kscience/kmath/structures/MutableBuffer; - public fun equals (Ljava/lang/Object;)Z - public static fun equals-impl ([JLjava/lang/Object;)Z - public static final fun equals-impl0 ([J[J)Z - public fun get (I)Ljava/lang/Long; - public synthetic fun get (I)Ljava/lang/Object; - public static fun get-impl ([JI)Ljava/lang/Long; - public final fun getArray ()[J - public fun getSize ()I - public static fun getSize-impl ([J)I - public fun hashCode ()I - public static fun hashCode-impl ([J)I - public synthetic fun iterator ()Ljava/util/Iterator; - public fun iterator ()Lkotlin/collections/LongIterator; - public static fun iterator-impl ([J)Lkotlin/collections/LongIterator; - public fun set (IJ)V - public synthetic fun set (ILjava/lang/Object;)V - public static fun set-impl ([JIJ)V - public fun toString ()Ljava/lang/String; - public static fun toString-impl ([J)Ljava/lang/String; - public final synthetic fun unbox-impl ()[J -} - -public final class space/kscience/kmath/structures/LongBufferKt { - public static final fun LongBuffer (ILkotlin/jvm/functions/Function1;)[J - public static final fun LongBuffer ([J)[J - public static final fun asBuffer ([J)[J - public static final fun toLongArray (Lspace/kscience/kmath/structures/Buffer;)[J -} - -public class space/kscience/kmath/structures/MemoryBuffer : space/kscience/kmath/structures/Buffer { - public static final field Companion Lspace/kscience/kmath/structures/MemoryBuffer$Companion; - public fun (Lspace/kscience/kmath/memory/Memory;Lspace/kscience/kmath/memory/MemorySpec;)V - public fun get (I)Ljava/lang/Object; - protected final fun getMemory ()Lspace/kscience/kmath/memory/Memory; - public fun getSize ()I - protected final fun getSpec ()Lspace/kscience/kmath/memory/MemorySpec; - public fun iterator ()Ljava/util/Iterator; -} - -public final class space/kscience/kmath/structures/MemoryBuffer$Companion { - public final fun create (Lspace/kscience/kmath/memory/MemorySpec;I)Lspace/kscience/kmath/structures/MemoryBuffer; - public final fun create (Lspace/kscience/kmath/memory/MemorySpec;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MemoryBuffer; -} - -public abstract interface class space/kscience/kmath/structures/MutableBuffer : space/kscience/kmath/structures/Buffer { - public static final field Companion Lspace/kscience/kmath/structures/MutableBuffer$Companion; - public abstract fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public abstract fun set (ILjava/lang/Object;)V -} - -public final class space/kscience/kmath/structures/MutableBuffer$Companion { - public final fun auto (Lkotlin/reflect/KClass;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer; - public final fun boxing (ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableBuffer; - public final fun double-CZ9oacQ (ILkotlin/jvm/functions/Function1;)[D - public final fun float-YxruXGw (ILkotlin/jvm/functions/Function1;)[F - public final fun int-Ye6GY2U (ILkotlin/jvm/functions/Function1;)[I - public final fun long-BuQOeTY (ILkotlin/jvm/functions/Function1;)[J - public final fun short-1yRgbGw (ILkotlin/jvm/functions/Function1;)[S -} - -public final class space/kscience/kmath/structures/MutableListBuffer : space/kscience/kmath/structures/MutableBuffer { - public static final synthetic fun box-impl (Ljava/util/List;)Lspace/kscience/kmath/structures/MutableListBuffer; - public static fun constructor-impl (ILkotlin/jvm/functions/Function1;)Ljava/util/List; - public static fun constructor-impl (Ljava/util/List;)Ljava/util/List; - public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public static fun copy-impl (Ljava/util/List;)Lspace/kscience/kmath/structures/MutableBuffer; - public fun equals (Ljava/lang/Object;)Z - public static fun equals-impl (Ljava/util/List;Ljava/lang/Object;)Z - public static final fun equals-impl0 (Ljava/util/List;Ljava/util/List;)Z - public fun get (I)Ljava/lang/Object; - public static fun get-impl (Ljava/util/List;I)Ljava/lang/Object; - public final fun getList ()Ljava/util/List; - public fun getSize ()I - public static fun getSize-impl (Ljava/util/List;)I - public fun hashCode ()I - public static fun hashCode-impl (Ljava/util/List;)I - public fun iterator ()Ljava/util/Iterator; - public static fun iterator-impl (Ljava/util/List;)Ljava/util/Iterator; - public fun set (ILjava/lang/Object;)V - public static fun set-impl (Ljava/util/List;ILjava/lang/Object;)V - public fun toString ()Ljava/lang/String; - public static fun toString-impl (Ljava/util/List;)Ljava/lang/String; - public final synthetic fun unbox-impl ()Ljava/util/List; -} - -public final class space/kscience/kmath/structures/MutableMemoryBuffer : space/kscience/kmath/structures/MemoryBuffer, space/kscience/kmath/structures/MutableBuffer { - public static final field Companion Lspace/kscience/kmath/structures/MutableMemoryBuffer$Companion; - public fun (Lspace/kscience/kmath/memory/Memory;Lspace/kscience/kmath/memory/MemorySpec;)V - public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun set (ILjava/lang/Object;)V -} - -public final class space/kscience/kmath/structures/MutableMemoryBuffer$Companion { - public final fun create (Lspace/kscience/kmath/memory/MemorySpec;I)Lspace/kscience/kmath/structures/MutableMemoryBuffer; - public final fun create (Lspace/kscience/kmath/memory/MemorySpec;ILkotlin/jvm/functions/Function1;)Lspace/kscience/kmath/structures/MutableMemoryBuffer; -} - -public final class space/kscience/kmath/structures/ReadOnlyBuffer : space/kscience/kmath/structures/Buffer { - public static final synthetic fun box-impl (Lspace/kscience/kmath/structures/MutableBuffer;)Lspace/kscience/kmath/structures/ReadOnlyBuffer; - public static fun constructor-impl (Lspace/kscience/kmath/structures/MutableBuffer;)Lspace/kscience/kmath/structures/MutableBuffer; - public fun equals (Ljava/lang/Object;)Z - public static fun equals-impl (Lspace/kscience/kmath/structures/MutableBuffer;Ljava/lang/Object;)Z - public static final fun equals-impl0 (Lspace/kscience/kmath/structures/MutableBuffer;Lspace/kscience/kmath/structures/MutableBuffer;)Z - public fun get (I)Ljava/lang/Object; - public static fun get-impl (Lspace/kscience/kmath/structures/MutableBuffer;I)Ljava/lang/Object; - public final fun getBuffer ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun getSize ()I - public static fun getSize-impl (Lspace/kscience/kmath/structures/MutableBuffer;)I - public fun hashCode ()I - public static fun hashCode-impl (Lspace/kscience/kmath/structures/MutableBuffer;)I - public fun iterator ()Ljava/util/Iterator; - public static fun iterator-impl (Lspace/kscience/kmath/structures/MutableBuffer;)Ljava/util/Iterator; - public fun toString ()Ljava/lang/String; - public static fun toString-impl (Lspace/kscience/kmath/structures/MutableBuffer;)Ljava/lang/String; - public final synthetic fun unbox-impl ()Lspace/kscience/kmath/structures/MutableBuffer; -} - -public final class space/kscience/kmath/structures/ShortBuffer : space/kscience/kmath/structures/MutableBuffer { - public static final synthetic fun box-impl ([S)Lspace/kscience/kmath/structures/ShortBuffer; - public static fun constructor-impl ([S)[S - public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public static fun copy-impl ([S)Lspace/kscience/kmath/structures/MutableBuffer; - public fun equals (Ljava/lang/Object;)Z - public static fun equals-impl ([SLjava/lang/Object;)Z - public static final fun equals-impl0 ([S[S)Z - public synthetic fun get (I)Ljava/lang/Object; - public fun get (I)Ljava/lang/Short; - public static fun get-impl ([SI)Ljava/lang/Short; - public final fun getArray ()[S - public fun getSize ()I - public static fun getSize-impl ([S)I - public fun hashCode ()I - public static fun hashCode-impl ([S)I - public synthetic fun iterator ()Ljava/util/Iterator; - public fun iterator ()Lkotlin/collections/ShortIterator; - public static fun iterator-impl ([S)Lkotlin/collections/ShortIterator; - public synthetic fun set (ILjava/lang/Object;)V - public fun set (IS)V - public static fun set-impl ([SIS)V - public fun toString ()Ljava/lang/String; - public static fun toString-impl ([S)Ljava/lang/String; - public final synthetic fun unbox-impl ()[S -} - -public final class space/kscience/kmath/structures/ShortBufferKt { - public static final fun ShortBuffer (ILkotlin/jvm/functions/Function1;)[S - public static final fun ShortBuffer ([S)[S - public static final fun asBuffer ([S)[S - public static final fun toShortArray (Lspace/kscience/kmath/structures/Buffer;)[S -} - -public final class space/kscience/kmath/structures/ValueFlag : java/lang/Enum { - public static final field MISSING Lspace/kscience/kmath/structures/ValueFlag; - public static final field NAN Lspace/kscience/kmath/structures/ValueFlag; - public static final field NEGATIVE_INFINITY Lspace/kscience/kmath/structures/ValueFlag; - public static final field POSITIVE_INFINITY Lspace/kscience/kmath/structures/ValueFlag; - public final fun getMask ()B - public static fun valueOf (Ljava/lang/String;)Lspace/kscience/kmath/structures/ValueFlag; - public static fun values ()[Lspace/kscience/kmath/structures/ValueFlag; -} - -public final class space/kscience/kmath/structures/VirtualBuffer : space/kscience/kmath/structures/Buffer { - public fun (ILkotlin/jvm/functions/Function1;)V - public fun get (I)Ljava/lang/Object; - public fun getSize ()I - public fun iterator ()Ljava/util/Iterator; -} - diff --git a/kmath-core/build.gradle.kts b/kmath-core/build.gradle.kts index 564d06f49..092f3deb7 100644 --- a/kmath-core/build.gradle.kts +++ b/kmath-core/build.gradle.kts @@ -1,7 +1,5 @@ plugins { - kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("scientifik.mpp") } kotlin.sourceSets { @@ -10,51 +8,4 @@ kotlin.sourceSets { api(project(":kmath-memory")) } } -} - -readme { - description = "Core classes, algebra definitions, basic linear algebra" - maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT - propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) - - feature( - id = "algebras", - ref = "src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt", - ) { "Algebraic structures like rings, spaces and fields." } - - feature( - id = "nd", - ref = "src/commonMain/kotlin/space/kscience/kmath/structures/StructureND.kt", - ) { "Many-dimensional structures and operations on them." } - - feature( - id = "linear", - 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", - ref = "src/commonMain/kotlin/space/kscience/kmath/structures/Buffers.kt", - ) { "One-dimensional structure" } - - feature( - id = "expressions", - 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() - } - - feature( - id = "domains", - ref = "src/commonMain/kotlin/space/kscience/kmath/domains", - ) { "Domains" } - - feature( - id = "autodiff", - ref = "src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt" - ) { "Automatic differentiation" } -} +} \ No newline at end of file diff --git a/kmath-core/docs/README-TEMPLATE.md b/kmath-core/docs/README-TEMPLATE.md deleted file mode 100644 index 41cfe1ccb..000000000 --- a/kmath-core/docs/README-TEMPLATE.md +++ /dev/null @@ -1,7 +0,0 @@ -# Module kmath-core - -The core interfaces of KMath. - -${features} - -${artifact} diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/expressions/Expression.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/expressions/Expression.kt new file mode 100644 index 000000000..aa7407c0a --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/expressions/Expression.kt @@ -0,0 +1,92 @@ +package scientifik.kmath.expressions + +import scientifik.kmath.operations.Field +import scientifik.kmath.operations.Ring +import scientifik.kmath.operations.Space + +/** + * An elementary function that could be invoked on a map of arguments + */ +interface Expression { + operator fun invoke(arguments: Map): T +} + +operator fun Expression.invoke(vararg pairs: Pair): T = invoke(mapOf(*pairs)) + +/** + * A context for expression construction + */ +interface ExpressionContext { + /** + * Introduce a variable into expression context + */ + fun variable(name: String, default: T? = null): Expression + + /** + * A constant expression which does not depend on arguments + */ + fun const(value: T): Expression +} + +internal class VariableExpression(val name: String, val default: T? = null) : Expression { + override fun invoke(arguments: Map): T = + arguments[name] ?: default ?: error("Parameter not found: $name") +} + +internal class ConstantExpression(val value: T) : Expression { + override fun invoke(arguments: Map): T = value +} + +internal class SumExpression(val context: Space, val first: Expression, val second: Expression) : + Expression { + override fun invoke(arguments: Map): T = context.add(first.invoke(arguments), second.invoke(arguments)) +} + +internal class ProductExpression(val context: Ring, val first: Expression, val second: Expression) : + Expression { + override fun invoke(arguments: Map): T = + context.multiply(first.invoke(arguments), second.invoke(arguments)) +} + +internal class ConstProductExpession(val context: Space, val expr: Expression, val const: Number) : + Expression { + override fun invoke(arguments: Map): T = context.multiply(expr.invoke(arguments), const) +} + +internal class DivExpession(val context: Field, val expr: Expression, val second: Expression) : + Expression { + override fun invoke(arguments: Map): T = context.divide(expr.invoke(arguments), second.invoke(arguments)) +} + +open class ExpressionSpace(val space: Space) : Space>, ExpressionContext { + override val zero: Expression = ConstantExpression(space.zero) + + override fun const(value: T): Expression = ConstantExpression(value) + + override fun variable(name: String, default: T?): Expression = VariableExpression(name, default) + + override fun add(a: Expression, b: Expression): Expression = SumExpression(space, a, b) + + override fun multiply(a: Expression, k: Number): Expression = ConstProductExpession(space, a, k) + + + operator fun Expression.plus(arg: T) = this + const(arg) + operator fun Expression.minus(arg: T) = this - const(arg) + + operator fun T.plus(arg: Expression) = arg + this + operator fun T.minus(arg: Expression) = arg - this +} + + +class ExpressionField(val field: Field) : Field>, ExpressionSpace(field) { + override val one: Expression = ConstantExpression(field.one) + override fun multiply(a: Expression, b: Expression): Expression = ProductExpression(field, a, b) + + override fun divide(a: Expression, b: Expression): Expression = DivExpession(field, a, b) + + operator fun Expression.times(arg: T) = this * const(arg) + operator fun Expression.div(arg: T) = this / const(arg) + + operator fun T.times(arg: Expression) = arg * this + operator fun T.div(arg: Expression) = arg / this +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/BufferMatrix.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/BufferMatrix.kt new file mode 100644 index 000000000..73b18b810 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/BufferMatrix.kt @@ -0,0 +1,124 @@ +package scientifik.kmath.linear + +import scientifik.kmath.operations.RealField +import scientifik.kmath.operations.Ring +import scientifik.kmath.structures.* + +/** + * Basic implementation of Matrix space based on [NDStructure] + */ +class BufferMatrixContext>( + override val elementContext: R, + private val bufferFactory: BufferFactory +) : GenericMatrixContext { + + override fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> T): BufferMatrix { + val buffer = bufferFactory(rows * columns) { offset -> initializer(offset / columns, offset % columns) } + return BufferMatrix(rows, columns, buffer) + } + + override fun point(size: Int, initializer: (Int) -> T): Point = bufferFactory(size, initializer) + + companion object { + + } +} + +@Suppress("OVERRIDE_BY_INLINE") +object RealMatrixContext : GenericMatrixContext { + + override val elementContext get() = RealField + + override inline fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> Double): Matrix { + val buffer = DoubleBuffer(rows * columns) { offset -> initializer(offset / columns, offset % columns) } + return BufferMatrix(rows, columns, buffer) + } + + override inline fun point(size: Int, initializer: (Int) -> Double): Point = DoubleBuffer(size,initializer) +} + +class BufferMatrix( + override val rowNum: Int, + override val colNum: Int, + val buffer: Buffer, + override val features: Set = emptySet() +) : FeaturedMatrix { + + init { + if (buffer.size != rowNum * colNum) { + error("Dimension mismatch for matrix structure") + } + } + + override val shape: IntArray get() = intArrayOf(rowNum, colNum) + + override fun suggestFeature(vararg features: MatrixFeature) = + BufferMatrix(rowNum, colNum, buffer, this.features + features) + + override fun get(index: IntArray): T = get(index[0], index[1]) + + override fun get(i: Int, j: Int): T = buffer[i * colNum + j] + + override fun elements(): Sequence> = sequence { + for (i in 0 until rowNum) { + for (j in 0 until colNum) { + yield(intArrayOf(i, j) to get(i, j)) + } + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + return when (other) { + is NDStructure<*> -> return NDStructure.equals(this, other) + else -> false + } + } + + override fun hashCode(): Int { + var result = buffer.hashCode() + result = 31 * result + features.hashCode() + return result + } + + override fun toString(): String { + return if (rowNum <= 5 && colNum <= 5) { + "Matrix(rowsNum = $rowNum, colNum = $colNum, features=$features)\n" + + rows.asSequence().joinToString(prefix = "(", postfix = ")", separator = "\n ") { + it.asSequence().joinToString(separator = "\t") { it.toString() } + } + } else { + "Matrix(rowsNum = $rowNum, colNum = $colNum, features=$features)" + } + } +} + +/** + * Optimized dot product for real matrices + */ +infix fun BufferMatrix.dot(other: BufferMatrix): BufferMatrix { + if (this.colNum != other.rowNum) error("Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})") + + val array = DoubleArray(this.rowNum * other.colNum) + + //convert to array to insure there is not memory indirection + fun Buffer.unsafeArray(): DoubleArray = if (this is DoubleBuffer) { + array + } else { + DoubleArray(size) { get(it) } + } + + val a = this.buffer.unsafeArray() + val b = other.buffer.unsafeArray() + + for (i in (0 until rowNum)) { + for (j in (0 until other.colNum)) { + for (k in (0 until colNum)) { + array[i * other.colNum + j] += a[i * colNum + k] * b[k * other.colNum + j] + } + } + } + + val buffer = DoubleBuffer(array) + return BufferMatrix(rowNum, other.colNum, buffer) +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/FeaturedMatrix.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/FeaturedMatrix.kt new file mode 100644 index 000000000..297586fc6 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/FeaturedMatrix.kt @@ -0,0 +1,86 @@ +package scientifik.kmath.linear + +import scientifik.kmath.operations.Ring +import scientifik.kmath.structures.Matrix +import scientifik.kmath.structures.Structure2D +import scientifik.kmath.structures.asBuffer +import kotlin.math.sqrt + +/** + * A 2d structure plus optional matrix-specific features + */ +interface FeaturedMatrix : Matrix { + + override val shape: IntArray get() = intArrayOf(rowNum, colNum) + + val features: Set + + /** + * Suggest new feature for this matrix. The result is the new matrix that may or may not reuse existing data structure. + * + * The implementation does not guarantee to check that matrix actually have the feature, so one should be careful to + * add only those features that are valid. + */ + fun suggestFeature(vararg features: MatrixFeature): FeaturedMatrix + + companion object { + + } +} + +fun Structure2D.Companion.real(rows: Int, columns: Int, initializer: (Int, Int) -> Double) = + MatrixContext.real.produce(rows, columns, initializer) + +/** + * Build a square matrix from given elements. + */ +fun Structure2D.Companion.square(vararg elements: T): FeaturedMatrix { + val size: Int = sqrt(elements.size.toDouble()).toInt() + if (size * size != elements.size) error("The number of elements ${elements.size} is not a full square") + val buffer = elements.asBuffer() + return BufferMatrix(size, size, buffer) +} + +val Matrix<*>.features get() = (this as? FeaturedMatrix)?.features?: emptySet() + +/** + * Check if matrix has the given feature class + */ +inline fun Matrix<*>.hasFeature(): Boolean = + features.find { it is T } != null + +/** + * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the criteria + */ +inline fun Matrix<*>.getFeature(): T? = + features.filterIsInstance().firstOrNull() + +/** + * Diagonal matrix of ones. The matrix is virtual no actual matrix is created + */ +fun > GenericMatrixContext.one(rows: Int, columns: Int): FeaturedMatrix = + VirtualMatrix(rows, columns, DiagonalFeature) { i, j -> + if (i == j) elementContext.one else elementContext.zero + } + + +/** + * A virtual matrix of zeroes + */ +fun > GenericMatrixContext.zero(rows: Int, columns: Int): FeaturedMatrix = + VirtualMatrix(rows, columns) { _, _ -> elementContext.zero } + +class TransposedFeature(val original: Matrix) : MatrixFeature + +/** + * Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A` + */ +fun Matrix.transpose(): Matrix { + return this.getFeature>()?.original ?: VirtualMatrix( + this.colNum, + this.rowNum, + setOf(TransposedFeature(this)) + ) { i, j -> get(j, i) } +} + +infix fun Matrix.dot(other: Matrix): Matrix = with(MatrixContext.real) { dot(other) } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LUPDecomposition.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LUPDecomposition.kt new file mode 100644 index 000000000..87e0ef027 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LUPDecomposition.kt @@ -0,0 +1,252 @@ +package scientifik.kmath.linear + +import scientifik.kmath.operations.Field +import scientifik.kmath.operations.RealField +import scientifik.kmath.operations.Ring +import scientifik.kmath.structures.BufferAccessor2D +import scientifik.kmath.structures.Matrix +import scientifik.kmath.structures.Structure2D +import kotlin.reflect.KClass + +/** + * Common implementation of [LUPDecompositionFeature] + */ +class LUPDecomposition( + val context: GenericMatrixContext>, + val lu: Structure2D, + val pivot: IntArray, + private val even: Boolean +) : LUPDecompositionFeature, DeterminantFeature { + + val elementContext get() = context.elementContext + + /** + * Returns the matrix L of the decomposition. + * + * L is a lower-triangular matrix with [Ring.one] in diagonal + */ + override val l: FeaturedMatrix = VirtualMatrix(lu.shape[0], lu.shape[1], setOf(LFeature)) { i, j -> + when { + j < i -> lu[i, j] + j == i -> elementContext.one + else -> elementContext.zero + } + } + + + /** + * Returns the matrix U of the decomposition. + * + * U is an upper-triangular matrix including the diagonal + */ + override val u: FeaturedMatrix = VirtualMatrix(lu.shape[0], lu.shape[1], setOf(UFeature)) { i, j -> + if (j >= i) lu[i, j] else elementContext.zero + } + + + /** + * Returns the P rows permutation matrix. + * + * P is a sparse matrix with exactly one element set to [Ring.one] in + * each row and each column, all other elements being set to [Ring.zero]. + */ + override val p: FeaturedMatrix = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j -> + if (j == pivot[i]) elementContext.one else elementContext.zero + } + + + /** + * Return the determinant of the matrix + * @return determinant of the matrix + */ + override val determinant: T by lazy { + with(elementContext) { + (0 until lu.shape[0]).fold(if (even) one else -one) { value, i -> value * lu[i, i] } + } + } + +} + +fun , F : Field> GenericMatrixContext.abs(value: T) = + if (value > elementContext.zero) value else with(elementContext) { -value } + + +/** + * Create a lup decomposition of generic matrix + */ +fun , F : Field> GenericMatrixContext.lup( + type: KClass, + matrix: Matrix, + checkSingular: (T) -> Boolean +): LUPDecomposition { + if (matrix.rowNum != matrix.colNum) { + error("LU decomposition supports only square matrices") + } + + val m = matrix.colNum + val pivot = IntArray(matrix.rowNum) + + //TODO just waits for KEEP-176 + BufferAccessor2D(type, matrix.rowNum, matrix.colNum).run { + elementContext.run { + + val lu = create(matrix) + + // Initialize permutation array and parity + for (row in 0 until m) { + pivot[row] = row + } + var even = true + + // Initialize permutation array and parity + for (row in 0 until m) { + pivot[row] = row + } + + // Loop over columns + for (col in 0 until m) { + + // upper + for (row in 0 until col) { + val luRow = lu.row(row) + var sum = luRow[col] + for (i in 0 until row) { + sum -= luRow[i] * lu[i, col] + } + luRow[col] = sum + } + + // lower + var max = col // permutation row + var largest = -one + for (row in col until m) { + val luRow = lu.row(row) + var sum = luRow[col] + for (i in 0 until col) { + sum -= luRow[i] * lu[i, col] + } + luRow[col] = sum + + // maintain best permutation choice + if (abs(sum) > largest) { + largest = abs(sum) + max = row + } + } + + // Singularity check + if (checkSingular(abs(lu[max, col]))) { + error("The matrix is singular") + } + + // Pivot if necessary + if (max != col) { + val luMax = lu.row(max) + val luCol = lu.row(col) + for (i in 0 until m) { + val tmp = luMax[i] + luMax[i] = luCol[i] + luCol[i] = tmp + } + val temp = pivot[max] + pivot[max] = pivot[col] + pivot[col] = temp + even = !even + } + + // Divide the lower elements by the "winning" diagonal elt. + val luDiag = lu[col, col] + for (row in col + 1 until m) { + lu[row, col] /= luDiag + } + } + + return LUPDecomposition(this@lup, lu.collect(), pivot, even) + } + } +} + +inline fun , F : Field> GenericMatrixContext.lup( + matrix: Matrix, + noinline checkSingular: (T) -> Boolean +) = lup(T::class, matrix, checkSingular) + +fun GenericMatrixContext.lup(matrix: Matrix) = lup(Double::class, matrix) { it < 1e-11 } + +fun LUPDecomposition.solve(type: KClass, matrix: Matrix): Matrix { + + if (matrix.rowNum != pivot.size) { + error("Matrix dimension mismatch. Expected ${pivot.size}, but got ${matrix.colNum}") + } + + BufferAccessor2D(type, matrix.rowNum, matrix.colNum).run { + elementContext.run { + + // Apply permutations to b + val bp = create { _, _ -> zero } + + for (row in 0 until pivot.size) { + val bpRow = bp.row(row) + val pRow = pivot[row] + for (col in 0 until matrix.colNum) { + bpRow[col] = matrix[pRow, col] + } + } + + // Solve LY = b + for (col in 0 until pivot.size) { + val bpCol = bp.row(col) + for (i in col + 1 until pivot.size) { + val bpI = bp.row(i) + val luICol = lu[i, col] + for (j in 0 until matrix.colNum) { + bpI[j] -= bpCol[j] * luICol + } + } + } + + // Solve UX = Y + for (col in pivot.size - 1 downTo 0) { + val bpCol = bp.row(col) + val luDiag = lu[col, col] + for (j in 0 until matrix.colNum) { + bpCol[j] /= luDiag + } + for (i in 0 until col) { + val bpI = bp.row(i) + val luICol = lu[i, col] + for (j in 0 until matrix.colNum) { + bpI[j] -= bpCol[j] * luICol + } + } + } + return context.produce(pivot.size, matrix.colNum) { i, j -> bp[i, j] } + } + } +} + +inline fun LUPDecomposition.solve(matrix: Matrix) = solve(T::class, matrix) + +/** + * Solve a linear equation **a*x = b** + */ +inline fun , F : Field> GenericMatrixContext.solve( + a: Matrix, + b: Matrix, + noinline checkSingular: (T) -> Boolean +): Matrix { + // Use existing decomposition if it is provided by matrix + val decomposition = a.getFeature() ?: lup(T::class, a, checkSingular) + return decomposition.solve(T::class, b) +} + +fun RealMatrixContext.solve(a: Matrix, b: Matrix) = + solve(a, b) { it < 1e-11 } + +inline fun , F : Field> GenericMatrixContext.inverse( + matrix: Matrix, + noinline checkSingular: (T) -> Boolean +) = solve(matrix, one(matrix.rowNum, matrix.colNum), checkSingular) + +fun RealMatrixContext.inverse(matrix: Matrix) = + solve(matrix, one(matrix.rowNum, matrix.colNum)) { it < 1e-11 } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgebra.kt new file mode 100644 index 000000000..abd8603f4 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/LinearAlgebra.kt @@ -0,0 +1,28 @@ +package scientifik.kmath.linear + +import scientifik.kmath.structures.Buffer +import scientifik.kmath.structures.Matrix +import scientifik.kmath.structures.VirtualBuffer + +typealias Point = Buffer + +/** + * A group of methods to resolve equation A dot X = B, where A and B are matrices or vectors + */ +interface LinearSolver { + fun solve(a: Matrix, b: Matrix): Matrix + fun solve(a: Matrix, b: Point): Point = solve(a, b.asMatrix()).asPoint() + fun inverse(a: Matrix): Matrix +} + +/** + * Convert matrix to vector if it is possible + */ +fun Matrix.asPoint(): Point = + if (this.colNum == 1) { + VirtualBuffer(rowNum) { get(it, 0) } + } else { + error("Can't convert matrix with more than one column to vector") + } + +fun Point.asMatrix() = VirtualMatrix(size, 1) { i, _ -> get(i) } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/MatrixBuilder.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/MatrixBuilder.kt new file mode 100644 index 000000000..516f65bb8 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/MatrixBuilder.kt @@ -0,0 +1,46 @@ +package scientifik.kmath.linear + +import scientifik.kmath.structures.Buffer +import scientifik.kmath.structures.BufferFactory +import scientifik.kmath.structures.Structure2D +import scientifik.kmath.structures.asBuffer + +class MatrixBuilder(val rows: Int, val columns: Int) { + operator fun invoke(vararg elements: T): FeaturedMatrix { + if (rows * columns != elements.size) error("The number of elements ${elements.size} is not equal $rows * $columns") + val buffer = elements.asBuffer() + return BufferMatrix(rows, columns, buffer) + } + + //TODO add specific matrix builder functions like diagonal, etc +} + +fun Structure2D.Companion.build(rows: Int, columns: Int): MatrixBuilder = MatrixBuilder(rows, columns) + +fun Structure2D.Companion.row(vararg values: T): FeaturedMatrix { + val buffer = values.asBuffer() + return BufferMatrix(1, values.size, buffer) +} + +inline fun Structure2D.Companion.row( + size: Int, + factory: BufferFactory = Buffer.Companion::auto, + noinline builder: (Int) -> T +): FeaturedMatrix { + val buffer = factory(size, builder) + return BufferMatrix(1, size, buffer) +} + +fun Structure2D.Companion.column(vararg values: T): FeaturedMatrix { + val buffer = values.asBuffer() + return BufferMatrix(values.size, 1, buffer) +} + +inline fun Structure2D.Companion.column( + size: Int, + factory: BufferFactory = Buffer.Companion::auto, + noinline builder: (Int) -> T +): FeaturedMatrix { + val buffer = factory(size, builder) + return BufferMatrix(size, 1, buffer) +} diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/MatrixContext.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/MatrixContext.kt new file mode 100644 index 000000000..7797fdadf --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/MatrixContext.kt @@ -0,0 +1,105 @@ +package scientifik.kmath.linear + +import scientifik.kmath.operations.Ring +import scientifik.kmath.operations.SpaceOperations +import scientifik.kmath.operations.sum +import scientifik.kmath.structures.Buffer +import scientifik.kmath.structures.BufferFactory +import scientifik.kmath.structures.Matrix +import scientifik.kmath.structures.asSequence + +/** + * Basic operations on matrices. Operates on [Matrix] + */ +interface MatrixContext : SpaceOperations> { + /** + * Produce a matrix with this context and given dimensions + */ + fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> T): Matrix + + infix fun Matrix.dot(other: Matrix): Matrix + + infix fun Matrix.dot(vector: Point): Point + + operator fun Matrix.times(value: T): Matrix + + operator fun T.times(m: Matrix): Matrix = m * this + + companion object { + /** + * Non-boxing double matrix + */ + val real = RealMatrixContext + + /** + * A structured matrix with custom buffer + */ + fun > buffered( + ring: R, + bufferFactory: BufferFactory = Buffer.Companion::boxing + ): GenericMatrixContext = + BufferMatrixContext(ring, bufferFactory) + + /** + * Automatic buffered matrix, unboxed if it is possible + */ + inline fun > auto(ring: R): GenericMatrixContext = + buffered(ring, Buffer.Companion::auto) + } +} + +interface GenericMatrixContext> : MatrixContext { + /** + * The ring context for matrix elements + */ + val elementContext: R + + /** + * Produce a point compatible with matrix space + */ + fun point(size: Int, initializer: (Int) -> T): Point + + override infix fun Matrix.dot(other: Matrix): Matrix { + //TODO add typed error + if (this.colNum != other.rowNum) error("Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})") + return produce(rowNum, other.colNum) { i, j -> + val row = rows[i] + val column = other.columns[j] + with(elementContext) { + sum(row.asSequence().zip(column.asSequence(), ::multiply)) + } + } + } + + override infix fun Matrix.dot(vector: Point): Point { + //TODO add typed error + if (this.colNum != vector.size) error("Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})") + return point(rowNum) { i -> + val row = rows[i] + with(elementContext) { + sum(row.asSequence().zip(vector.asSequence(), ::multiply)) + } + } + } + + override operator fun Matrix.unaryMinus() = + produce(rowNum, colNum) { i, j -> elementContext.run { -get(i, j) } } + + override fun add(a: Matrix, b: Matrix): Matrix { + if (a.rowNum != b.rowNum || a.colNum != b.colNum) error("Matrix operation dimension mismatch. [${a.rowNum},${a.colNum}] + [${b.rowNum},${b.colNum}]") + return produce(a.rowNum, a.colNum) { i, j -> elementContext.run { a.get(i, j) + b[i, j] } } + } + + override operator fun Matrix.minus(b: Matrix): Matrix { + if (rowNum != b.rowNum || colNum != b.colNum) error("Matrix operation dimension mismatch. [$rowNum,$colNum] - [${b.rowNum},${b.colNum}]") + return produce(rowNum, colNum) { i, j -> elementContext.run { get(i, j) + b[i, j] } } + } + + override fun multiply(a: Matrix, k: Number): Matrix = + produce(a.rowNum, a.colNum) { i, j -> elementContext.run { a.get(i, j) * k } } + + operator fun Number.times(matrix: FeaturedMatrix): Matrix = matrix * this + + override fun Matrix.times(value: T): Matrix = + produce(rowNum, colNum) { i, j -> elementContext.run { get(i, j) * value } } +} diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/MatrixFeatures.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/MatrixFeatures.kt new file mode 100644 index 000000000..de315071f --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/MatrixFeatures.kt @@ -0,0 +1,62 @@ +package scientifik.kmath.linear + +/** + * A marker interface representing some matrix feature like diagonal, sparce, zero, etc. Features used to optimize matrix + * operations performance in some cases. + */ +interface MatrixFeature + +/** + * The matrix with this feature is considered to have only diagonal non-null elements + */ +object DiagonalFeature : MatrixFeature + +/** + * Matrix with this feature has all zero elements + */ +object ZeroFeature : MatrixFeature + +/** + * Matrix with this feature have unit elements on diagonal and zero elements in all other places + */ +object UnitFeature : MatrixFeature + +/** + * Inverted matrix feature + */ +interface InverseMatrixFeature : MatrixFeature { + val inverse: FeaturedMatrix +} + +/** + * A determinant container + */ +interface DeterminantFeature : MatrixFeature { + val determinant: T +} + +@Suppress("FunctionName") +fun DeterminantFeature(determinant: T) = object: DeterminantFeature{ + override val determinant: T = determinant +} + +/** + * Lower triangular matrix + */ +object LFeature: MatrixFeature + +/** + * Upper triangular feature + */ +object UFeature: MatrixFeature + +/** + * TODO add documentation + */ +interface LUPDecompositionFeature : MatrixFeature { + val l: FeaturedMatrix + val u: FeaturedMatrix + val p: FeaturedMatrix +} + +//TODO add sparse matrix feature \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/VectorSpace.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/VectorSpace.kt new file mode 100644 index 000000000..8e14e2882 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/VectorSpace.kt @@ -0,0 +1,75 @@ +package scientifik.kmath.linear + +import scientifik.kmath.operations.RealField +import scientifik.kmath.operations.Space +import scientifik.kmath.structures.Buffer +import scientifik.kmath.structures.BufferFactory + +/** + * A linear space for vectors. + * Could be used on any point-like structure + */ +interface VectorSpace> : Space> { + + val size: Int + + val space: S + + fun produce(initializer: (Int) -> T): Point + + /** + * Produce a space-element of this vector space for expressions + */ + //fun produceElement(initializer: (Int) -> T): Vector + + override val zero: Point get() = produce { space.zero } + + override fun add(a: Point, b: Point): Point = produce { with(space) { a[it] + b[it] } } + + override fun multiply(a: Point, k: Number): Point = produce { with(space) { a[it] * k } } + + //TODO add basis + + companion object { + + private val realSpaceCache = HashMap>() + + /** + * Non-boxing double vector space + */ + fun real(size: Int): BufferVectorSpace { + return realSpaceCache.getOrPut(size) { + BufferVectorSpace( + size, + RealField, + Buffer.Companion::auto + ) + } + } + + /** + * A structured vector space with custom buffer + */ + fun > buffered( + size: Int, + space: S, + bufferFactory: BufferFactory = Buffer.Companion::boxing + ) = BufferVectorSpace(size, space, bufferFactory) + + /** + * Automatic buffered vector, unboxed if it is possible + */ + inline fun > auto(size: Int, space: S): VectorSpace = + buffered(size, space, Buffer.Companion::auto) + } +} + + +class BufferVectorSpace>( + override val size: Int, + override val space: S, + val bufferFactory: BufferFactory +) : VectorSpace { + override fun produce(initializer: (Int) -> T) = bufferFactory(size, initializer) + //override fun produceElement(initializer: (Int) -> T): Vector = BufferVector(this, produce(initializer)) +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/VirtualMatrix.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/VirtualMatrix.kt new file mode 100644 index 000000000..0806cabea --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/linear/VirtualMatrix.kt @@ -0,0 +1,59 @@ +package scientifik.kmath.linear + +import scientifik.kmath.structures.Matrix + +class VirtualMatrix( + override val rowNum: Int, + override val colNum: Int, + override val features: Set = emptySet(), + val generator: (i: Int, j: Int) -> T +) : FeaturedMatrix { + + constructor(rowNum: Int, colNum: Int, vararg features: MatrixFeature, generator: (i: Int, j: Int) -> T) : this( + rowNum, + colNum, + setOf(*features), + generator + ) + + override val shape: IntArray get() = intArrayOf(rowNum, colNum) + + override fun get(i: Int, j: Int): T = generator(i, j) + + override fun suggestFeature(vararg features: MatrixFeature) = + VirtualMatrix(rowNum, colNum, this.features + features, generator) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is FeaturedMatrix<*>) return false + + if (rowNum != other.rowNum) return false + if (colNum != other.colNum) return false + + return elements().all { (index, value) -> value == other[index] } + } + + override fun hashCode(): Int { + var result = rowNum + result = 31 * result + colNum + result = 31 * result + features.hashCode() + result = 31 * result + generator.hashCode() + return result + } + + + companion object { + /** + * Wrap a matrix adding additional features to it + */ + fun wrap(matrix: Matrix, vararg features: MatrixFeature): FeaturedMatrix { + return if (matrix is VirtualMatrix) { + VirtualMatrix(matrix.rowNum, matrix.colNum, matrix.features + features, matrix.generator) + } else { + VirtualMatrix(matrix.rowNum, matrix.colNum, matrix.features + features) { i, j -> + matrix[i, j] + } + } + } + } +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/AutoDiff.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/AutoDiff.kt new file mode 100644 index 000000000..ed77054cf --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/AutoDiff.kt @@ -0,0 +1,239 @@ +package scientifik.kmath.misc + +import scientifik.kmath.linear.Point +import scientifik.kmath.operations.ExtendedField +import scientifik.kmath.operations.Field +import scientifik.kmath.operations.sum +import scientifik.kmath.structures.asBuffer + +/* + * Implementation of backward-mode automatic differentiation. + * Initial gist by Roman Elizarov: https://gist.github.com/elizarov/1ad3a8583e88cb6ea7a0ad09bb591d3d + */ + +/** + * Differentiable variable with value and derivative of differentiation ([deriv]) result + * with respect to this variable. + */ +open class Variable(val value: T) + +class DerivationResult( + value: T, + val deriv: Map, T>, + val context: Field +) : Variable(value) { + fun deriv(variable: Variable) = deriv[variable] ?: context.zero + + /** + * compute divergence + */ + fun div() = context.run { sum(deriv.values) } + + /** + * Compute a gradient for variables in given order + */ + fun grad(vararg variables: Variable): Point = if (variables.isEmpty()) { + error("Variable order is not provided for gradient construction") + } else { + variables.map(::deriv).asBuffer() + } +} + +/** + * Runs differentiation and establishes [AutoDiffField] context inside the block of code. + * + * The partial derivatives are placed in argument `d` variable + * + * Example: + * ``` + * val x = Variable(2) // define variable(s) and their values + * val y = deriv { sqr(x) + 5 * x + 3 } // write formulate in deriv context + * assertEquals(17.0, y.x) // the value of result (y) + * assertEquals(9.0, x.d) // dy/dx + * ``` + */ +fun > F.deriv(body: AutoDiffField.() -> Variable): DerivationResult = + AutoDiffContext(this).run { + val result = body() + result.d = context.one// computing derivative w.r.t result + runBackwardPass() + DerivationResult(result.value, derivatives, this@deriv) + } + + +abstract class AutoDiffField> : Field> { + + abstract val context: F + + /** + * Performs update of derivative after the rest of the formula in the back-pass. + * + * For example, implementation of `sin` function is: + * + * ``` + * fun AD.sin(x: Variable): Variable = derive(Variable(sin(x.x)) { z -> // call derive with function result + * x.d += z.d * cos(x.x) // update derivative using chain rule and derivative of the function + * } + * ``` + */ + abstract fun derive(value: R, block: F.(R) -> Unit): R + + /** + * A variable accessing inner state of derivatives. + * Use this function in inner builders to avoid creating additional derivative bindings + */ + abstract var Variable.d: T + + abstract fun variable(value: T): Variable + + inline fun variable(block: F.() -> T) = variable(context.block()) + + // Overloads for Double constants + + operator fun Number.plus(that: Variable): Variable = + derive(variable { this@plus.toDouble() * one + that.value }) { z -> + that.d += z.d + } + + operator fun Variable.plus(b: Number): Variable = b.plus(this) + + operator fun Number.minus(that: Variable): Variable = + derive(variable { this@minus.toDouble() * one - that.value }) { z -> + that.d -= z.d + } + + operator fun Variable.minus(that: Number): Variable = + derive(variable { this@minus.value - one * that.toDouble() }) { z -> + this@minus.d += z.d + } +} + +/** + * Automatic Differentiation context class. + */ +private class AutoDiffContext>(override val context: F) : AutoDiffField() { + + // this stack contains pairs of blocks and values to apply them to + private var stack = arrayOfNulls(8) + private var sp = 0 + + internal val derivatives = HashMap, T>() + + + /** + * A variable coupled with its derivative. For internal use only + */ + private class VariableWithDeriv(x: T, var d: T) : Variable(x) + + + override fun variable(value: T): Variable = + VariableWithDeriv(value, context.zero) + + override var Variable.d: T + get() = (this as? VariableWithDeriv)?.d ?: derivatives[this] ?: context.zero + set(value) { + if (this is VariableWithDeriv) { + d = value + } else { + derivatives[this] = value + } + } + + @Suppress("UNCHECKED_CAST") + override fun derive(value: R, block: F.(R) -> Unit): R { + // save block to stack for backward pass + if (sp >= stack.size) stack = stack.copyOf(stack.size * 2) + stack[sp++] = block + stack[sp++] = value + return value + } + + @Suppress("UNCHECKED_CAST") + fun runBackwardPass() { + while (sp > 0) { + val value = stack[--sp] + val block = stack[--sp] as F.(Any?) -> Unit + context.block(value) + } + } + + // Basic math (+, -, *, /) + + + override fun add(a: Variable, b: Variable): Variable = + derive(variable { a.value + b.value }) { z -> + a.d += z.d + b.d += z.d + } + + override fun multiply(a: Variable, b: Variable): Variable = + derive(variable { a.value * b.value }) { z -> + a.d += z.d * b.value + b.d += z.d * a.value + } + + override fun divide(a: Variable, b: Variable): Variable = + derive(variable { a.value / b.value }) { z -> + a.d += z.d / b.value + b.d -= z.d * a.value / (b.value * b.value) + } + + override fun multiply(a: Variable, k: Number): Variable = + derive(variable { k.toDouble() * a.value }) { z -> + a.d += z.d * k.toDouble() + } + + override val zero: Variable get() = Variable(context.zero) + override val one: Variable get() = Variable(context.one) +} + +// Extensions for differentiation of various basic mathematical functions + +// x ^ 2 +fun > AutoDiffField.sqr(x: Variable): Variable = + derive(variable { x.value * x.value }) { z -> + x.d += z.d * 2 * x.value + } + +// x ^ 1/2 +fun > AutoDiffField.sqrt(x: Variable): Variable = + derive(variable { sqrt(x.value) }) { z -> + x.d += z.d * 0.5 / z.value + } + +// x ^ y (const) +fun > AutoDiffField.pow(x: Variable, y: Double): Variable = + derive(variable { power(x.value, y) }) { z -> + x.d += z.d * y * power(x.value, y - 1) + } + +fun > AutoDiffField.pow(x: Variable, y: Int): Variable = pow(x, y.toDouble()) + +// exp(x) +fun > AutoDiffField.exp(x: Variable): Variable = + derive(variable { exp(x.value) }) { z -> + x.d += z.d * z.value + } + +// ln(x) +fun > AutoDiffField.ln(x: Variable): Variable = derive( + variable { ln(x.value) } +) { z -> + x.d += z.d / x.value +} + +// x ^ y (any) +fun > AutoDiffField.pow(x: Variable, y: Variable): Variable = + exp(y * ln(x)) + +// sin(x) +fun > AutoDiffField.sin(x: Variable): Variable = + derive(variable { sin(x.value) }) { z -> + x.d += z.d * cos(x.value) + } + +// cos(x) +fun > AutoDiffField.cos(x: Variable): Variable = + derive(variable { cos(x.value) }) { z -> + x.d -= z.d * sin(x.value) + } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/Grids.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/Grids.kt new file mode 100644 index 000000000..90ce5da68 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/Grids.kt @@ -0,0 +1,36 @@ +package scientifik.kmath.misc + +/** + * Convert double range to sequence. + * + * If the step is positive, than the sequence starts with the lower boundary and increments by [step] until current value is lower than upper boundary. + * The boundary itself is not necessary included. + * + * If step is negative, the same goes from upper boundary downwards + */ +fun ClosedFloatingPointRange.toSequence(step: Double): Sequence = + when { + step == 0.0 -> error("Zero step in double progression") + step > 0 -> sequence { + var current = start + while (current <= endInclusive) { + yield(current) + current += step + } + } + else -> sequence { + var current = endInclusive + while (current >= start) { + yield(current) + current += step + } + } + } + +/** + * Convert double range to array of evenly spaced doubles, where the size of array equals [numPoints] + */ +fun ClosedFloatingPointRange.toGrid(numPoints: Int): DoubleArray { + if (numPoints < 2) error("Can't create generic grid with less than two points") + return DoubleArray(numPoints) { i -> start + (endInclusive - start) / (numPoints - 1) * i } +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/cumulative.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/cumulative.kt new file mode 100644 index 000000000..c3cfc448a --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/misc/cumulative.kt @@ -0,0 +1,76 @@ +package scientifik.kmath.misc + +import scientifik.kmath.operations.Space +import kotlin.jvm.JvmName + + +/** + * Generic cumulative operation on iterator + * @param T type of initial iterable + * @param R type of resulting iterable + * @param initial lazy evaluated + */ +fun Iterator.cumulative(initial: R, operation: (R, T) -> R): Iterator = object : Iterator { + var state: R = initial + override fun hasNext(): Boolean = this@cumulative.hasNext() + + override fun next(): R { + state = operation(state, this@cumulative.next()) + return state + } +} + +fun Iterable.cumulative(initial: R, operation: (R, T) -> R): Iterable = object : Iterable { + override fun iterator(): Iterator = this@cumulative.iterator().cumulative(initial, operation) +} + +fun Sequence.cumulative(initial: R, operation: (R, T) -> R): Sequence = object : Sequence { + override fun iterator(): Iterator = this@cumulative.iterator().cumulative(initial, operation) +} + +fun List.cumulative(initial: R, operation: (R, T) -> R): List = + this.iterator().cumulative(initial, operation).asSequence().toList() + +//Cumulative sum + +/** + * Cumulative sum with custom space + */ +fun Iterable.cumulativeSum(space: Space) = with(space) { + cumulative(zero) { element: T, sum: T -> sum + element } +} + +@JvmName("cumulativeSumOfDouble") +fun Iterable.cumulativeSum() = this.cumulative(0.0) { element, sum -> sum + element } + +@JvmName("cumulativeSumOfInt") +fun Iterable.cumulativeSum() = this.cumulative(0) { element, sum -> sum + element } + +@JvmName("cumulativeSumOfLong") +fun Iterable.cumulativeSum() = this.cumulative(0L) { element, sum -> sum + element } + +fun Sequence.cumulativeSum(space: Space) = with(space) { + cumulative(zero) { element: T, sum: T -> sum + element } +} + +@JvmName("cumulativeSumOfDouble") +fun Sequence.cumulativeSum() = this.cumulative(0.0) { element, sum -> sum + element } + +@JvmName("cumulativeSumOfInt") +fun Sequence.cumulativeSum() = this.cumulative(0) { element, sum -> sum + element } + +@JvmName("cumulativeSumOfLong") +fun Sequence.cumulativeSum() = this.cumulative(0L) { element, sum -> sum + element } + +fun List.cumulativeSum(space: Space) = with(space) { + cumulative(zero) { element: T, sum: T -> sum + element } +} + +@JvmName("cumulativeSumOfDouble") +fun List.cumulativeSum() = this.cumulative(0.0) { element, sum -> sum + element } + +@JvmName("cumulativeSumOfInt") +fun List.cumulativeSum() = this.cumulative(0) { element, sum -> sum + element } + +@JvmName("cumulativeSumOfLong") +fun List.cumulativeSum() = this.cumulative(0L) { element, sum -> sum + element } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Algebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Algebra.kt new file mode 100644 index 000000000..485185526 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Algebra.kt @@ -0,0 +1,95 @@ +package scientifik.kmath.operations + +@DslMarker +annotation class KMathContext + +/** + * Marker interface for any algebra + */ +interface Algebra + +inline operator fun , R> T.invoke(block: T.() -> R): R = run(block) + +/** + * Space-like operations without neutral element + */ +interface SpaceOperations : Algebra { + /** + * Addition operation for two context elements + */ + fun add(a: T, b: T): T + + /** + * Multiplication operation for context element and real number + */ + fun multiply(a: T, k: Number): T + + //Operation to be performed in this context + operator fun T.unaryMinus(): T = multiply(this, -1.0) + + operator fun T.plus(b: T): T = add(this, b) + operator fun T.minus(b: T): T = add(this, -b) + operator fun T.times(k: Number) = multiply(this, k.toDouble()) + operator fun T.div(k: Number) = multiply(this, 1.0 / k.toDouble()) + operator fun Number.times(b: T) = b * this +} + + +/** + * A general interface representing linear context of some kind. + * The context defines sum operation for its elements and multiplication by real value. + * One must note that in some cases context is a singleton class, but in some cases it + * works as a context for operations inside it. + * + * TODO do we need non-commutative context? + */ +interface Space : SpaceOperations { + /** + * Neutral element for sum operation + */ + val zero: T +} + +/** + * Operations on ring without multiplication neutral element + */ +interface RingOperations : SpaceOperations { + /** + * Multiplication for two field elements + */ + fun multiply(a: T, b: T): T + + operator fun T.times(b: T): T = multiply(this, b) +} + +/** + * The same as {@link Space} but with additional multiplication operation + */ +interface Ring : Space, RingOperations { + /** + * neutral operation for multiplication + */ + val one: T + +// operator fun T.plus(b: Number) = this.plus(b * one) +// operator fun Number.plus(b: T) = b + this +// +// operator fun T.minus(b: Number) = this.minus(b * one) +// operator fun Number.minus(b: T) = -b + this +} + +/** + * All ring operations but without neutral elements + */ +interface FieldOperations : RingOperations { + fun divide(a: T, b: T): T + + operator fun T.div(b: T): T = divide(this, b) +} + +/** + * Four operations algebra + */ +interface Field : Ring, FieldOperations { + operator fun Number.div(b: T) = this * divide(one, b) +} diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/AlgebraElements.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/AlgebraElements.kt new file mode 100644 index 000000000..093021ae3 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/AlgebraElements.kt @@ -0,0 +1,48 @@ +package scientifik.kmath.operations + +/** + * The generic mathematics elements which is able to store its context + * @param T the type of space operation results + * @param I self type of the element. Needed for static type checking + * @param C the type of mathematical context for this element + */ +interface MathElement { + /** + * The context this element belongs to + */ + val context: C +} + +interface MathWrapper { + fun unwrap(): T + fun T.wrap(): I +} + +/** + * The element of linear context + * @param T the type of space operation results + * @param I self type of the element. Needed for static type checking + * @param S the type of space + */ +interface SpaceElement, S : Space> : MathElement, MathWrapper { + + operator fun plus(b: T) = context.add(unwrap(), b).wrap() + operator fun minus(b: T) = context.add(unwrap(), context.multiply(b, -1.0)).wrap() + operator fun times(k: Number) = context.multiply(unwrap(), k.toDouble()).wrap() + operator fun div(k: Number) = context.multiply(unwrap(), 1.0 / k.toDouble()).wrap() +} + +/** + * Ring element + */ +interface RingElement, R : Ring> : SpaceElement { + operator fun times(b: T) = context.multiply(unwrap(), b).wrap() +} + +/** + * Field element + */ +interface FieldElement, F : Field> : RingElement { + override val context: F + operator fun div(b: T) = context.divide(unwrap(), b).wrap() +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/AlgebraExtensions.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/AlgebraExtensions.kt new file mode 100644 index 000000000..bfb4199a3 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/AlgebraExtensions.kt @@ -0,0 +1,15 @@ +package scientifik.kmath.operations + +fun Space.sum(data: Iterable): T = data.fold(zero) { left, right -> add(left, right) } +fun Space.sum(data: Sequence): T = data.fold(zero) { left, right -> add(left, right) } + +fun > Iterable.sumWith(space: S): T = space.sum(this) + +//TODO optimized power operation +fun RingOperations.power(arg: T, power: Int): T { + var res = arg + repeat(power - 1) { + res *= arg + } + return res +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/BigInt.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/BigInt.kt new file mode 100644 index 000000000..5e7d49b1c --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/BigInt.kt @@ -0,0 +1,500 @@ +package scientifik.kmath.operations + +import scientifik.kmath.operations.BigInt.Companion.BASE +import scientifik.kmath.operations.BigInt.Companion.BASE_SIZE +import scientifik.kmath.structures.* +import kotlin.math.log2 +import kotlin.math.max +import kotlin.math.min +import kotlin.math.sign + + +typealias Magnitude = UIntArray +typealias TBase = ULong + +/** + * Kotlin Multiplatform implementation of Big Integer numbers (KBigInteger). + * + * @author Robert Drynkin (https://github.com/robdrynkin) and Peter Klimai (https://github.com/pklimai) + */ +object BigIntField : Field { + override val zero: BigInt = BigInt.ZERO + override val one: BigInt = BigInt.ONE + + override fun add(a: BigInt, b: BigInt): BigInt = a.plus(b) + + override fun multiply(a: BigInt, k: Number): BigInt = a.times(k.toLong()) + + override fun multiply(a: BigInt, b: BigInt): BigInt = a.times(b) + + operator fun String.unaryPlus(): BigInt = this.parseBigInteger() ?: error("Can't parse $this as big integer") + + operator fun String.unaryMinus(): BigInt = + -(this.parseBigInteger() ?: error("Can't parse $this as big integer")) + + override fun divide(a: BigInt, b: BigInt): BigInt = a.div(b) +} + +class BigInt internal constructor( + private val sign: Byte, + private val magnitude: Magnitude +) : Comparable { + + override fun compareTo(other: BigInt): Int { + return when { + (this.sign == 0.toByte()) and (other.sign == 0.toByte()) -> 0 + this.sign < other.sign -> -1 + this.sign > other.sign -> 1 + else -> this.sign * compareMagnitudes(this.magnitude, other.magnitude) + } + } + + override fun equals(other: Any?): Boolean { + if (other is BigInt) { + return this.compareTo(other) == 0 + } else error("Can't compare KBigInteger to a different type") + } + + override fun hashCode(): Int { + return magnitude.hashCode() + this.sign + } + + fun abs(): BigInt = if (sign == 0.toByte()) this else BigInt(1, magnitude) + + operator fun unaryMinus(): BigInt { + return if (this.sign == 0.toByte()) this else BigInt((-this.sign).toByte(), this.magnitude) + } + + operator fun plus(b: BigInt): BigInt { + return when { + b.sign == 0.toByte() -> this + this.sign == 0.toByte() -> b + this == -b -> ZERO + this.sign == b.sign -> BigInt(this.sign, addMagnitudes(this.magnitude, b.magnitude)) + else -> { + val comp: Int = compareMagnitudes(this.magnitude, b.magnitude) + + if (comp == 1) { + BigInt(this.sign, subtractMagnitudes(this.magnitude, b.magnitude)) + } else { + BigInt((-this.sign).toByte(), subtractMagnitudes(b.magnitude, this.magnitude)) + } + } + } + } + + operator fun minus(b: BigInt): BigInt { + return this + (-b) + } + + operator fun times(b: BigInt): BigInt { + return when { + this.sign == 0.toByte() -> ZERO + b.sign == 0.toByte() -> ZERO +// TODO: Karatsuba + else -> BigInt((this.sign * b.sign).toByte(), multiplyMagnitudes(this.magnitude, b.magnitude)) + } + } + + operator fun times(other: UInt): BigInt { + return when { + this.sign == 0.toByte() -> ZERO + other == 0U -> ZERO + else -> BigInt(this.sign, multiplyMagnitudeByUInt(this.magnitude, other)) + } + } + + operator fun times(other: Int): BigInt { + return if (other > 0) + this * kotlin.math.abs(other).toUInt() + else + -this * kotlin.math.abs(other).toUInt() + } + + operator fun div(other: UInt): BigInt { + return BigInt(this.sign, divideMagnitudeByUInt(this.magnitude, other)) + } + + operator fun div(other: Int): BigInt { + return BigInt( + (this.sign * other.sign).toByte(), + divideMagnitudeByUInt(this.magnitude, kotlin.math.abs(other).toUInt()) + ) + } + + private fun division(other: BigInt): Pair { + // Long division algorithm: + // https://en.wikipedia.org/wiki/Division_algorithm#Integer_division_(unsigned)_with_remainder + // TODO: Implement more effective algorithm + var q: BigInt = ZERO + var r: BigInt = ZERO + + val bitSize = + (BASE_SIZE * (this.magnitude.size - 1) + log2(this.magnitude.lastOrNull()?.toFloat() ?: 0f + 1)).toInt() + for (i in bitSize downTo 0) { + r = r shl 1 + r = r or ((abs(this) shr i) and ONE) + if (r >= abs(other)) { + r -= abs(other) + q += (ONE shl i) + } + } + + return Pair(BigInt((this.sign * other.sign).toByte(), q.magnitude), r) + } + + operator fun div(other: BigInt): BigInt { + return this.division(other).first + } + + infix fun shl(i: Int): BigInt { + if (this == ZERO) return ZERO + if (i == 0) return this + + val fullShifts = i / BASE_SIZE + 1 + val relShift = i % BASE_SIZE + val shiftLeft = { x: UInt -> if (relShift >= 32) 0U else x shl relShift } + val shiftRight = { x: UInt -> if (BASE_SIZE - relShift >= 32) 0U else x shr (BASE_SIZE - relShift) } + + val newMagnitude: Magnitude = Magnitude(this.magnitude.size + fullShifts) + + for (j in this.magnitude.indices) { + newMagnitude[j + fullShifts - 1] = shiftLeft(this.magnitude[j]) + if (j != 0) { + newMagnitude[j + fullShifts - 1] = newMagnitude[j + fullShifts - 1] or shiftRight(this.magnitude[j - 1]) + } + } + + newMagnitude[this.magnitude.size + fullShifts - 1] = shiftRight(this.magnitude.last()) + + return BigInt(this.sign, stripLeadingZeros(newMagnitude)) + } + + infix fun shr(i: Int): BigInt { + if (this == ZERO) return ZERO + if (i == 0) return this + + val fullShifts = i / BASE_SIZE + val relShift = i % BASE_SIZE + val shiftRight = { x: UInt -> if (relShift >= 32) 0U else x shr relShift } + val shiftLeft = { x: UInt -> if (BASE_SIZE - relShift >= 32) 0U else x shl (BASE_SIZE - relShift) } + if (this.magnitude.size - fullShifts <= 0) { + return ZERO + } + val newMagnitude: Magnitude = Magnitude(this.magnitude.size - fullShifts) + + for (j in fullShifts until this.magnitude.size) { + newMagnitude[j - fullShifts] = shiftRight(this.magnitude[j]) + if (j != this.magnitude.size - 1) { + newMagnitude[j - fullShifts] = newMagnitude[j - fullShifts] or shiftLeft(this.magnitude[j + 1]) + } + } + + return BigInt(this.sign, stripLeadingZeros(newMagnitude)) + } + + infix fun or(other: BigInt): BigInt { + if (this == ZERO) return other; + if (other == ZERO) return this; + val resSize = max(this.magnitude.size, other.magnitude.size) + val newMagnitude: Magnitude = Magnitude(resSize) + for (i in 0 until resSize) { + if (i < this.magnitude.size) { + newMagnitude[i] = newMagnitude[i] or this.magnitude[i] + } + if (i < other.magnitude.size) { + newMagnitude[i] = newMagnitude[i] or other.magnitude[i] + } + } + return BigInt(1, stripLeadingZeros(newMagnitude)) + } + + infix fun and(other: BigInt): BigInt { + if ((this == ZERO) or (other == ZERO)) return ZERO; + val resSize = min(this.magnitude.size, other.magnitude.size) + val newMagnitude: Magnitude = Magnitude(resSize) + for (i in 0 until resSize) { + newMagnitude[i] = this.magnitude[i] and other.magnitude[i] + } + return BigInt(1, stripLeadingZeros(newMagnitude)) + } + + operator fun rem(other: Int): Int { + val res = this - (this / other) * other + return if (res == ZERO) 0 else res.sign * res.magnitude[0].toInt() + } + + operator fun rem(other: BigInt): BigInt { + return this - (this / other) * other + } + + fun modPow(exponent: BigInt, m: BigInt): BigInt { + return when { + exponent == ZERO -> ONE + exponent % 2 == 1 -> (this * modPow(exponent - ONE, m)) % m + else -> { + val sqRoot = modPow(exponent / 2, m) + (sqRoot * sqRoot) % m + } + } + } + + override fun toString(): String { + if (this.sign == 0.toByte()) { + return "0x0" + } + var res: String = if (this.sign == (-1).toByte()) "-0x" else "0x" + var numberStarted = false + + for (i in this.magnitude.size - 1 downTo 0) { + for (j in BASE_SIZE / 4 - 1 downTo 0) { + val curByte = (this.magnitude[i] shr 4 * j) and 0xfU + if (numberStarted or (curByte != 0U)) { + numberStarted = true + res += hexMapping[curByte] + } + } + } + + return res + } + + companion object { + const val BASE = 0xffffffffUL + const val BASE_SIZE: Int = 32 + val ZERO: BigInt = BigInt(0, uintArrayOf()) + val ONE: BigInt = BigInt(1, uintArrayOf(1u)) + + private val hexMapping: HashMap = hashMapOf( + 0U to "0", 1U to "1", 2U to "2", 3U to "3", + 4U to "4", 5U to "5", 6U to "6", 7U to "7", + 8U to "8", 9U to "9", 10U to "a", 11U to "b", + 12U to "c", 13U to "d", 14U to "e", 15U to "f" + ) + + private fun compareMagnitudes(mag1: Magnitude, mag2: Magnitude): Int { + when { + mag1.size > mag2.size -> return 1 + mag1.size < mag2.size -> return -1 + else -> { + for (i in mag1.size - 1 downTo 0) { + if (mag1[i] > mag2[i]) { + return 1 + } else if (mag1[i] < mag2[i]) { + return -1 + } + } + return 0 + } + } + } + + private fun addMagnitudes(mag1: Magnitude, mag2: Magnitude): Magnitude { + val resultLength: Int = max(mag1.size, mag2.size) + 1 + val result = Magnitude(resultLength) + var carry: TBase = 0UL + + for (i in 0 until resultLength - 1) { + val res = when { + i >= mag1.size -> mag2[i].toULong() + carry + i >= mag2.size -> mag1[i].toULong() + carry + else -> mag1[i].toULong() + mag2[i].toULong() + carry + } + result[i] = (res and BASE).toUInt() + carry = (res shr BASE_SIZE) + } + result[resultLength - 1] = carry.toUInt() + return stripLeadingZeros(result) + } + + private fun subtractMagnitudes(mag1: Magnitude, mag2: Magnitude): Magnitude { + val resultLength: Int = mag1.size + val result = Magnitude(resultLength) + var carry = 0L + + for (i in 0 until resultLength) { + var res: Long = + if (i < mag2.size) mag1[i].toLong() - mag2[i].toLong() - carry + else mag1[i].toLong() - carry + + carry = if (res < 0) 1 else 0 + res += carry * (BASE + 1UL).toLong() + + result[i] = res.toUInt() + } + + return stripLeadingZeros(result) + } + + private fun multiplyMagnitudeByUInt(mag: Magnitude, x: UInt): Magnitude { + val resultLength: Int = mag.size + 1 + val result = Magnitude(resultLength) + var carry: ULong = 0UL + + for (i in mag.indices) { + val cur: ULong = carry + mag[i].toULong() * x.toULong() + result[i] = (cur and BASE.toULong()).toUInt() + carry = cur shr BASE_SIZE + } + result[resultLength - 1] = (carry and BASE).toUInt() + + return stripLeadingZeros(result) + } + + private fun multiplyMagnitudes(mag1: Magnitude, mag2: Magnitude): Magnitude { + val resultLength: Int = mag1.size + mag2.size + val result = Magnitude(resultLength) + + for (i in mag1.indices) { + var carry: ULong = 0UL + for (j in mag2.indices) { + val cur: ULong = result[i + j].toULong() + mag1[i].toULong() * mag2[j].toULong() + carry + result[i + j] = (cur and BASE.toULong()).toUInt() + carry = cur shr BASE_SIZE + } + result[i + mag2.size] = (carry and BASE).toUInt() + } + + return stripLeadingZeros(result) + } + + private fun divideMagnitudeByUInt(mag: Magnitude, x: UInt): Magnitude { + val resultLength: Int = mag.size + val result = Magnitude(resultLength) + var carry: ULong = 0UL + + for (i in mag.size - 1 downTo 0) { + val cur: ULong = mag[i].toULong() + (carry shl BASE_SIZE) + result[i] = (cur / x).toUInt() + carry = cur % x + } + return stripLeadingZeros(result) + } + + } + +} + + +private fun stripLeadingZeros(mag: Magnitude): Magnitude { + if (mag.isEmpty() || mag.last() != 0U) { + return mag + } + var resSize: Int = mag.size - 1 + while (mag[resSize] == 0U) { + if (resSize == 0) + break + resSize -= 1 + } + return mag.sliceArray(IntRange(0, resSize)) +} + +fun abs(x: BigInt): BigInt = x.abs() + +/** + * Convert this [Int] to [BigInt] + */ +fun Int.toBigInt() = BigInt(sign.toByte(), uintArrayOf(kotlin.math.abs(this).toUInt())) + +/** + * Convert this [Long] to [BigInt] + */ +fun Long.toBigInt() = BigInt( + sign.toByte(), stripLeadingZeros( + uintArrayOf( + (kotlin.math.abs(this).toULong() and BASE).toUInt(), + ((kotlin.math.abs(this).toULong() shr BASE_SIZE) and BASE).toUInt() + ) + ) +) + +/** + * Convert UInt to [BigInt] + */ +fun UInt.toBigInt() = BigInt(1, uintArrayOf(this)) + +/** + * Convert ULong to [BigInt] + */ +fun ULong.toBigInt() = BigInt( + 1, + stripLeadingZeros( + uintArrayOf( + (this and BigInt.BASE).toUInt(), + ((this shr BigInt.BASE_SIZE) and BigInt.BASE).toUInt() + ) + ) +) + +/** + * Create a [BigInt] with this array of magnitudes with protective copy + */ +fun UIntArray.toBigInt(sign: Byte): BigInt { + if (sign == 0.toByte() && isNotEmpty()) error("") + return BigInt(sign, this.copyOf()) +} + +val hexChToInt = hashMapOf( + '0' to 0, '1' to 1, '2' to 2, '3' to 3, + '4' to 4, '5' to 5, '6' to 6, '7' to 7, + '8' to 8, '9' to 9, 'A' to 10, 'B' to 11, + 'C' to 12, 'D' to 13, 'E' to 14, 'F' to 15 +) + +/** + * Returns null if a valid number can not be read from a string + */ +fun String.parseBigInteger(): BigInt? { + val sign: Int + val sPositive: String + when { + this[0] == '+' -> { + sign = +1 + sPositive = this.substring(1) + } + this[0] == '-' -> { + sign = -1 + sPositive = this.substring(1) + } + else -> { + sPositive = this + sign = +1 + } + } + var res = BigInt.ZERO + var digitValue = BigInt.ONE + val sPositiveUpper = sPositive.toUpperCase() + if (sPositiveUpper.startsWith("0X")) { // hex representation + val sHex = sPositiveUpper.substring(2) + for (ch in sHex.reversed()) { + if (ch == '_') continue + res += digitValue * (hexChToInt[ch] ?: return null) + digitValue *= 16.toBigInt() + } + } else { // decimal representation + for (ch in sPositiveUpper.reversed()) { + if (ch == '_') continue + if (ch !in '0'..'9') { + return null + } + res += digitValue * (ch.toInt() - '0'.toInt()) + digitValue *= 10.toBigInt() + } + } + return res * sign +} + +inline fun Buffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): Buffer = + boxing(size, initializer) + +inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): MutableBuffer = + boxing(size, initializer) + +fun NDAlgebra.Companion.bigInt(vararg shape: Int): BoxingNDRing = + BoxingNDRing(shape, BigIntField, Buffer.Companion::bigInt) + +fun NDElement.Companion.bigInt( + vararg shape: Int, + initializer: BigIntField.(IntArray) -> BigInt +): BufferedNDRingElement = + NDAlgebra.bigInt(*shape).produce(initializer) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Complex.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Complex.kt new file mode 100644 index 000000000..6c529f55e --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/Complex.kt @@ -0,0 +1,105 @@ +package scientifik.kmath.operations + +import scientifik.kmath.structures.Buffer +import scientifik.kmath.structures.MemoryBuffer +import scientifik.kmath.structures.MutableBuffer +import scientifik.memory.MemoryReader +import scientifik.memory.MemorySpec +import scientifik.memory.MemoryWriter +import kotlin.math.* + +/** + * A field for complex numbers + */ +object ComplexField : ExtendedFieldOperations, Field { + override val zero: Complex = Complex(0.0, 0.0) + + override val one: Complex = Complex(1.0, 0.0) + + val i = Complex(0.0, 1.0) + + override fun add(a: Complex, b: Complex): Complex = Complex(a.re + b.re, a.im + b.im) + + override fun multiply(a: Complex, k: Number): Complex = Complex(a.re * k.toDouble(), a.im * k.toDouble()) + + override fun multiply(a: Complex, b: Complex): Complex = + Complex(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re) + + override fun divide(a: Complex, b: Complex): Complex { + val norm = b.re * b.re + b.im * b.im + return Complex((a.re * b.re + a.im * b.im) / norm, (a.re * b.im - a.im * b.re) / norm) + } + + override fun sin(arg: Complex): Complex = i / 2 * (exp(-i * arg) - exp(i * arg)) + + override fun cos(arg: Complex): Complex = (exp(-i * arg) + exp(i * arg)) / 2 + + override fun power(arg: Complex, pow: Number): Complex = + arg.r.pow(pow.toDouble()) * (cos(pow.toDouble() * arg.theta) + i * sin(pow.toDouble() * arg.theta)) + + override fun exp(arg: Complex): Complex = exp(arg.re) * (cos(arg.im) + i * sin(arg.im)) + + override fun ln(arg: Complex): Complex = ln(arg.r) + i * atan2(arg.im, arg.re) + + operator fun Double.plus(c: Complex) = add(this.toComplex(), c) + + operator fun Double.minus(c: Complex) = add(this.toComplex(), -c) + + operator fun Complex.plus(d: Double) = d + this + + operator fun Complex.minus(d: Double) = add(this, -d.toComplex()) + + operator fun Double.times(c: Complex) = Complex(c.re * this, c.im * this) +} + +/** + * Complex number class + */ +data class Complex(val re: Double, val im: Double) : FieldElement, Comparable { + constructor(re: Number, im: Number) : this(re.toDouble(), im.toDouble()) + + override fun unwrap(): Complex = this + + override fun Complex.wrap(): Complex = this + + override val context: ComplexField get() = ComplexField + + override fun compareTo(other: Complex): Int = r.compareTo(other.r) + + companion object : MemorySpec { + override val objectSize: Int = 16 + + override fun MemoryReader.read(offset: Int): Complex = + Complex(readDouble(offset), readDouble(offset + 8)) + + override fun MemoryWriter.write(offset: Int, value: Complex) { + writeDouble(offset, value.re) + writeDouble(offset + 8, value.im) + } + } +} + +/** + * A complex conjugate + */ +val Complex.conjugate: Complex get() = Complex(re, -im) + +/** + * Absolute value of complex number + */ +val Complex.r: Double get() = sqrt(re * re + im * im) + +/** + * An angle between vector represented by complex number and X axis + */ +val Complex.theta: Double get() = atan(im / re) + +fun Double.toComplex() = Complex(this, 0.0) + +inline fun Buffer.Companion.complex(size: Int, crossinline init: (Int) -> Complex): Buffer { + return MemoryBuffer.create(Complex, size, init) +} + +inline fun MutableBuffer.Companion.complex(size: Int, crossinline init: (Int) -> Complex): Buffer { + return MemoryBuffer.create(Complex, size, init) +} diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/NumberAlgebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/NumberAlgebra.kt new file mode 100644 index 000000000..2b6a92f14 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/NumberAlgebra.kt @@ -0,0 +1,183 @@ +package scientifik.kmath.operations + +import kotlin.math.abs +import kotlin.math.pow as kpow + +/** + * Advanced Number-like field that implements basic operations + */ +interface ExtendedFieldOperations : + FieldOperations, + TrigonometricOperations, + PowerOperations, + ExponentialOperations + +interface ExtendedField : ExtendedFieldOperations, Field + +/** + * Real field element wrapping double. + * + * TODO inline does not work due to compiler bug. Waiting for fix for KT-27586 + */ +inline class Real(val value: Double) : FieldElement { + override fun unwrap(): Double = value + + override fun Double.wrap(): Real = Real(value) + + override val context get() = RealField + + companion object +} + +/** + * A field for double without boxing. Does not produce appropriate field element + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +object RealField : ExtendedField, Norm { + override val zero: Double = 0.0 + override inline fun add(a: Double, b: Double) = a + b + override inline fun multiply(a: Double, b: Double) = a * b + override inline fun multiply(a: Double, k: Number) = a * k.toDouble() + + override val one: Double = 1.0 + override inline fun divide(a: Double, b: Double) = a / b + + override inline fun sin(arg: Double) = kotlin.math.sin(arg) + override inline fun cos(arg: Double) = kotlin.math.cos(arg) + + override inline fun power(arg: Double, pow: Number) = arg.kpow(pow.toDouble()) + + override inline fun exp(arg: Double) = kotlin.math.exp(arg) + override inline fun ln(arg: Double) = kotlin.math.ln(arg) + + override inline fun norm(arg: Double) = abs(arg) + + override inline fun Double.unaryMinus() = -this + + override inline fun Double.plus(b: Double) = this + b + + override inline fun Double.minus(b: Double) = this - b + + override inline fun Double.times(b: Double) = this * b + + override inline fun Double.div(b: Double) = this / b +} + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +object FloatField : ExtendedField, Norm { + override val zero: Float = 0f + override inline fun add(a: Float, b: Float) = a + b + override inline fun multiply(a: Float, b: Float) = a * b + override inline fun multiply(a: Float, k: Number) = a * k.toFloat() + + override val one: Float = 1f + override inline fun divide(a: Float, b: Float) = a / b + + override inline fun sin(arg: Float) = kotlin.math.sin(arg) + override inline fun cos(arg: Float) = kotlin.math.cos(arg) + + override inline fun power(arg: Float, pow: Number) = arg.pow(pow.toFloat()) + + override inline fun exp(arg: Float) = kotlin.math.exp(arg) + override inline fun ln(arg: Float) = kotlin.math.ln(arg) + + override inline fun norm(arg: Float) = abs(arg) + + override inline fun Float.unaryMinus() = -this + + override inline fun Float.plus(b: Float) = this + b + + override inline fun Float.minus(b: Float) = this - b + + override inline fun Float.times(b: Float) = this * b + + override inline fun Float.div(b: Float) = this / b +} + +/** + * A field for [Int] without boxing. Does not produce corresponding field element + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +object IntRing : Ring, Norm { + override val zero: Int = 0 + override inline fun add(a: Int, b: Int) = a + b + override inline fun multiply(a: Int, b: Int) = a * b + override inline fun multiply(a: Int, k: Number) = k.toInt() * a + override val one: Int = 1 + + override inline fun norm(arg: Int) = abs(arg) + + override inline fun Int.unaryMinus() = -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 +} + +/** + * A field for [Short] without boxing. Does not produce appropriate field element + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +object ShortRing : Ring, Norm { + override val zero: Short = 0 + override inline fun add(a: Short, b: Short) = (a + b).toShort() + override inline fun multiply(a: Short, b: Short) = (a * b).toShort() + override inline fun multiply(a: Short, k: Number) = (a * k.toShort()).toShort() + override val one: Short = 1 + + override fun norm(arg: Short): Short = if (arg > 0) arg else (-arg).toShort() + + override inline fun Short.unaryMinus() = (-this).toShort() + + override inline fun Short.plus(b: Short) = (this + b).toShort() + + override inline fun Short.minus(b: Short) = (this - b).toShort() + + override inline fun Short.times(b: Short) = (this * b).toShort() +} + +/** + * A field for [Byte] values + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +object ByteRing : Ring, Norm { + override val zero: Byte = 0 + override inline fun add(a: Byte, b: Byte) = (a + b).toByte() + override inline fun multiply(a: Byte, b: Byte) = (a * b).toByte() + override inline fun multiply(a: Byte, k: Number) = (a * k.toByte()).toByte() + override val one: Byte = 1 + + override fun norm(arg: Byte): Byte = if (arg > 0) arg else (-arg).toByte() + + override inline fun Byte.unaryMinus() = (-this).toByte() + + override inline fun Byte.plus(b: Byte) = (this + b).toByte() + + override inline fun Byte.minus(b: Byte) = (this - b).toByte() + + override inline fun Byte.times(b: Byte) = (this * b).toByte() +} + +/** + * A field for [Long] values + */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +object LongRing : Ring, Norm { + override val zero: Long = 0 + override inline fun add(a: Long, b: Long) = (a + b) + override inline fun multiply(a: Long, b: Long) = (a * b) + override inline fun multiply(a: Long, k: Number) = a * k.toLong() + override val one: Long = 1 + + override fun norm(arg: Long): Long = abs(arg) + + override inline fun Long.unaryMinus() = (-this) + + override inline fun Long.plus(b: Long) = (this + b) + + override inline fun Long.minus(b: Long) = (this - b) + + override inline fun Long.times(b: Long) = (this * b) +} diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/OptionalOperations.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/OptionalOperations.kt new file mode 100644 index 000000000..bd83932e7 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/operations/OptionalOperations.kt @@ -0,0 +1,57 @@ +package scientifik.kmath.operations + + +/* Trigonometric operations */ + +/** + * A container for trigonometric operations for specific type. Trigonometric operations are limited to fields. + * + * The operations are not exposed to class directly to avoid method bloat but instead are declared in the field. + * It also allows to override behavior for optional operations + * + */ +interface TrigonometricOperations : FieldOperations { + fun sin(arg: T): T + fun cos(arg: T): T + + fun tg(arg: T): T = sin(arg) / cos(arg) + + fun ctg(arg: T): T = cos(arg) / sin(arg) +} + +fun >> sin(arg: T): T = arg.context.sin(arg) +fun >> cos(arg: T): T = arg.context.cos(arg) +fun >> tg(arg: T): T = arg.context.tg(arg) +fun >> ctg(arg: T): T = arg.context.ctg(arg) + +/* Power and roots */ + +/** + * A context extension to include power operations like square roots, etc + */ +interface PowerOperations : Algebra { + fun power(arg: T, pow: Number): T + fun sqrt(arg: T) = power(arg, 0.5) + + infix fun T.pow(pow: Number) = power(this, pow) +} + +infix fun >> T.pow(power: Double): T = context.power(this, power) +fun >> sqrt(arg: T): T = arg pow 0.5 +fun >> sqr(arg: T): T = arg pow 2.0 + +/* Exponential */ + +interface ExponentialOperations: Algebra { + fun exp(arg: T): T + fun ln(arg: T): T +} + +fun >> exp(arg: T): T = arg.context.exp(arg) +fun >> ln(arg: T): T = arg.context.ln(arg) + +interface Norm { + fun norm(arg: T): R +} + +fun >, R> norm(arg: T): R = arg.context.norm(arg) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BoxingNDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BoxingNDField.kt new file mode 100644 index 000000000..e6d4b226d --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BoxingNDField.kt @@ -0,0 +1,82 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.Field +import scientifik.kmath.operations.FieldElement + + +class BoxingNDField>( + override val shape: IntArray, + override val elementContext: F, + val bufferFactory: BufferFactory +) : BufferedNDField { + + override val strides: Strides = DefaultStrides(shape) + + fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer = + bufferFactory(size, initializer) + + override fun check(vararg elements: NDBuffer) { + if (!elements.all { it.strides == this.strides }) error("Element strides are not the same as context strides") + } + + override val zero by lazy { produce { zero } } + override val one by lazy { produce { one } } + + override fun produce(initializer: F.(IntArray) -> T) = + BufferedNDFieldElement( + this, + buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }) + + override fun map(arg: NDBuffer, transform: F.(T) -> T): BufferedNDFieldElement { + check(arg) + return BufferedNDFieldElement( + this, + buildBuffer(arg.strides.linearSize) { offset -> elementContext.transform(arg.buffer[offset]) }) + +// val buffer = arg.buffer.transform { _, value -> elementContext.transform(value) } +// return BufferedNDFieldElement(this, buffer) + + } + + override fun mapIndexed( + arg: NDBuffer, + transform: F.(index: IntArray, T) -> T + ): BufferedNDFieldElement { + check(arg) + return BufferedNDFieldElement( + this, + buildBuffer(arg.strides.linearSize) { offset -> + elementContext.transform( + arg.strides.index(offset), + arg.buffer[offset] + ) + }) + +// val buffer = +// arg.buffer.transform { offset, value -> elementContext.transform(arg.strides.index(offset), value) } +// return BufferedNDFieldElement(this, buffer) + } + + override fun combine( + a: NDBuffer, + b: NDBuffer, + transform: F.(T, T) -> T + ): BufferedNDFieldElement { + check(a, b) + return BufferedNDFieldElement( + this, + buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) }) + } + + override fun NDBuffer.toElement(): FieldElement, *, out BufferedNDField> = + BufferedNDFieldElement(this@BoxingNDField, buffer) +} + +inline fun , R> F.nd( + noinline bufferFactory: BufferFactory, + vararg shape: Int, + action: NDField.() -> R +): R { + val ndfield: BoxingNDField = NDField.boxing(this, *shape, bufferFactory = bufferFactory) + return ndfield.action() +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BoxingNDRing.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BoxingNDRing.kt new file mode 100644 index 000000000..39fc555e8 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BoxingNDRing.kt @@ -0,0 +1,72 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.Ring +import scientifik.kmath.operations.RingElement + +class BoxingNDRing>( + override val shape: IntArray, + override val elementContext: R, + val bufferFactory: BufferFactory +) : BufferedNDRing { + + override val strides: Strides = DefaultStrides(shape) + + fun buildBuffer(size: Int, initializer: (Int) -> T): Buffer = + bufferFactory(size, initializer) + + override fun check(vararg elements: NDBuffer) { + if (!elements.all { it.strides == this.strides }) error("Element strides are not the same as context strides") + } + + override val zero by lazy { produce { zero } } + override val one by lazy { produce { one } } + + override fun produce(initializer: R.(IntArray) -> T) = + BufferedNDRingElement( + this, + buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) }) + + override fun map(arg: NDBuffer, transform: R.(T) -> T): BufferedNDRingElement { + check(arg) + return BufferedNDRingElement( + this, + buildBuffer(arg.strides.linearSize) { offset -> elementContext.transform(arg.buffer[offset]) }) + +// val buffer = arg.buffer.transform { _, value -> elementContext.transform(value) } +// return BufferedNDFieldElement(this, buffer) + + } + + override fun mapIndexed( + arg: NDBuffer, + transform: R.(index: IntArray, T) -> T + ): BufferedNDRingElement { + check(arg) + return BufferedNDRingElement( + this, + buildBuffer(arg.strides.linearSize) { offset -> + elementContext.transform( + arg.strides.index(offset), + arg.buffer[offset] + ) + }) + +// val buffer = +// arg.buffer.transform { offset, value -> elementContext.transform(arg.strides.index(offset), value) } +// return BufferedNDFieldElement(this, buffer) + } + + override fun combine( + a: NDBuffer, + b: NDBuffer, + transform: R.(T, T) -> T + ): BufferedNDRingElement { + check(a, b) + return BufferedNDRingElement( + this, + buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) }) + } + + override fun NDBuffer.toElement(): RingElement, *, out BufferedNDRing> = + BufferedNDRingElement(this@BoxingNDRing, buffer) +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferAccessor2D.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferAccessor2D.kt new file mode 100644 index 000000000..b14da5d99 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferAccessor2D.kt @@ -0,0 +1,45 @@ +package scientifik.kmath.structures + +import kotlin.reflect.KClass + +/** + * A context that allows to operate on a [MutableBuffer] as on 2d array + */ +class BufferAccessor2D(val type: KClass, val rowNum: Int, val colNum: Int) { + + operator fun Buffer.get(i: Int, j: Int) = get(i + colNum * j) + + operator fun MutableBuffer.set(i: Int, j: Int, value: T) { + set(i + colNum * j, value) + } + + inline fun create(init: (i: Int, j: Int) -> T) = + MutableBuffer.auto(type, rowNum * colNum) { offset -> init(offset / colNum, offset % colNum) } + + fun create(mat: Structure2D) = create { i, j -> mat[i, j] } + + //TODO optimize wrapper + fun MutableBuffer.collect(): Structure2D = + NDStructure.auto(type, rowNum, colNum) { (i, j) -> get(i, j) }.as2D() + + + inner class Row(val buffer: MutableBuffer, val rowIndex: Int) : MutableBuffer { + override val size: Int get() = colNum + + override fun get(index: Int): T = buffer[rowIndex, index] + + override fun set(index: Int, value: T) { + buffer[rowIndex, index] = value + } + + override fun copy(): MutableBuffer = MutableBuffer.auto(type, colNum) { get(it) } + + override fun iterator(): Iterator = (0 until colNum).map(::get).iterator() + + } + + /** + * Get row + */ + fun MutableBuffer.row(i: Int) = Row(this, i) +} diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferedNDAlgebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferedNDAlgebra.kt new file mode 100644 index 000000000..9742f3662 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferedNDAlgebra.kt @@ -0,0 +1,43 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.* + +interface BufferedNDAlgebra: NDAlgebra>{ + val strides: Strides + + override fun check(vararg elements: NDBuffer) { + if (!elements.all { it.strides == this.strides }) error("Strides mismatch") + } + + /** + * Convert any [NDStructure] to buffered structure using strides from this context. + * If the structure is already [NDBuffer], conversion is free. If not, it could be expensive because iteration over indexes + * + * If the argument is [NDBuffer] with different strides structure, the new element will be produced. + */ + fun NDStructure.toBuffer(): NDBuffer { + return if (this is NDBuffer && this.strides == this@BufferedNDAlgebra.strides) { + this + } else { + produce { index -> get(index) } + } + } + + /** + * Convert a buffer to element of this algebra + */ + fun NDBuffer.toElement(): MathElement> +} + + +interface BufferedNDSpace> : NDSpace>, BufferedNDAlgebra { + override fun NDBuffer.toElement(): SpaceElement, *, out BufferedNDSpace> +} + +interface BufferedNDRing> : NDRing>, BufferedNDSpace { + override fun NDBuffer.toElement(): RingElement, *, out BufferedNDRing> +} + +interface BufferedNDField> : NDField>, BufferedNDRing { + override fun NDBuffer.toElement(): FieldElement, *, out BufferedNDField> +} diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferedNDElement.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferedNDElement.kt new file mode 100644 index 000000000..be80f66bf --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferedNDElement.kt @@ -0,0 +1,88 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.* + +/** + * Base class for an element with context, containing strides + */ +abstract class BufferedNDElement : NDBuffer(), NDElement> { + abstract override val context: BufferedNDAlgebra + + override val strides get() = context.strides + + override val shape: IntArray get() = context.shape +} + +class BufferedNDSpaceElement>( + override val context: BufferedNDSpace, + override val buffer: Buffer +) : BufferedNDElement(), SpaceElement, BufferedNDSpaceElement, BufferedNDSpace> { + + override fun unwrap(): NDBuffer = this + + override fun NDBuffer.wrap(): BufferedNDSpaceElement { + context.check(this) + return BufferedNDSpaceElement(context, buffer) + } +} + +class BufferedNDRingElement>( + override val context: BufferedNDRing, + override val buffer: Buffer +) : BufferedNDElement(), RingElement, BufferedNDRingElement, BufferedNDRing> { + + override fun unwrap(): NDBuffer = this + + override fun NDBuffer.wrap(): BufferedNDRingElement { + context.check(this) + return BufferedNDRingElement(context, buffer) + } +} + +class BufferedNDFieldElement>( + override val context: BufferedNDField, + override val buffer: Buffer +) : BufferedNDElement(), FieldElement, BufferedNDFieldElement, BufferedNDField> { + + override fun unwrap(): NDBuffer = this + + override fun NDBuffer.wrap(): BufferedNDFieldElement { + context.check(this) + return BufferedNDFieldElement(context, buffer) + } +} + + +/** + * Element by element application of any operation on elements to the whole array. Just like in numpy + */ +operator fun > Function1.invoke(ndElement: BufferedNDElement) = + ndElement.context.run { map(ndElement) { invoke(it) }.toElement() } + +/* plus and minus */ + +/** + * Summation operation for [BufferedNDElement] and single element + */ +operator fun > BufferedNDElement.plus(arg: T) = + context.map(this) { it + arg }.wrap() + +/** + * Subtraction operation between [BufferedNDElement] and single element + */ +operator fun > BufferedNDElement.minus(arg: T) = + context.map(this) { it - arg }.wrap() + +/* prod and div */ + +/** + * Product operation for [BufferedNDElement] and single element + */ +operator fun > BufferedNDElement.times(arg: T) = + context.map(this) { it * arg }.wrap() + +/** + * Division operation between [BufferedNDElement] and single element + */ +operator fun > BufferedNDElement.div(arg: T) = + context.map(this) { it / arg }.wrap() \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt new file mode 100644 index 000000000..613a0d7ca --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Buffers.kt @@ -0,0 +1,260 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.Complex +import scientifik.kmath.operations.complex +import kotlin.reflect.KClass + + +typealias BufferFactory = (Int, (Int) -> T) -> Buffer +typealias MutableBufferFactory = (Int, (Int) -> T) -> MutableBuffer + + +/** + * A generic random access structure for both primitives and objects + */ +interface Buffer { + + /** + * The size of the buffer + */ + val size: Int + + /** + * Get element at given index + */ + operator fun get(index: Int): T + + /** + * Iterate over all elements + */ + operator fun iterator(): Iterator + + /** + * Check content eqiality with another buffer + */ + fun contentEquals(other: Buffer<*>): Boolean = + asSequence().mapIndexed { index, value -> value == other[index] }.all { it } + + companion object { + + inline fun real(size: Int, initializer: (Int) -> Double): DoubleBuffer { + val array = DoubleArray(size) { initializer(it) } + return DoubleBuffer(array) + } + + /** + * Create a boxing buffer of given type + */ + inline fun boxing(size: Int, initializer: (Int) -> T): Buffer = ListBuffer(List(size, initializer)) + + @Suppress("UNCHECKED_CAST") + inline fun auto(type: KClass, size: Int, crossinline initializer: (Int) -> T): Buffer { + //TODO add resolution based on Annotation or companion resolution + return when (type) { + Double::class -> DoubleBuffer(DoubleArray(size) { initializer(it) as Double }) as Buffer + Short::class -> ShortBuffer(ShortArray(size) { initializer(it) as Short }) as Buffer + Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as Buffer + Long::class -> LongBuffer(LongArray(size) { initializer(it) as Long }) as Buffer + Complex::class -> complex(size) { initializer(it) as Complex } as Buffer + else -> boxing(size, initializer) + } + } + + /** + * Create most appropriate immutable buffer for given type avoiding boxing wherever possible + */ + @Suppress("UNCHECKED_CAST") + inline fun auto(size: Int, crossinline initializer: (Int) -> T): Buffer = + auto(T::class, size, initializer) + } +} + +fun Buffer.asSequence(): Sequence = Sequence(::iterator) + +fun Buffer.asIterable(): Iterable = Iterable(::iterator) + +val Buffer<*>.indices: IntRange get() = IntRange(0, size - 1) + +interface MutableBuffer : Buffer { + operator fun set(index: Int, value: T) + + /** + * A shallow copy of the buffer + */ + fun copy(): MutableBuffer + + companion object { + /** + * Create a boxing mutable buffer of given type + */ + inline fun boxing(size: Int, initializer: (Int) -> T): MutableBuffer = + MutableListBuffer(MutableList(size, initializer)) + + @Suppress("UNCHECKED_CAST") + inline fun auto(type: KClass, size: Int, initializer: (Int) -> T): MutableBuffer { + return when (type) { + Double::class -> DoubleBuffer(DoubleArray(size) { initializer(it) as Double }) as MutableBuffer + Short::class -> ShortBuffer(ShortArray(size) { initializer(it) as Short }) as MutableBuffer + Int::class -> IntBuffer(IntArray(size) { initializer(it) as Int }) as MutableBuffer + Long::class -> LongBuffer(LongArray(size) { initializer(it) as Long }) as MutableBuffer + else -> boxing(size, initializer) + } + } + + /** + * Create most appropriate mutable buffer for given type avoiding boxing wherever possible + */ + @Suppress("UNCHECKED_CAST") + inline fun auto(size: Int, initializer: (Int) -> T): MutableBuffer = + auto(T::class, size, initializer) + + val real: MutableBufferFactory = { size: Int, initializer: (Int) -> Double -> + DoubleBuffer(DoubleArray(size) { initializer(it) }) + } + } +} + + +inline class ListBuffer(val list: List) : Buffer { + + override val size: Int + get() = list.size + + override fun get(index: Int): T = list[index] + + override fun iterator(): Iterator = list.iterator() +} + +fun List.asBuffer() = ListBuffer(this) + +@Suppress("FunctionName") +inline fun ListBuffer(size: Int, init: (Int) -> T) = List(size, init).asBuffer() + +inline class MutableListBuffer(val list: MutableList) : MutableBuffer { + + override val size: Int + get() = list.size + + override fun get(index: Int): T = list[index] + + override fun set(index: Int, value: T) { + list[index] = value + } + + override fun iterator(): Iterator = list.iterator() + override fun copy(): MutableBuffer = MutableListBuffer(ArrayList(list)) +} + +class ArrayBuffer(private val array: Array) : MutableBuffer { + //Can't inline because array is invariant + override val size: Int + get() = array.size + + override fun get(index: Int): T = array[index] + + override fun set(index: Int, value: T) { + array[index] = value + } + + override fun iterator(): Iterator = array.iterator() + + override fun copy(): MutableBuffer = ArrayBuffer(array.copyOf()) +} + +fun Array.asBuffer(): ArrayBuffer = ArrayBuffer(this) + +inline class ShortBuffer(val array: ShortArray) : MutableBuffer { + override val size: Int get() = array.size + + override fun get(index: Int): Short = array[index] + + override fun set(index: Int, value: Short) { + array[index] = value + } + + override fun iterator() = array.iterator() + + override fun copy(): MutableBuffer = ShortBuffer(array.copyOf()) + +} + +fun ShortArray.asBuffer() = ShortBuffer(this) + +inline class IntBuffer(val array: IntArray) : MutableBuffer { + override val size: Int get() = array.size + + override fun get(index: Int): Int = array[index] + + override fun set(index: Int, value: Int) { + array[index] = value + } + + override fun iterator() = array.iterator() + + override fun copy(): MutableBuffer = IntBuffer(array.copyOf()) + +} + +fun IntArray.asBuffer() = IntBuffer(this) + +inline class LongBuffer(val array: LongArray) : MutableBuffer { + override val size: Int get() = array.size + + override fun get(index: Int): Long = array[index] + + override fun set(index: Int, value: Long) { + array[index] = value + } + + override fun iterator() = array.iterator() + + override fun copy(): MutableBuffer = LongBuffer(array.copyOf()) + +} + +fun LongArray.asBuffer() = LongBuffer(this) + +inline class ReadOnlyBuffer(val buffer: MutableBuffer) : Buffer { + override val size: Int get() = buffer.size + + override fun get(index: Int): T = buffer.get(index) + + override fun iterator() = buffer.iterator() +} + +/** + * A buffer with content calculated on-demand. The calculated contect is not stored, so it is recalculated on each call. + * Useful when one needs single element from the buffer. + */ +class VirtualBuffer(override val size: Int, private val generator: (Int) -> T) : Buffer { + override fun get(index: Int): T { + if (index < 0 || index >= size) throw IndexOutOfBoundsException("Expected index from 0 to ${size - 1}, but found $index") + return generator(index) + } + + override fun iterator(): Iterator = (0 until size).asSequence().map(generator).iterator() + + override fun contentEquals(other: Buffer<*>): Boolean { + return if (other is VirtualBuffer) { + this.size == other.size && this.generator == other.generator + } else { + super.contentEquals(other) + } + } +} + +/** + * Convert this buffer to read-only buffer + */ +fun Buffer.asReadOnly(): Buffer = if (this is MutableBuffer) { + ReadOnlyBuffer(this) +} else { + this +} + +/** + * Typealias for buffer transformations + */ +typealias BufferTransform = (Buffer) -> Buffer + +typealias SuspendBufferTransform = suspend (Buffer) -> Buffer \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ComplexNDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ComplexNDField.kt new file mode 100644 index 000000000..a79366a99 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ComplexNDField.kt @@ -0,0 +1,144 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.Complex +import scientifik.kmath.operations.ComplexField +import scientifik.kmath.operations.FieldElement +import scientifik.kmath.operations.complex + +typealias ComplexNDElement = BufferedNDFieldElement + +/** + * An optimized nd-field for complex numbers + */ +class ComplexNDField(override val shape: IntArray) : + BufferedNDField, + ExtendedNDField> { + + override val strides: Strides = DefaultStrides(shape) + + override val elementContext: ComplexField get() = ComplexField + override val zero by lazy { produce { zero } } + override val one by lazy { produce { one } } + + inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Complex): Buffer = + Buffer.complex(size) { initializer(it) } + + /** + * Inline transform an NDStructure to another structure + */ + override fun map( + arg: NDBuffer, + transform: ComplexField.(Complex) -> Complex + ): ComplexNDElement { + check(arg) + val array = buildBuffer(arg.strides.linearSize) { offset -> ComplexField.transform(arg.buffer[offset]) } + return BufferedNDFieldElement(this, array) + } + + override fun produce(initializer: ComplexField.(IntArray) -> Complex): ComplexNDElement { + val array = buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) } + return BufferedNDFieldElement(this, array) + } + + override fun mapIndexed( + arg: NDBuffer, + transform: ComplexField.(index: IntArray, Complex) -> Complex + ): ComplexNDElement { + check(arg) + return BufferedNDFieldElement( + this, + buildBuffer(arg.strides.linearSize) { offset -> + elementContext.transform( + arg.strides.index(offset), + arg.buffer[offset] + ) + }) + } + + override fun combine( + a: NDBuffer, + b: NDBuffer, + transform: ComplexField.(Complex, Complex) -> Complex + ): ComplexNDElement { + check(a, b) + return BufferedNDFieldElement( + this, + buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) }) + } + + override fun NDBuffer.toElement(): FieldElement, *, out BufferedNDField> = + BufferedNDFieldElement(this@ComplexNDField, buffer) + + override fun power(arg: NDBuffer, pow: Number) = map(arg) { power(it, pow) } + + override fun exp(arg: NDBuffer) = map(arg) { exp(it) } + + override fun ln(arg: NDBuffer) = map(arg) { ln(it) } + + override fun sin(arg: NDBuffer) = map(arg) { sin(it) } + + override fun cos(arg: NDBuffer) = map(arg) { cos(it) } + +} + + +/** + * Fast element production using function inlining + */ +inline fun BufferedNDField.produceInline(crossinline initializer: ComplexField.(Int) -> Complex): ComplexNDElement { + val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.initializer(offset) } + return BufferedNDFieldElement(this, buffer) +} + +/** + * Map one [ComplexNDElement] using function with indexes + */ +inline fun ComplexNDElement.mapIndexed(crossinline transform: ComplexField.(index: IntArray, Complex) -> Complex) = + context.produceInline { offset -> transform(strides.index(offset), buffer[offset]) } + +/** + * Map one [ComplexNDElement] using function without indexes + */ +inline fun ComplexNDElement.map(crossinline transform: ComplexField.(Complex) -> Complex): ComplexNDElement { + val buffer = Buffer.complex(strides.linearSize) { offset -> ComplexField.transform(buffer[offset]) } + return BufferedNDFieldElement(context, buffer) +} + +/** + * Element by element application of any operation on elements to the whole array. Just like in numpy + */ +operator fun Function1.invoke(ndElement: ComplexNDElement) = + ndElement.map { this@invoke(it) } + + +/* plus and minus */ + +/** + * Summation operation for [BufferedNDElement] and single element + */ +operator fun ComplexNDElement.plus(arg: Complex) = + map { it + arg } + +/** + * Subtraction operation between [BufferedNDElement] and single element + */ +operator fun ComplexNDElement.minus(arg: Complex) = + map { it - arg } + +operator fun ComplexNDElement.plus(arg: Double) = + map { it + arg } + +operator fun ComplexNDElement.minus(arg: Double) = + map { it - arg } + +fun NDField.Companion.complex(vararg shape: Int): ComplexNDField = ComplexNDField(shape) + +fun NDElement.Companion.complex(vararg shape: Int, initializer: ComplexField.(IntArray) -> Complex): ComplexNDElement = + NDField.complex(*shape).produce(initializer) + +/** + * Produce a context for n-dimensional operations inside this real field + */ +inline fun ComplexField.nd(vararg shape: Int, action: ComplexNDField.() -> R): R { + return NDField.complex(*shape).run(action) +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/DoubleBuffer.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/DoubleBuffer.kt new file mode 100644 index 000000000..c0b7f713b --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/DoubleBuffer.kt @@ -0,0 +1,34 @@ +package scientifik.kmath.structures + +inline class DoubleBuffer(val array: DoubleArray) : MutableBuffer { + override val size: Int get() = array.size + + override fun get(index: Int): Double = array[index] + + override fun set(index: Int, value: Double) { + array[index] = value + } + + override fun iterator() = array.iterator() + + override fun copy(): MutableBuffer = + DoubleBuffer(array.copyOf()) +} + +@Suppress("FunctionName") +inline fun DoubleBuffer(size: Int, init: (Int) -> Double): DoubleBuffer = DoubleBuffer(DoubleArray(size) { init(it) }) + +@Suppress("FunctionName") +fun DoubleBuffer(vararg doubles: Double): DoubleBuffer = DoubleBuffer(doubles) + +/** + * Transform buffer of doubles into array for high performance operations + */ +val MutableBuffer.array: DoubleArray + get() = if (this is DoubleBuffer) { + array + } else { + DoubleArray(size) { get(it) } + } + +fun DoubleArray.asBuffer() = DoubleBuffer(this) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt new file mode 100644 index 000000000..3437644ff --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ExtendedNDField.kt @@ -0,0 +1,45 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.* + +interface ExtendedNDField> : + NDField, + TrigonometricOperations, + PowerOperations, + ExponentialOperations + where F : ExtendedFieldOperations, F : Field + + +///** +// * NDField that supports [ExtendedField] operations on its elements +// */ +//class ExtendedNDFieldWrapper, N : NDStructure>(private val ndField: NDField) : +// ExtendedNDField, NDField by ndField { +// +// override val shape: IntArray get() = ndField.shape +// override val elementContext: F get() = ndField.elementContext +// +// override fun produce(initializer: F.(IntArray) -> T) = ndField.produce(initializer) +// +// override fun power(arg: N, pow: Double): N { +// return produce { with(elementContext) { power(arg[it], pow) } } +// } +// +// override fun exp(arg: N): N { +// return produce { with(elementContext) { exp(arg[it]) } } +// } +// +// override fun ln(arg: N): N { +// return produce { with(elementContext) { ln(arg[it]) } } +// } +// +// override fun sin(arg: N): N { +// return produce { with(elementContext) { sin(arg[it]) } } +// } +// +// override fun cos(arg: N): N { +// return produce { with(elementContext) { cos(arg[it]) } } +// } +//} + + diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/MemoryBuffer.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/MemoryBuffer.kt new file mode 100644 index 000000000..a09f09165 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/MemoryBuffer.kt @@ -0,0 +1,60 @@ +package scientifik.kmath.structures + +import scientifik.memory.* + +/** + * A non-boxing buffer based on [ByteBuffer] storage + */ +open class MemoryBuffer(protected val memory: Memory, protected val spec: MemorySpec) : Buffer { + + override val size: Int get() = memory.size / spec.objectSize + + private val reader = memory.reader() + + override fun get(index: Int): T = reader.read(spec, spec.objectSize * index) + + override fun iterator(): Iterator = (0 until size).asSequence().map { get(it) }.iterator() + + + companion object { + fun create(spec: MemorySpec, size: Int) = + MemoryBuffer(Memory.allocate(size * spec.objectSize), spec) + + inline fun create( + spec: MemorySpec, + size: Int, + crossinline initializer: (Int) -> T + ): MemoryBuffer = + MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer -> + (0 until size).forEach { + buffer[it] = initializer(it) + } + } + } +} + +class MutableMemoryBuffer(memory: Memory, spec: MemorySpec) : MemoryBuffer(memory, spec), + MutableBuffer { + + private val writer = memory.writer() + + override fun set(index: Int, value: T) = writer.write(spec, spec.objectSize * index, value) + + override fun copy(): MutableBuffer = MutableMemoryBuffer(memory.copy(), spec) + + companion object { + fun create(spec: MemorySpec, size: Int) = + MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec) + + inline fun create( + spec: MemorySpec, + size: Int, + crossinline initializer: (Int) -> T + ) = + MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer -> + (0 until size).forEach { + buffer[it] = initializer(it) + } + } + } +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDAlgebra.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDAlgebra.kt new file mode 100644 index 000000000..c826565cf --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDAlgebra.kt @@ -0,0 +1,156 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.Complex +import scientifik.kmath.operations.Field +import scientifik.kmath.operations.Ring +import scientifik.kmath.operations.Space + + +/** + * An exception is thrown when the expected ans actual shape of NDArray differs + */ +class ShapeMismatchException(val expected: IntArray, val actual: IntArray) : RuntimeException() + + +/** + * The base interface for all nd-algebra implementations + * @param T the type of nd-structure element + * @param C the type of the element context + * @param N the type of the structure + */ +interface NDAlgebra> { + val shape: IntArray + val elementContext: C + + /** + * Produce a new [N] structure using given initializer function + */ + fun produce(initializer: C.(IntArray) -> T): N + + /** + * Map elements from one structure to another one + */ + fun map(arg: N, transform: C.(T) -> T): N + + /** + * Map indexed elements + */ + fun mapIndexed(arg: N, transform: C.(index: IntArray, T) -> T): N + + /** + * Combine two structures into one + */ + fun combine(a: N, b: N, transform: C.(T, T) -> T): N + + /** + * Check if given elements are consistent with this context + */ + fun check(vararg elements: N) { + elements.forEach { + if (!shape.contentEquals(it.shape)) { + throw ShapeMismatchException(shape, it.shape) + } + } + } + + /** + * element-by-element invoke a function working on [T] on a [NDStructure] + */ + operator fun Function1.invoke(structure: N) = map(structure) { value -> this@invoke(value) } + + companion object +} + +/** + * An nd-space over element space + */ +interface NDSpace, N : NDStructure> : Space, NDAlgebra { + /** + * Element-by-element addition + */ + override fun add(a: N, b: N): N = combine(a, b) { aValue, bValue -> add(aValue, bValue) } + + /** + * Multiply all elements by constant + */ + override fun multiply(a: N, k: Number): N = map(a) { multiply(it, k) } + + //TODO move to extensions after KEEP-176 + operator fun N.plus(arg: T) = map(this) { value -> add(arg, value) } + + operator fun N.minus(arg: T) = map(this) { value -> add(arg, -value) } + + operator fun T.plus(arg: N) = map(arg) { value -> add(this@plus, value) } + operator fun T.minus(arg: N) = map(arg) { value -> add(-this@minus, value) } + + companion object +} + +/** + * An nd-ring over element ring + */ +interface NDRing, N : NDStructure> : Ring, NDSpace { + + /** + * Element-by-element multiplication + */ + override fun multiply(a: N, b: N): N = combine(a, b) { aValue, bValue -> multiply(aValue, bValue) } + + //TODO move to extensions after KEEP-176 + operator fun N.times(arg: T) = map(this) { value -> multiply(arg, value) } + + operator fun T.times(arg: N) = map(arg) { value -> multiply(this@times, value) } + + companion object +} + +/** + * Field for n-dimensional structures. + * @param shape - the list of dimensions of the array + * @param elementField - operations field defined on individual array element + * @param T - the type of the element contained in ND structure + * @param F - field of structure elements + * @param R - actual nd-element type of this field + */ +interface NDField, N : NDStructure> : Field, NDRing { + + /** + * Element-by-element division + */ + override fun divide(a: N, b: N): N = combine(a, b) { aValue, bValue -> divide(aValue, bValue) } + + //TODO move to extensions after KEEP-176 + operator fun N.div(arg: T) = map(this) { value -> divide(arg, value) } + + operator fun T.div(arg: N) = map(arg) { divide(it, this@div) } + + companion object { + + private val realNDFieldCache = HashMap() + + /** + * Create a nd-field for [Double] values or pull it from cache if it was created previously + */ + fun real(vararg shape: Int) = realNDFieldCache.getOrPut(shape) { RealNDField(shape) } + + /** + * Create a nd-field with boxing generic buffer + */ + fun > boxing( + field: F, + vararg shape: Int, + bufferFactory: BufferFactory = Buffer.Companion::boxing + ) = BoxingNDField(shape, field, bufferFactory) + + /** + * Create a most suitable implementation for nd-field using reified class. + */ + @Suppress("UNCHECKED_CAST") + inline fun > auto(field: F, vararg shape: Int): BufferedNDField = + when { + T::class == Double::class -> real(*shape) as BufferedNDField + T::class == Complex::class -> complex(*shape) as BufferedNDField + else -> BoxingNDField(shape, field, Buffer.Companion::auto) + } + } +} diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDElement.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDElement.kt new file mode 100644 index 000000000..a18a03364 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDElement.kt @@ -0,0 +1,132 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.Field +import scientifik.kmath.operations.RealField +import scientifik.kmath.operations.Ring +import scientifik.kmath.operations.Space + +/** + * The root for all [NDStructure] based algebra elements. Does not implement algebra element root because of problems with recursive self-types + * @param T the type of the element of the structure + * @param C the type of the context for the element + * @param N the type of the underlying [NDStructure] + */ +interface NDElement> : NDStructure { + + val context: NDAlgebra + + fun unwrap(): N + + fun N.wrap(): NDElement + + companion object { + /** + * Create a optimized NDArray of doubles + */ + fun real(shape: IntArray, initializer: RealField.(IntArray) -> Double = { 0.0 }) = + NDField.real(*shape).produce(initializer) + + + fun real1D(dim: Int, initializer: (Int) -> Double = { _ -> 0.0 }) = + real(intArrayOf(dim)) { initializer(it[0]) } + + + fun real2D(dim1: Int, dim2: Int, initializer: (Int, Int) -> Double = { _, _ -> 0.0 }) = + real(intArrayOf(dim1, dim2)) { initializer(it[0], it[1]) } + + fun real3D(dim1: Int, dim2: Int, dim3: Int, initializer: (Int, Int, Int) -> Double = { _, _, _ -> 0.0 }) = + real(intArrayOf(dim1, dim2, dim3)) { initializer(it[0], it[1], it[2]) } + + + /** + * Simple boxing NDArray + */ + fun > boxing( + shape: IntArray, + field: F, + initializer: F.(IntArray) -> T + ): BufferedNDElement { + val ndField = BoxingNDField(shape, field, Buffer.Companion::boxing) + return ndField.produce(initializer) + } + + inline fun > auto( + shape: IntArray, + field: F, + noinline initializer: F.(IntArray) -> T + ): BufferedNDFieldElement { + val ndField = NDField.auto(field, *shape) + return BufferedNDFieldElement(ndField, ndField.produce(initializer).buffer) + } + } +} + + +fun > NDElement.mapIndexed(transform: C.(index: IntArray, T) -> T) = + context.mapIndexed(unwrap(), transform).wrap() + +fun > NDElement.map(transform: C.(T) -> T) = context.map(unwrap(), transform).wrap() + + +/** + * Element by element application of any operation on elements to the whole [NDElement] + */ +operator fun > Function1.invoke(ndElement: NDElement) = + ndElement.map { value -> this@invoke(value) } + +/* plus and minus */ + +/** + * Summation operation for [NDElement] and single element + */ +operator fun , N : NDStructure> NDElement.plus(arg: T) = + map { value -> arg + value } + +/** + * Subtraction operation between [NDElement] and single element + */ +operator fun , N : NDStructure> NDElement.minus(arg: T) = + map { value -> arg - value } + +/* prod and div */ + +/** + * Product operation for [NDElement] and single element + */ +operator fun , N : NDStructure> NDElement.times(arg: T) = + map { value -> arg * value } + +/** + * Division operation between [NDElement] and single element + */ +operator fun , N : NDStructure> NDElement.div(arg: T) = + map { value -> arg / value } + + +// /** +// * Reverse sum operation +// */ +// operator fun T.plus(arg: NDStructure): NDElement = produce { index -> +// field.run { this@plus + arg[index] } +// } +// +// /** +// * Reverse minus operation +// */ +// operator fun T.minus(arg: NDStructure): NDElement = produce { index -> +// field.run { this@minus - arg[index] } +// } +// +// /** +// * Reverse product operation +// */ +// operator fun T.times(arg: NDStructure): NDElement = produce { index -> +// field.run { this@times * arg[index] } +// } +// +// /** +// * Reverse division operation +// */ +// operator fun T.div(arg: NDStructure): NDElement = produce { index -> +// field.run { this@div / arg[index] } +// } diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDStructure.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDStructure.kt new file mode 100644 index 000000000..236a6f366 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/NDStructure.kt @@ -0,0 +1,263 @@ +package scientifik.kmath.structures + +import kotlin.jvm.JvmName +import kotlin.reflect.KClass + + +interface NDStructure { + + val shape: IntArray + + val dimension get() = shape.size + + operator fun get(index: IntArray): T + + fun elements(): Sequence> + + override fun equals(other: Any?): Boolean + + override fun hashCode(): Int + + companion object { + fun equals(st1: NDStructure<*>, st2: NDStructure<*>): Boolean { + if (st1 === st2) return true + + // fast comparison of buffers if possible + if ( + st1 is NDBuffer && + st2 is NDBuffer && + st1.strides == st2.strides + ) { + return st1.buffer.contentEquals(st2.buffer) + } + + //element by element comparison if it could not be avoided + return st1.elements().all { (index, value) -> value == st2[index] } + } + + /** + * Create a NDStructure with explicit buffer factory + * + * Strides should be reused if possible + */ + fun build( + strides: Strides, + bufferFactory: BufferFactory = Buffer.Companion::boxing, + initializer: (IntArray) -> T + ) = + BufferNDStructure(strides, bufferFactory(strides.linearSize) { i -> initializer(strides.index(i)) }) + + /** + * Inline create NDStructure with non-boxing buffer implementation if it is possible + */ + inline fun auto(strides: Strides, crossinline initializer: (IntArray) -> T) = + BufferNDStructure(strides, Buffer.auto(strides.linearSize) { i -> initializer(strides.index(i)) }) + + inline fun auto(type: KClass, strides: Strides, crossinline initializer: (IntArray) -> T) = + BufferNDStructure(strides, Buffer.auto(type, strides.linearSize) { i -> initializer(strides.index(i)) }) + + fun build( + shape: IntArray, + bufferFactory: BufferFactory = Buffer.Companion::boxing, + initializer: (IntArray) -> T + ) = build(DefaultStrides(shape), bufferFactory, initializer) + + inline fun auto(shape: IntArray, crossinline initializer: (IntArray) -> T) = + auto(DefaultStrides(shape), initializer) + + @JvmName("autoVarArg") + inline fun auto(vararg shape: Int, crossinline initializer: (IntArray) -> T) = + auto(DefaultStrides(shape), initializer) + + inline fun auto(type: KClass, vararg shape: Int, crossinline initializer: (IntArray) -> T) = + auto(type, DefaultStrides(shape), initializer) + } +} + +operator fun NDStructure.get(vararg index: Int): T = get(index) + +interface MutableNDStructure : NDStructure { + operator fun set(index: IntArray, value: T) +} + +inline fun MutableNDStructure.mapInPlace(action: (IntArray, T) -> T) { + elements().forEach { (index, oldValue) -> + this[index] = action(index, oldValue) + } +} + +/** + * A way to convert ND index to linear one and back + */ +interface Strides { + /** + * Shape of NDstructure + */ + val shape: IntArray + + /** + * Array strides + */ + val strides: List + + /** + * Get linear index from multidimensional index + */ + fun offset(index: IntArray): Int + + /** + * Get multidimensional from linear + */ + fun index(offset: Int): IntArray + + /** + * The size of linear buffer to accommodate all elements of ND-structure corresponding to strides + */ + val linearSize: Int + + /** + * Iterate over ND indices in a natural order + */ + fun indices(): Sequence { + //TODO introduce a fast way to calculate index of the next element? + return (0 until linearSize).asSequence().map { index(it) } + } +} + +class DefaultStrides private constructor(override val shape: IntArray) : Strides { + /** + * Strides for memory access + */ + override val strides by lazy { + sequence { + var current = 1 + yield(1) + shape.forEach { + current *= it + yield(current) + } + }.toList() + } + + override fun offset(index: IntArray): Int { + return index.mapIndexed { i, value -> + if (value < 0 || value >= this.shape[i]) { + throw RuntimeException("Index $value out of shape bounds: (0,${this.shape[i]})") + } + value * strides[i] + }.sum() + } + + override fun index(offset: Int): IntArray { + val res = IntArray(shape.size) + var current = offset + var strideIndex = strides.size - 2 + while (strideIndex >= 0) { + res[strideIndex] = (current / strides[strideIndex]) + current %= strides[strideIndex] + strideIndex-- + } + return res + } + + override val linearSize: Int + get() = strides[shape.size] + + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is DefaultStrides) return false + + if (!shape.contentEquals(other.shape)) return false + + return true + } + + override fun hashCode(): Int { + return shape.contentHashCode() + } + + companion object { + private val defaultStridesCache = HashMap() + + /** + * Cached builder for default strides + */ + operator fun invoke(shape: IntArray): Strides = defaultStridesCache.getOrPut(shape) { DefaultStrides(shape) } + } +} + +abstract class NDBuffer : NDStructure { + abstract val buffer: Buffer + abstract val strides: Strides + + override fun get(index: IntArray): T = buffer[strides.offset(index)] + + override val shape: IntArray get() = strides.shape + + override fun elements(): Sequence> = strides.indices().map { it to this[it] } + + override fun equals(other: Any?): Boolean { + return NDStructure.equals(this, other as? NDStructure<*> ?: return false) + } + + override fun hashCode(): Int { + var result = strides.hashCode() + result = 31 * result + buffer.hashCode() + return result + } +} + +/** + * Boxing generic [NDStructure] + */ +class BufferNDStructure( + override val strides: Strides, + override val buffer: Buffer +) : NDBuffer() { + init { + if (strides.linearSize != buffer.size) { + error("Expected buffer side of ${strides.linearSize}, but found ${buffer.size}") + } + } +} + +/** + * Transform structure to a new structure using provided [BufferFactory] and optimizing if argument is [BufferNDStructure] + */ +inline fun NDStructure.mapToBuffer( + factory: BufferFactory = Buffer.Companion::auto, + crossinline transform: (T) -> R +): BufferNDStructure { + return if (this is BufferNDStructure) { + BufferNDStructure(this.strides, factory.invoke(strides.linearSize) { transform(buffer[it]) }) + } else { + val strides = DefaultStrides(shape) + BufferNDStructure(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) + } +} + +/** + * Mutable ND buffer based on linear [autoBuffer] + */ +class MutableBufferNDStructure( + override val strides: Strides, + override val buffer: MutableBuffer +) : NDBuffer(), MutableNDStructure { + + init { + if (strides.linearSize != buffer.size) { + error("Expected buffer side of ${strides.linearSize}, but found ${buffer.size}") + } + } + + override fun set(index: IntArray, value: T) = buffer.set(strides.offset(index), value) +} + +inline fun NDStructure.combine( + struct: NDStructure, + crossinline block: (T, T) -> T +): NDStructure { + if (!this.shape.contentEquals(struct.shape)) error("Shape mismatch in structure combination") + return NDStructure.auto(shape) { block(this[it], struct[it]) } +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealBufferField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealBufferField.kt new file mode 100644 index 000000000..88c8c29db --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealBufferField.kt @@ -0,0 +1,153 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.ExtendedField +import scientifik.kmath.operations.ExtendedFieldOperations +import kotlin.math.* + + +/** + * A simple field over linear buffers of [Double] + */ +object RealBufferFieldOperations : ExtendedFieldOperations> { + override fun add(a: Buffer, b: Buffer): DoubleBuffer { + require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " } + return if (a is DoubleBuffer && b is DoubleBuffer) { + val aArray = a.array + val bArray = b.array + DoubleBuffer(DoubleArray(a.size) { aArray[it] + bArray[it] }) + } else { + DoubleBuffer(DoubleArray(a.size) { a[it] + b[it] }) + } + } + + override fun multiply(a: Buffer, k: Number): DoubleBuffer { + val kValue = k.toDouble() + return if (a is DoubleBuffer) { + val aArray = a.array + DoubleBuffer(DoubleArray(a.size) { aArray[it] * kValue }) + } else { + DoubleBuffer(DoubleArray(a.size) { a[it] * kValue }) + } + } + + override fun multiply(a: Buffer, b: Buffer): DoubleBuffer { + require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " } + return if (a is DoubleBuffer && b is DoubleBuffer) { + val aArray = a.array + val bArray = b.array + DoubleBuffer(DoubleArray(a.size) { aArray[it] * bArray[it] }) + } else { + DoubleBuffer(DoubleArray(a.size) { a[it] * b[it] }) + } + } + + override fun divide(a: Buffer, b: Buffer): DoubleBuffer { + require(b.size == a.size) { "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " } + return if (a is DoubleBuffer && b is DoubleBuffer) { + val aArray = a.array + val bArray = b.array + DoubleBuffer(DoubleArray(a.size) { aArray[it] / bArray[it] }) + } else { + DoubleBuffer(DoubleArray(a.size) { a[it] / b[it] }) + } + } + + override fun sin(arg: Buffer): DoubleBuffer { + return if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { sin(array[it]) }) + } else { + DoubleBuffer(DoubleArray(arg.size) { sin(arg[it]) }) + } + } + + override fun cos(arg: Buffer): DoubleBuffer { + return if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { cos(array[it]) }) + } else { + DoubleBuffer(DoubleArray(arg.size) { cos(arg[it]) }) + } + } + + override fun power(arg: Buffer, pow: Number): DoubleBuffer { + return if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) }) + } else { + DoubleBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) }) + } + } + + override fun exp(arg: Buffer): DoubleBuffer { + return if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { exp(array[it]) }) + } else { + DoubleBuffer(DoubleArray(arg.size) { exp(arg[it]) }) + } + } + + override fun ln(arg: Buffer): DoubleBuffer { + return if (arg is DoubleBuffer) { + val array = arg.array + DoubleBuffer(DoubleArray(arg.size) { ln(array[it]) }) + } else { + DoubleBuffer(DoubleArray(arg.size) { ln(arg[it]) }) + } + } +} + +class RealBufferField(val size: Int) : ExtendedField> { + + override val zero: Buffer by lazy { DoubleBuffer(size) { 0.0 } } + + override val one: Buffer by lazy { DoubleBuffer(size) { 1.0 } } + + override fun add(a: Buffer, b: Buffer): DoubleBuffer { + require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } + return RealBufferFieldOperations.add(a, b) + } + + override fun multiply(a: Buffer, k: Number): DoubleBuffer { + require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } + return RealBufferFieldOperations.multiply(a, k) + } + + override fun multiply(a: Buffer, b: Buffer): DoubleBuffer { + require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } + return RealBufferFieldOperations.multiply(a, b) + } + + + override fun divide(a: Buffer, b: Buffer): DoubleBuffer { + require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } + return RealBufferFieldOperations.divide(a, b) + } + + override fun sin(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return RealBufferFieldOperations.sin(arg) + } + + override fun cos(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return RealBufferFieldOperations.cos(arg) + } + + override fun power(arg: Buffer, pow: Number): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return RealBufferFieldOperations.power(arg, pow) + } + + override fun exp(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return RealBufferFieldOperations.exp(arg) + } + + override fun ln(arg: Buffer): DoubleBuffer { + require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } + return RealBufferFieldOperations.ln(arg) + } + +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealNDField.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealNDField.kt new file mode 100644 index 000000000..8c1bd4239 --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/RealNDField.kt @@ -0,0 +1,128 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.FieldElement +import scientifik.kmath.operations.RealField + +typealias RealNDElement = BufferedNDFieldElement + +class RealNDField(override val shape: IntArray) : + BufferedNDField, + ExtendedNDField> { + + override val strides: Strides = DefaultStrides(shape) + + override val elementContext: RealField get() = RealField + override val zero by lazy { produce { zero } } + override val one by lazy { produce { one } } + + inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Double): Buffer = + DoubleBuffer(DoubleArray(size) { initializer(it) }) + + /** + * Inline transform an NDStructure to + */ + override fun map( + arg: NDBuffer, + transform: RealField.(Double) -> Double + ): RealNDElement { + check(arg) + val array = buildBuffer(arg.strides.linearSize) { offset -> RealField.transform(arg.buffer[offset]) } + return BufferedNDFieldElement(this, array) + } + + override fun produce(initializer: RealField.(IntArray) -> Double): RealNDElement { + val array = buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) } + return BufferedNDFieldElement(this, array) + } + + override fun mapIndexed( + arg: NDBuffer, + transform: RealField.(index: IntArray, Double) -> Double + ): RealNDElement { + check(arg) + return BufferedNDFieldElement( + this, + buildBuffer(arg.strides.linearSize) { offset -> + elementContext.transform( + arg.strides.index(offset), + arg.buffer[offset] + ) + }) + } + + override fun combine( + a: NDBuffer, + b: NDBuffer, + transform: RealField.(Double, Double) -> Double + ): RealNDElement { + check(a, b) + return BufferedNDFieldElement( + this, + buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) }) + } + + override fun NDBuffer.toElement(): FieldElement, *, out BufferedNDField> = + BufferedNDFieldElement(this@RealNDField, buffer) + + override fun power(arg: NDBuffer, pow: Number) = map(arg) { power(it, pow) } + + override fun exp(arg: NDBuffer) = map(arg) { exp(it) } + + override fun ln(arg: NDBuffer) = map(arg) { ln(it) } + + override fun sin(arg: NDBuffer) = map(arg) { sin(it) } + + override fun cos(arg: NDBuffer) = map(arg) { cos(it) } + +} + + +/** + * Fast element production using function inlining + */ +inline fun BufferedNDField.produceInline(crossinline initializer: RealField.(Int) -> Double): RealNDElement { + val array = DoubleArray(strides.linearSize) { offset -> RealField.initializer(offset) } + return BufferedNDFieldElement(this, DoubleBuffer(array)) +} + +/** + * Map one [RealNDElement] using function with indexes + */ +inline fun RealNDElement.mapIndexed(crossinline transform: RealField.(index: IntArray, Double) -> Double) = + context.produceInline { offset -> transform(strides.index(offset), buffer[offset]) } + +/** + * Map one [RealNDElement] using function without indexes + */ +inline fun RealNDElement.map(crossinline transform: RealField.(Double) -> Double): RealNDElement { + val array = DoubleArray(strides.linearSize) { offset -> RealField.transform(buffer[offset]) } + return BufferedNDFieldElement(context, DoubleBuffer(array)) +} + +/** + * Element by element application of any operation on elements to the whole array. Just like in numpy + */ +operator fun Function1.invoke(ndElement: RealNDElement) = + ndElement.map { this@invoke(it) } + + +/* plus and minus */ + +/** + * Summation operation for [BufferedNDElement] and single element + */ +operator fun RealNDElement.plus(arg: Double) = + map { it + arg } + +/** + * Subtraction operation between [BufferedNDElement] and single element + */ +operator fun RealNDElement.minus(arg: Double) = + map { it - arg } + +/** + * Produce a context for n-dimensional operations inside this real field + */ +inline fun RealField.nd(vararg shape: Int, action: RealNDField.() -> R): R { + return NDField.real(*shape).run(action) +} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ShortNDRing.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ShortNDRing.kt new file mode 100644 index 000000000..6b09c91de --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/ShortNDRing.kt @@ -0,0 +1,96 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.RingElement +import scientifik.kmath.operations.ShortRing + + +typealias ShortNDElement = BufferedNDRingElement + +class ShortNDRing(override val shape: IntArray) : + BufferedNDRing { + + override val strides: Strides = DefaultStrides(shape) + + override val elementContext: ShortRing get() = ShortRing + override val zero by lazy { produce { ShortRing.zero } } + override val one by lazy { produce { ShortRing.one } } + + inline fun buildBuffer(size: Int, crossinline initializer: (Int) -> Short): Buffer = + ShortBuffer(ShortArray(size) { initializer(it) }) + + /** + * Inline transform an NDStructure to + */ + override fun map( + arg: NDBuffer, + transform: ShortRing.(Short) -> Short + ): ShortNDElement { + check(arg) + val array = buildBuffer(arg.strides.linearSize) { offset -> ShortRing.transform(arg.buffer[offset]) } + return BufferedNDRingElement(this, array) + } + + override fun produce(initializer: ShortRing.(IntArray) -> Short): ShortNDElement { + val array = buildBuffer(strides.linearSize) { offset -> elementContext.initializer(strides.index(offset)) } + return BufferedNDRingElement(this, array) + } + + override fun mapIndexed( + arg: NDBuffer, + transform: ShortRing.(index: IntArray, Short) -> Short + ): ShortNDElement { + check(arg) + return BufferedNDRingElement( + this, + buildBuffer(arg.strides.linearSize) { offset -> + elementContext.transform( + arg.strides.index(offset), + arg.buffer[offset] + ) + }) + } + + override fun combine( + a: NDBuffer, + b: NDBuffer, + transform: ShortRing.(Short, Short) -> Short + ): ShortNDElement { + check(a, b) + return BufferedNDRingElement( + this, + buildBuffer(strides.linearSize) { offset -> elementContext.transform(a.buffer[offset], b.buffer[offset]) }) + } + + override fun NDBuffer.toElement(): RingElement, *, out BufferedNDRing> = + BufferedNDRingElement(this@ShortNDRing, buffer) +} + + +/** + * Fast element production using function inlining + */ +inline fun BufferedNDRing.produceInline(crossinline initializer: ShortRing.(Int) -> Short): ShortNDElement { + val array = ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) } + return BufferedNDRingElement(this, ShortBuffer(array)) +} + +/** + * Element by element application of any operation on elements to the whole array. Just like in numpy + */ +operator fun Function1.invoke(ndElement: ShortNDElement) = + ndElement.context.produceInline { i -> invoke(ndElement.buffer[i]) } + + +/* plus and minus */ + +/** + * Summation operation for [StridedNDFieldElement] and single element + */ +operator fun ShortNDElement.plus(arg: Short) = + context.produceInline { i -> (buffer[i] + arg).toShort() } + +/** + * Subtraction operation between [StridedNDFieldElement] and single element + */ +operator fun ShortNDElement.minus(arg: Short) = + context.produceInline { i -> (buffer[i] - arg).toShort() } \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Structure1D.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Structure1D.kt new file mode 100644 index 000000000..9974538ec --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Structure1D.kt @@ -0,0 +1,62 @@ +package scientifik.kmath.structures + +/** + * A structure that is guaranteed to be one-dimensional + */ +interface Structure1D : NDStructure, Buffer { + override val dimension: Int get() = 1 + + override fun get(index: IntArray): T { + if (index.size != 1) error("Index dimension mismatch. Expected 1 but found ${index.size}") + return get(index[0]) + } + + override fun iterator(): Iterator = (0 until size).asSequence().map { get(it) }.iterator() +} + +/** + * A 1D wrapper for nd-structure + */ +private inline class Structure1DWrapper(val structure: NDStructure) : Structure1D{ + + override val shape: IntArray get() = structure.shape + override val size: Int get() = structure.shape[0] + + override fun get(index: Int): T = structure[index] + + override fun elements(): Sequence> = structure.elements() +} + + +/** + * A structure wrapper for buffer + */ +private inline class Buffer1DWrapper(val buffer: Buffer) : Structure1D { + override val shape: IntArray get() = intArrayOf(buffer.size) + + override val size: Int get() = buffer.size + + override fun elements(): Sequence> = + asSequence().mapIndexed { index, value -> intArrayOf(index) to value } + + override fun get(index: Int): T = buffer.get(index) +} + +/** + * Represent a [NDStructure] as [Structure1D]. Throw error in case of dimension mismatch + */ +fun NDStructure.as1D(): Structure1D = if (shape.size == 1) { + if( this is NDBuffer){ + Buffer1DWrapper(this.buffer) + } else { + Structure1DWrapper(this) + } +} else { + error("Can't create 1d-structure from ${shape.size}d-structure") +} + + +/** + * Represent this buffer as 1D structure + */ +fun Buffer.asND(): Structure1D = Buffer1DWrapper(this) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Structure2D.kt b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Structure2D.kt new file mode 100644 index 000000000..bfaf8338d --- /dev/null +++ b/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/Structure2D.kt @@ -0,0 +1,60 @@ +package scientifik.kmath.structures + +/** + * A structure that is guaranteed to be two-dimensional + */ +interface Structure2D : NDStructure { + val rowNum: Int get() = shape[0] + val colNum: Int get() = shape[1] + + operator fun get(i: Int, j: Int): T + + override fun get(index: IntArray): T { + if (index.size != 2) error("Index dimension mismatch. Expected 2 but found ${index.size}") + return get(index[0], index[1]) + } + + val rows: Buffer> + get() = VirtualBuffer(rowNum) { i -> + VirtualBuffer(colNum) { j -> get(i, j) } + } + + val columns: Buffer> + get() = VirtualBuffer(colNum) { j -> + VirtualBuffer(rowNum) { i -> get(i, j) } + } + + override fun elements(): Sequence> = sequence { + for (i in (0 until rowNum)) { + for (j in (0 until colNum)) { + yield(intArrayOf(i, j) to get(i, j)) + } + } + } + + companion object { + + } +} + +/** + * A 2D wrapper for nd-structure + */ +private inline class Structure2DWrapper(val structure: NDStructure) : Structure2D { + override fun get(i: Int, j: Int): T = structure[i, j] + + override val shape: IntArray get() = structure.shape + + override fun elements(): Sequence> = structure.elements() +} + +/** + * Represent a [NDStructure] as [Structure1D]. Throw error in case of dimension mismatch + */ +fun NDStructure.as2D(): Structure2D = if (shape.size == 2) { + Structure2DWrapper(this) +} else { + error("Can't create 2d-structure from ${shape.size}d-structure") +} + +typealias Matrix = Structure2D \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt deleted file mode 100644 index de7f30680..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/ColumnarData.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.data - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.Structure2D -import space.kscience.kmath.structures.Buffer - -/** - * A column-based data set with all columns of the same size (not necessary fixed in time). - * The column could be retrieved by a [get] operation. - */ -@UnstableKMathAPI -public interface ColumnarData { - public val size: Int - - /** - * Provide a column by symbol or null if column with given symbol is not defined - */ - public operator fun get(symbol: Symbol): Buffer? -} - -/** - * A zero-copy method to represent a [Structure2D] as a two-column x-y data. - * There could more than two columns in the structure. - */ -@OptIn(PerformancePitfall::class) -@UnstableKMathAPI -public fun Structure2D.asColumnarData(mapping: Map): ColumnarData { - require(shape[1] >= mapping.maxOf { it.value }) { "Column index out of bounds" } - return object : ColumnarData { - override val size: Int get() = shape[0] - override fun get(symbol: Symbol): Buffer { - val index = mapping[symbol] ?: error("No column mapping for symbol $symbol") - return columns[index] - } - } -} - 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 deleted file mode 100644 index f3ecc7e37..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYColumnarData.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.data - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.Structure2D -import space.kscience.kmath.structures.Buffer -import kotlin.math.max - -/** - * The buffer of X values. - */ -@UnstableKMathAPI -public interface XYColumnarData : ColumnarData { - /** - * The buffer of X values - */ - public val x: Buffer - - /** - * The buffer of Y values. - */ - public val y: Buffer - - override fun get(symbol: Symbol): Buffer? = when (symbol) { - Symbol.x -> x - Symbol.y -> y - else -> null - } -} - -@Suppress("FunctionName") -@UnstableKMathAPI -public fun XYColumnarData(x: Buffer, y: Buffer): XYColumnarData { - require(x.size == y.size) { "Buffer size mismatch. x buffer size is ${x.size}, y buffer size is ${y.size}" } - return object : XYColumnarData { - override val size: Int = x.size - override val x: Buffer = x - override val y: Buffer = y - } -} - - -/** - * A zero-copy method to represent a [Structure2D] as a two-column x-y data. - * There could more than two columns in the structure. - */ -@OptIn(PerformancePitfall::class) -@UnstableKMathAPI -public fun Structure2D.asXYData(xIndex: Int = 0, yIndex: Int = 1): XYColumnarData { - require(shape[1] >= max(xIndex, yIndex)) { "Column index out of bounds" } - return object : XYColumnarData { - override val size: Int get() = this@asXYData.shape[0] - override val x: Buffer get() = columns[xIndex] - override val y: Buffer get() = columns[yIndex] - } -} 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 deleted file mode 100644 index 42866afc4..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/data/XYZColumnarData.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.data - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.structures.Buffer - -/** - * A [XYColumnarData] with guaranteed [x], [y] and [z] columns designated by corresponding symbols. - * Inherits [XYColumnarData]. - */ -@UnstableKMathAPI -public interface XYZColumnarData : XYColumnarData { - public val z: Buffer - - override fun get(symbol: Symbol): Buffer? = when (symbol) { - Symbol.x -> x - Symbol.y -> y - Symbol.z -> z - else -> null - } -} 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 deleted file mode 100644 index 0c4d2307b..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/Domain.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.domains - -import space.kscience.kmath.linear.Point - -/** - * A simple geometric domain. - * - * @param T the type of element of this domain. - */ -public interface Domain { - /** - * Checks if the specified point is contained in this domain. - */ - public operator fun contains(point: Point): Boolean - - /** - * Number of hyperspace dimensions. - */ - public val dimension: Int -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt deleted file mode 100644 index aee1d52c5..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/DoubleDomain.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package space.kscience.kmath.domains - -import space.kscience.kmath.misc.UnstableKMathAPI - -/** - * n-dimensional volume - * - * @author Alexander Nozik - */ -@UnstableKMathAPI -public interface DoubleDomain : Domain { - /** - * Global lower edge - * @param num axis number - */ - public fun getLowerBound(num: Int): Double - - /** - * Global upper edge - * @param num axis number - */ - public fun getUpperBound(num: Int): Double - - /** - * Hyper volume - * @return - */ - public fun volume(): Double -} 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 deleted file mode 100644 index 7ea3e22c4..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/HyperSquareDomain.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package space.kscience.kmath.domains - -import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.indices - -/** - * - * HyperSquareDomain class. - * - * @author Alexander Nozik - */ -@UnstableKMathAPI -public class HyperSquareDomain(private val lower: Buffer, private val upper: Buffer) : DoubleDomain { - override val dimension: Int get() = lower.size - - override operator fun contains(point: Point): Boolean = point.indices.all { i -> - point[i] in lower[i]..upper[i] - } - - override fun getLowerBound(num: Int): Double = lower[num] - - override fun getUpperBound(num: Int): Double = upper[num] - - override fun volume(): Double { - var res = 1.0 - - for (i in 0 until dimension) { - if (lower[i].isInfinite() || upper[i].isInfinite()) return Double.POSITIVE_INFINITY - if (upper[i] > lower[i]) res *= upper[i] - lower[i] - } - - return res - } -} 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 deleted file mode 100644 index 040bb80b0..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnconstrainedDomain.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package space.kscience.kmath.domains - -import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI - -@UnstableKMathAPI -public class UnconstrainedDomain(override val dimension: Int) : DoubleDomain { - override operator fun contains(point: Point): Boolean = true - - override fun getLowerBound(num: Int): Double = Double.NEGATIVE_INFINITY - - override fun getUpperBound(num: Int): 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 deleted file mode 100644 index a5add6a0b..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains/UnivariateDomain.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.domains - -import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI - -@UnstableKMathAPI -public class UnivariateDomain(public val range: ClosedFloatingPointRange) : DoubleDomain { - override val dimension: Int get() = 1 - - public operator fun contains(d: Double): Boolean = range.contains(d) - - override operator fun contains(point: Point): Boolean { - require(point.size == 0) - return contains(point[0]) - } - - override fun getLowerBound(num: Int): Double { - require(num == 0) - return range.start - } - - override fun getUpperBound(num: Int): Double { - require(num == 0) - return range.endInclusive - } - - 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 deleted file mode 100644 index 4887f3c74..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/DifferentiableExpression.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.expressions - -/** - * Represents expression, which structure can be differentiated. - * - * @param T the type this expression takes as argument and returns. - */ -public interface DifferentiableExpression : Expression { - /** - * Differentiates this expression by ordered collection of [symbols]. - * - * @param symbols the symbols. - * @return the derivative or `null`. - */ - public fun derivativeOrNull(symbols: List): 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 = - derivative(symbols.toList()) - -public fun DifferentiableExpression.derivative(name: String): Expression = - derivative(StringSymbol(name)) - -/** - * 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 { - override fun derivativeOrNull(symbols: List): R? -} - -public fun > SpecialDifferentiableExpression.derivative(symbols: List): R = - derivativeOrNull(symbols) ?: error("Derivative by symbols $symbols not provided") - -public fun > SpecialDifferentiableExpression.derivative(vararg symbols: Symbol): R = - derivative(symbols.toList()) - -public fun > SpecialDifferentiableExpression.derivative(name: String): R = - derivative(StringSymbol(name)) - -/** - * A [DifferentiableExpression] that defines only first derivatives - */ -public abstract class FirstDerivativeExpression : DifferentiableExpression { - /** - * Returns first derivative of this expression by given [symbol]. - */ - public abstract fun derivativeOrNull(symbol: Symbol): Expression? - - public final override fun derivativeOrNull(symbols: List): Expression? { - val dSymbol = symbols.firstOrNull() ?: return null - return derivativeOrNull(dSymbol) - } -} - -/** - * A factory that converts an expression in autodiff variables to a [DifferentiableExpression] - */ -public fun interface AutoDiffProcessor, out R : Expression> { - public fun process(function: A.() -> I): DifferentiableExpression -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt deleted file mode 100644 index c7dafec3b..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Expression.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.expressions - -import space.kscience.kmath.operations.Algebra -import kotlin.jvm.JvmName -import kotlin.properties.ReadOnlyProperty - -/** - * An elementary function that could be invoked on a map of arguments. - * - * @param T the type this expression takes as argument and returns. - */ -public fun interface Expression { - /** - * Calls this expression from arguments. - * - * @param arguments the map of arguments. - * @return the value. - */ - public operator fun invoke(arguments: Map): T -} - -/** - * Calls this expression without providing any arguments. - * - * @return a value. - */ -public operator fun Expression.invoke(): T = invoke(emptyMap()) - -/** - * Calls this expression from arguments. - * - * @param pairs the pairs of arguments to values. - * @return a value. - */ -@JvmName("callBySymbol") -public operator fun Expression.invoke(vararg pairs: Pair): T = invoke(mapOf(*pairs)) - -/** - * Calls this expression from arguments. - * - * @param pairs the pairs of arguments' names to value. - * @return a value. - */ -@JvmName("callByString") -public operator fun Expression.invoke(vararg pairs: Pair): T = - invoke(mapOf(*pairs).mapKeys { StringSymbol(it.key) }) - - -/** - * A context for expression construction - * - * @param T type of the constants for the expression - * @param E type of the actual expression state - */ -public interface ExpressionAlgebra : Algebra { - - /** - * A constant expression that does not depend on arguments. - */ - public fun const(value: T): E -} - -/** - * Bind a symbol by name inside the [ExpressionAlgebra] - */ -public fun ExpressionAlgebra.binding(): ReadOnlyProperty = ReadOnlyProperty { _, property -> - bindSymbol(property.name) ?: error("A variable with name ${property.name} does not exist") -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt deleted file mode 100644 index bb7f36fc5..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/FunctionalExpressionAlgebra.kt +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.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 val algebra: A, -) : ExpressionAlgebra> { - /** - * Builds an Expression of constant expression that does not depend on arguments. - */ - override fun const(value: T): Expression = Expression { value } - - /** - * Builds an Expression to access a variable. - */ - override fun bindSymbolOrNull(value: String): Expression? = Expression { arguments -> - algebra.bindSymbolOrNull(value) - ?: arguments[StringSymbol(value)] - ?: error("Symbol '$value' is not supported in $this") - } - - override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = - { left, right -> - Expression { arguments -> - algebra.binaryOperationFunction(operation)(left.invoke(arguments), right.invoke(arguments)) - } - } - - override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = { arg -> - Expression { arguments -> algebra.unaryOperationFunction(operation)(arg.invoke(arguments)) } - } -} - -/** - * A context class for [Expression] construction for [Ring] algebras. - */ -public open class FunctionalExpressionGroup>( - algebra: A, -) : FunctionalExpressionAlgebra(algebra), Group> { - override val zero: Expression get() = const(algebra.zero) - - override fun Expression.unaryMinus(): Expression = - unaryOperation(GroupOperations.MINUS_OPERATION, this) - - /** - * Builds an Expression of addition of two another expressions. - */ - override fun add(a: Expression, b: Expression): Expression = - binaryOperation(GroupOperations.PLUS_OPERATION, a, b) - -// /** -// * Builds an Expression of multiplication of expression by number. -// */ -// override fun multiply(a: Expression, k: Number): Expression = Expression { arguments -> -// algebra.multiply(a.invoke(arguments), k) -// } - - public operator fun Expression.plus(arg: T): Expression = this + const(arg) - public operator fun Expression.minus(arg: T): Expression = this - const(arg) - public operator fun T.plus(arg: Expression): Expression = arg + this - public operator fun T.minus(arg: Expression): Expression = arg - this - - override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = - super.unaryOperationFunction(operation) - - override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = - super.binaryOperationFunction(operation) - -} - -public open class FunctionalExpressionRing>( - algebra: A, -) : FunctionalExpressionGroup(algebra), Ring> { - override val one: Expression get() = const(algebra.one) - - /** - * Builds an Expression of multiplication of two expressions. - */ - 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 - - override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = - super.unaryOperationFunction(operation) - - override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = - super.binaryOperationFunction(operation) -} - -public open class FunctionalExpressionField>( - algebra: A, -) : FunctionalExpressionRing(algebra), Field>, ScaleOperations> { - /** - * Builds an Expression of division an expression by another one. - */ - 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 - - override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = - super.unaryOperationFunction(operation) - - override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = - super.binaryOperationFunction(operation) - - override fun scale(a: Expression, value: Double): Expression = algebra { - Expression { args -> a(args) * value } - } - - override fun bindSymbolOrNull(value: String): Expression? = - super.bindSymbolOrNull(value) -} - -public open class FunctionalExpressionExtendedField>( - algebra: A, -) : FunctionalExpressionField(algebra), ExtendedField> { - override fun number(value: Number): Expression = const(algebra.number(value)) - - override fun sqrt(arg: Expression): Expression = - unaryOperationFunction(PowerOperations.SQRT_OPERATION)(arg) - - override fun sin(arg: Expression): Expression = - unaryOperationFunction(TrigonometricOperations.SIN_OPERATION)(arg) - - override fun cos(arg: Expression): Expression = - unaryOperationFunction(TrigonometricOperations.COS_OPERATION)(arg) - - override fun asin(arg: Expression): Expression = - unaryOperationFunction(TrigonometricOperations.ASIN_OPERATION)(arg) - - override fun acos(arg: Expression): Expression = - unaryOperationFunction(TrigonometricOperations.ACOS_OPERATION)(arg) - - override fun atan(arg: Expression): Expression = - unaryOperationFunction(TrigonometricOperations.ATAN_OPERATION)(arg) - - override fun power(arg: Expression, pow: Number): Expression = - binaryOperationFunction(PowerOperations.POW_OPERATION)(arg, number(pow)) - - override fun exp(arg: Expression): Expression = - unaryOperationFunction(ExponentialOperations.EXP_OPERATION)(arg) - - override fun ln(arg: Expression): Expression = - unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg) - - override fun unaryOperationFunction(operation: String): (arg: Expression) -> Expression = - super.unaryOperationFunction(operation) - - override fun binaryOperationFunction(operation: String): (left: Expression, right: Expression) -> Expression = - super.binaryOperationFunction(operation) - - override fun bindSymbol(value: String): Expression = super.bindSymbol(value) -} - -public inline fun > A.expressionInGroup( - block: FunctionalExpressionGroup.() -> Expression, -): Expression { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return FunctionalExpressionGroup(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 { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return FunctionalExpressionField(this).block() -} - -public inline fun > A.expressionInExtendedField( - block: FunctionalExpressionExtendedField.() -> Expression, -): Expression = FunctionalExpressionExtendedField(this).block() diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt deleted file mode 100644 index fe50902b1..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MST.kt +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.expressions - -import space.kscience.kmath.operations.Algebra -import space.kscience.kmath.operations.NumericAlgebra -import space.kscience.kmath.operations.bindSymbol - -/** - * A Mathematical Syntax Tree (MST) node for mathematical expressions. - * - * @author Alexander Nozik - */ -public sealed interface MST { - - /** - * A node containing a numeric value or scalar. - * - * @property value the value of this number. - */ - public data class Numeric(val value: Number) : MST - - /** - * A node containing an unary operation. - * - * @property operation the identifier of operation. - * @property value the argument of this operation. - */ - public data class Unary(val operation: String, val value: MST) : MST - - /** - * A node containing binary operation. - * - * @property operation the identifier operation. - * @property left the left operand. - * @property right the right operand. - */ - public data class Binary(val operation: String, val left: MST, val right: MST) : MST -} - -// TODO add a function with named arguments - -/** - * Interprets the [MST] node with this [Algebra]. - * - * @receiver the algebra that provides operations. - * @param node the node to evaluate. - * @return the value of expression. - * @author Alexander Nozik - */ -public fun Algebra.evaluate(node: MST): T = when (node) { - is MST.Numeric -> (this as? NumericAlgebra)?.number(node.value) - ?: error("Numeric nodes are not supported by $this") - - is Symbol -> bindSymbol(node) - - is MST.Unary -> when { - this is NumericAlgebra && node.value is MST.Numeric -> unaryOperationFunction(node.operation)(number(node.value.value)) - else -> unaryOperationFunction(node.operation)(evaluate(node.value)) - } - - is MST.Binary -> when { - this is NumericAlgebra && node.left is MST.Numeric && node.right is MST.Numeric -> - binaryOperationFunction(node.operation)(number(node.left.value), number(node.right.value)) - - this is NumericAlgebra && node.left is MST.Numeric -> - leftSideNumberOperationFunction(node.operation)(node.left.value, evaluate(node.right)) - - this is NumericAlgebra && node.right is MST.Numeric -> - rightSideNumberOperationFunction(node.operation)(evaluate(node.left), node.right.value) - - else -> binaryOperationFunction(node.operation)(evaluate(node.left), evaluate(node.right)) - } -} - -internal class InnerAlgebra(val algebra: Algebra, val arguments: Map) : NumericAlgebra { - override fun bindSymbolOrNull(value: String): T? = algebra.bindSymbolOrNull(value) ?: arguments[StringSymbol(value)] - - override fun unaryOperation(operation: String, arg: T): T = - algebra.unaryOperation(operation, arg) - - override fun binaryOperation(operation: String, left: T, right: T): T = - algebra.binaryOperation(operation, left, right) - - override fun unaryOperationFunction(operation: String): (arg: T) -> T = - algebra.unaryOperationFunction(operation) - - override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = - algebra.binaryOperationFunction(operation) - - @Suppress("UNCHECKED_CAST") - override fun number(value: Number): T = if (algebra is NumericAlgebra<*>) - (algebra as NumericAlgebra).number(value) - else - error("Numeric nodes are not supported by $this") -} - -/** - * Interprets the [MST] node with this [Algebra] and optional [arguments] - */ -public fun MST.interpret(algebra: Algebra, arguments: Map): T = - InnerAlgebra(algebra, arguments).evaluate(this) - -/** - * Interprets the [MST] node with this [Algebra] and optional [arguments] - * - * @receiver the node to evaluate. - * @param algebra the algebra that provides operations. - * @return the value of expression. - */ -public fun MST.interpret(algebra: Algebra, vararg arguments: Pair): T = - interpret(algebra, mapOf(*arguments)) - -/** - * Interpret this [MST] as expression. - */ -public fun MST.toExpression(algebra: Algebra): Expression = Expression { arguments -> - interpret(algebra, arguments) -} 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 deleted file mode 100644 index bbc74005c..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/MstAlgebra.kt +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.expressions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* - -/** - * [Algebra] over [MST] nodes. - */ -public object MstNumericAlgebra : NumericAlgebra { - 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) - - override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = - { arg -> MST.Unary(operation, arg) } - - override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = - { left, right -> MST.Binary(operation, left, right) } -} - -/** - * [Group] over [MST] nodes. - */ -public object MstGroup : Group, NumericAlgebra, ScaleOperations { - override val zero: MST.Numeric = number(0.0) - - 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) - - override operator fun MST.unaryMinus(): MST.Unary = - unaryOperationFunction(GroupOperations.MINUS_OPERATION)(this) - - override operator fun MST.minus(b: MST): MST.Binary = - binaryOperationFunction(GroupOperations.MINUS_OPERATION)(this, b) - - override fun scale(a: MST, value: Double): MST.Binary = - binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, number(value)) - - override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = - MstNumericAlgebra.binaryOperationFunction(operation) - - override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = - MstNumericAlgebra.unaryOperationFunction(operation) -} - -/** - * [Ring] over [MST] nodes. - */ -@Suppress("OVERRIDE_BY_INLINE") -@OptIn(UnstableKMathAPI::class) -public object MstRing : Ring, NumbersAddOperations, ScaleOperations { - override inline val zero: MST.Numeric get() = MstGroup.zero - override val one: MST.Numeric = number(1.0) - - override fun number(value: Number): MST.Numeric = MstGroup.number(value) - override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - override fun add(a: MST, b: MST): MST.Binary = MstGroup.add(a, b) - - override fun scale(a: MST, value: Double): MST.Binary = - MstGroup.binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, MstGroup.number(value)) - - override fun multiply(a: MST, b: MST): MST.Binary = - binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, b) - - override operator fun MST.unaryPlus(): MST.Unary = MstGroup { +this@unaryPlus } - override operator fun MST.unaryMinus(): MST.Unary = MstGroup { -this@unaryMinus } - override operator fun MST.minus(b: MST): MST.Binary = MstGroup { this@minus - b } - - override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = - MstGroup.binaryOperationFunction(operation) - - override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = - MstNumericAlgebra.unaryOperationFunction(operation) -} - -/** - * [Field] over [MST] nodes. - */ -@Suppress("OVERRIDE_BY_INLINE") -@OptIn(UnstableKMathAPI::class) -public object MstField : Field, NumbersAddOperations, ScaleOperations { - override inline val zero: MST.Numeric get() = MstRing.zero - override inline val one: MST.Numeric get() = MstRing.one - - override fun bindSymbolOrNull(value: String): Symbol = MstNumericAlgebra.bindSymbolOrNull(value) - override fun number(value: Number): MST.Numeric = MstRing.number(value) - override fun add(a: MST, b: MST): MST.Binary = MstRing.add(a, b) - - override fun scale(a: MST, value: Double): MST.Binary = - MstGroup.binaryOperationFunction(RingOperations.TIMES_OPERATION)(a, MstGroup.number(value)) - - override fun multiply(a: MST, b: MST): MST.Binary = MstRing.multiply(a, b) - override fun divide(a: MST, b: MST): MST.Binary = - binaryOperationFunction(FieldOperations.DIV_OPERATION)(a, b) - - override operator fun MST.unaryPlus(): MST.Unary = MstRing { +this@unaryPlus } - override operator fun MST.unaryMinus(): MST.Unary = MstRing { -this@unaryMinus } - override operator fun MST.minus(b: MST): MST.Binary = MstRing { this@minus - b } - - override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = - MstRing.binaryOperationFunction(operation) - - override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = - MstRing.unaryOperationFunction(operation) -} - -/** - * [ExtendedField] over [MST] nodes. - */ -@Suppress("OVERRIDE_BY_INLINE") -public object MstExtendedField : ExtendedField, NumericAlgebra { - override inline val zero: MST.Numeric get() = MstField.zero - override inline val one: MST.Numeric get() = MstField.one - - 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) - - override fun scale(a: MST, value: Double): MST = - binaryOperation(GroupOperations.PLUS_OPERATION, a, number(value)) - - 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 } - - override fun power(arg: MST, pow: Number): MST.Binary = - binaryOperationFunction(PowerOperations.POW_OPERATION)(arg, number(pow)) - - override fun exp(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.EXP_OPERATION)(arg) - override fun ln(arg: MST): MST.Unary = unaryOperationFunction(ExponentialOperations.LN_OPERATION)(arg) - - override fun binaryOperationFunction(operation: String): (left: MST, right: MST) -> MST.Binary = - MstField.binaryOperationFunction(operation) - - override fun unaryOperationFunction(operation: String): (arg: MST) -> MST.Unary = - MstField.unaryOperationFunction(operation) -} - -/** - * Logic algebra for [MST] - */ -@UnstableKMathAPI -public object MstLogicAlgebra : LogicAlgebra { - override fun bindSymbolOrNull(value: String): MST = super.bindSymbolOrNull(value) ?: StringSymbol(value) - - override fun const(boolean: Boolean): Symbol = if (boolean) { - LogicAlgebra.TRUE - } else { - LogicAlgebra.FALSE - } - - override fun MST.not(): MST = MST.Unary(Boolean::not.name, this) - - override fun MST.and(other: MST): MST = MST.Binary(Boolean::and.name, this, other) - - override fun MST.or(other: MST): MST = MST.Binary(Boolean::or.name, this, other) - - override fun MST.xor(other: MST): MST = MST.Binary(Boolean::xor.name, this, other) -} 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 deleted file mode 100644 index 4a97baac4..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.expressions - -import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.asBuffer -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -/* - * Implementation of backward-mode automatic differentiation. - * Initial gist by Roman Elizarov: https://gist.github.com/elizarov/1ad3a8583e88cb6ea7a0ad09bb591d3d - */ - - -public open class AutoDiffValue(public val value: T) - -/** - * Represents result of [simpleAutoDiff] call. - * - * @param T the non-nullable type of value. - * @param value the value of result. - * @property simpleAutoDiff The mapping of differentiated variables to their derivatives. - * @property context The field over [T]. - */ -public class DerivationResult( - public val value: T, - private val derivativeValues: Map, - public val context: Field, -) { - /** - * Returns derivative of [variable] or returns [Ring.zero] in [context]. - */ - public fun derivative(variable: Symbol): T = derivativeValues[variable.identity] ?: context.zero - - /** - * Computes the divergence. - */ - public fun div(): T = context { sum(derivativeValues.values) } -} - -/** - * Computes the gradient for variables in given order. - */ -public fun DerivationResult.grad(vararg variables: Symbol): Point { - check(variables.isNotEmpty()) { "Variable order is not provided for gradient construction" } - return variables.map(::derivative).asBuffer() -} - -/** - * Represents field in context of which functions can be derived. - */ -@OptIn(UnstableKMathAPI::class) -public open class SimpleAutoDiffField>( - public val context: F, - bindings: Map, -) : Field>, ExpressionAlgebra>, NumbersAddOperations> { - 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) - private var sp: Int = 0 - private val derivatives: MutableMap, T> = hashMapOf() - - private val bindings: Map> = bindings.entries.associate { - it.key.identity to AutoDiffVariableWithDerivative(it.key.identity, it.value, context.zero) - } - - /** - * Differentiable variable with value and derivative of differentiation ([simpleAutoDiff]) result - * with respect to this variable. - * - * @param T the non-nullable type of value. - * @property value The value of this variable. - */ - private class AutoDiffVariableWithDerivative( - override val identity: String, - value: T, - var d: T, - ) : AutoDiffValue(value), Symbol { - override fun toString(): String = identity - override fun equals(other: Any?): Boolean = this.identity == (other as? Symbol)?.identity - override fun hashCode(): Int = identity.hashCode() - } - - override fun bindSymbolOrNull(value: String): AutoDiffValue? = bindings[value] - - private fun getDerivative(variable: AutoDiffValue): T = - (variable as? AutoDiffVariableWithDerivative)?.d ?: derivatives[variable] ?: context.zero - - private fun setDerivative(variable: AutoDiffValue, value: T) { - if (variable is AutoDiffVariableWithDerivative) variable.d = value else derivatives[variable] = value - } - - @Suppress("UNCHECKED_CAST") - private fun runBackwardPass() { - while (sp > 0) { - val value = stack[--sp] - val block = stack[--sp] as F.(Any?) -> Unit - context.block(value) - } - } - - override fun const(value: T): AutoDiffValue = AutoDiffValue(value) - - override fun number(value: Number): AutoDiffValue = const { one * value } - - /** - * A variable accessing inner state of derivatives. - * Use this value in inner builders to avoid creating additional derivative bindings. - */ - public var AutoDiffValue.d: T - get() = getDerivative(this) - set(value) = setDerivative(this, value) - - /** - * Performs update of derivative after the rest of the formula in the back-pass. - * - * For example, implementation of `sin` function is: - * - * ``` - * fun AD.sin(x: Variable): Variable = derive(Variable(sin(x.x)) { z -> // call derive with function result - * x.d += z.d * cos(x.x) // update derivative using chain rule and derivative of the function - * } - * ``` - */ - @Suppress("UNCHECKED_CAST") - public fun derive(value: R, block: F.(R) -> Unit): R { - // save block to stack for backward pass - if (sp >= stack.size) stack = stack.copyOf(stack.size * 2) - stack[sp++] = block - stack[sp++] = value - return value - } - - - internal fun differentiate(function: SimpleAutoDiffField.() -> AutoDiffValue): DerivationResult { - val result = function() - result.d = context.one // computing derivative w.r.t result - runBackwardPass() - return DerivationResult(result.value, bindings.mapValues { it.value.d }, context) - } - -// // Overloads for Double constants -// -// override operator fun Number.plus(b: AutoDiffValue): AutoDiffValue = -// derive(const { this@plus.toDouble() * one + b.value }) { z -> -// b.d += z.d -// } -// -// override operator fun AutoDiffValue.plus(b: Number): AutoDiffValue = b.plus(this) -// -// override operator fun Number.minus(b: AutoDiffValue): AutoDiffValue = -// derive(const { this@minus.toDouble() * one - b.value }) { z -> b.d -= z.d } -// -// override operator fun AutoDiffValue.minus(b: Number): AutoDiffValue = -// derive(const { this@minus.value - one * b.toDouble() }) { z -> d += z.d } - - - override fun AutoDiffValue.unaryMinus(): AutoDiffValue = - derive(const { -value }) { z -> d -= z.d } - - // Basic math (+, -, *, /) - - override fun add(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = - derive(const { a.value + b.value }) { z -> - a.d += z.d - b.d += z.d - } - - override fun multiply(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = - derive(const { a.value * b.value }) { z -> - a.d += z.d * b.value - b.d += z.d * a.value - } - - override fun divide(a: AutoDiffValue, b: AutoDiffValue): AutoDiffValue = - derive(const { a.value / b.value }) { z -> - a.d += z.d / b.value - b.d -= z.d * a.value / (b.value * b.value) - } - - override fun scale(a: AutoDiffValue, value: Double): AutoDiffValue = - 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. - * - * The partial derivatives are placed in argument `d` variable - * - * Example: - * ``` - * val x by symbol // define variable(s) and their values - * val y = DoubleField.withAutoDiff() { sqr(x) + 5 * x + 3 } // write formulate in deriv context - * assertEquals(17.0, y.x) // the value of result (y) - * assertEquals(9.0, x.d) // dy/dx - * ``` - * - * @param body the action in [SimpleAutoDiffField] context returning [AutoDiffValue] to differentiate with respect to. - * @return the result of differentiation. - */ -public fun > F.simpleAutoDiff( - bindings: Map, - body: SimpleAutoDiffField.() -> AutoDiffValue, -): DerivationResult { - contract { callsInPlace(body, InvocationKind.EXACTLY_ONCE) } - - return SimpleAutoDiffField(this, bindings).differentiate(body) -} - -public fun > F.simpleAutoDiff( - vararg bindings: Pair, - body: SimpleAutoDiffField.() -> AutoDiffValue, -): DerivationResult = simpleAutoDiff(bindings.toMap(), body) - - -/** - * A constructs that creates a derivative structure with required order on-demand - */ -public class SimpleAutoDiffExpression>( - public val field: F, - public val function: SimpleAutoDiffField.() -> AutoDiffValue, -) : FirstDerivativeExpression() { - override operator fun invoke(arguments: Map): T { - //val bindings = arguments.entries.map { it.key.bind(it.value) } - return SimpleAutoDiffField(field, arguments).function().value - } - - 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) - } -} - -/** - * Generate [AutoDiffProcessor] for [SimpleAutoDiffExpression] - */ -public fun > simpleAutoDiff(field: F): AutoDiffProcessor, SimpleAutoDiffField, Expression> = - AutoDiffProcessor { function -> - SimpleAutoDiffExpression(field, function) - } - -// Extensions for differentiation of various basic mathematical functions - -// x ^ 2 -public fun > SimpleAutoDiffField.sqr(x: AutoDiffValue): AutoDiffValue = - derive(const { x.value * x.value }) { z -> x.d += z.d * 2.0 * x.value } - -// x ^ 1/2 -public fun > SimpleAutoDiffField.sqrt(x: AutoDiffValue): AutoDiffValue = - derive(const { sqrt(x.value) }) { z -> x.d += z.d / 2.0 / z.value } - -// x ^ y (const) -public fun > SimpleAutoDiffField.pow( - x: AutoDiffValue, - y: Double, -): AutoDiffValue = derive(const { power(x.value, y) }) { z -> - x.d += z.d * y * power(x.value, y - 1) -} - -public fun > SimpleAutoDiffField.pow( - x: AutoDiffValue, - y: Int, -): AutoDiffValue = pow(x, y.toDouble()) - -// exp(x) -public fun > SimpleAutoDiffField.exp(x: AutoDiffValue): AutoDiffValue = - derive(const { exp(x.value) }) { z -> x.d += z.d * z.value } - -// ln(x) -public fun > SimpleAutoDiffField.ln(x: AutoDiffValue): AutoDiffValue = - derive(const { ln(x.value) }) { z -> x.d += z.d / x.value } - -// x ^ y (any) -public fun > SimpleAutoDiffField.pow( - x: AutoDiffValue, - y: AutoDiffValue, -): AutoDiffValue = - exp(y * ln(x)) - -// sin(x) -public fun > SimpleAutoDiffField.sin(x: AutoDiffValue): AutoDiffValue = - derive(const { sin(x.value) }) { z -> x.d += z.d * cos(x.value) } - -// cos(x) -public fun > SimpleAutoDiffField.cos(x: AutoDiffValue): AutoDiffValue = - derive(const { cos(x.value) }) { z -> x.d -= z.d * sin(x.value) } - -public fun > SimpleAutoDiffField.tan(x: AutoDiffValue): AutoDiffValue = - derive(const { tan(x.value) }) { z -> - val c = cos(x.value) - x.d += z.d / (c * c) - } - -public fun > SimpleAutoDiffField.asin(x: AutoDiffValue): AutoDiffValue = - derive(const { asin(x.value) }) { z -> x.d += z.d / sqrt(one - x.value * x.value) } - -public fun > SimpleAutoDiffField.acos(x: AutoDiffValue): AutoDiffValue = - derive(const { acos(x.value) }) { z -> x.d -= z.d / sqrt(one - x.value * x.value) } - -public fun > SimpleAutoDiffField.atan(x: AutoDiffValue): AutoDiffValue = - derive(const { atan(x.value) }) { z -> x.d += z.d / (one + x.value * x.value) } - -public fun > SimpleAutoDiffField.sinh(x: AutoDiffValue): AutoDiffValue = - derive(const { sinh(x.value) }) { z -> x.d += z.d * cosh(x.value) } - -public fun > SimpleAutoDiffField.cosh(x: AutoDiffValue): AutoDiffValue = - derive(const { cosh(x.value) }) { z -> x.d += z.d * sinh(x.value) } - -public fun > SimpleAutoDiffField.tanh(x: AutoDiffValue): AutoDiffValue = - derive(const { tanh(x.value) }) { z -> - val c = cosh(x.value) - x.d += z.d / (c * c) - } - -public fun > SimpleAutoDiffField.asinh(x: AutoDiffValue): AutoDiffValue = - derive(const { asinh(x.value) }) { z -> x.d += z.d / sqrt(one + x.value * x.value) } - -public fun > SimpleAutoDiffField.acosh(x: AutoDiffValue): AutoDiffValue = - derive(const { acosh(x.value) }) { z -> x.d += z.d / (sqrt((x.value - one) * (x.value + one))) } - -public fun > SimpleAutoDiffField.atanh(x: AutoDiffValue): AutoDiffValue = - derive(const { atanh(x.value) }) { z -> x.d += z.d / (one - x.value * x.value) } - -public class SimpleAutoDiffExtendedField>( - context: F, - bindings: Map, -) : ExtendedField>, ScaleOperations>, - SimpleAutoDiffField(context, bindings) { - - override fun bindSymbol(value: String): AutoDiffValue = super.bindSymbol(value) - - override fun number(value: Number): AutoDiffValue = const { 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 - override fun sqrt(arg: AutoDiffValue): AutoDiffValue = - (this as SimpleAutoDiffField).sqrt(arg) - - // x ^ y (const) - override fun power(arg: AutoDiffValue, pow: Number): AutoDiffValue = - (this as SimpleAutoDiffField).pow(arg, pow.toDouble()) - - // exp(x) - override fun exp(arg: AutoDiffValue): AutoDiffValue = - (this as SimpleAutoDiffField).exp(arg) - - // ln(x) - override fun ln(arg: AutoDiffValue): AutoDiffValue = - (this as SimpleAutoDiffField).ln(arg) - - // x ^ y (any) - public fun pow( - x: AutoDiffValue, - y: AutoDiffValue, - ): AutoDiffValue = exp(y * ln(x)) - - // sin(x) - override fun sin(arg: AutoDiffValue): AutoDiffValue = - (this as SimpleAutoDiffField).sin(arg) - - // cos(x) - override fun cos(arg: AutoDiffValue): AutoDiffValue = - (this as SimpleAutoDiffField).cos(arg) - - override fun tan(arg: AutoDiffValue): AutoDiffValue = - (this as SimpleAutoDiffField).tan(arg) - - override fun asin(arg: AutoDiffValue): AutoDiffValue = - (this as SimpleAutoDiffField).asin(arg) - - override fun acos(arg: AutoDiffValue): AutoDiffValue = - (this as SimpleAutoDiffField).acos(arg) - - override fun atan(arg: AutoDiffValue): AutoDiffValue = - (this as SimpleAutoDiffField).atan(arg) - - override fun sinh(arg: AutoDiffValue): AutoDiffValue = - (this as SimpleAutoDiffField).sinh(arg) - - override fun cosh(arg: AutoDiffValue): AutoDiffValue = - (this as SimpleAutoDiffField).cosh(arg) - - override fun tanh(arg: AutoDiffValue): AutoDiffValue = - (this as SimpleAutoDiffField).tanh(arg) - - override fun asinh(arg: AutoDiffValue): AutoDiffValue = - (this as SimpleAutoDiffField).asinh(arg) - - override fun acosh(arg: AutoDiffValue): AutoDiffValue = - (this as SimpleAutoDiffField).acosh(arg) - - override fun atanh(arg: AutoDiffValue): AutoDiffValue = - (this as SimpleAutoDiffField).atanh(arg) -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt deleted file mode 100644 index d72b94b2a..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/Symbol.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.expressions - -import kotlin.jvm.JvmInline -import kotlin.properties.ReadOnlyProperty - -/** - * A marker interface for a symbol. A symbol must have an identity. - * Ic - */ -public interface Symbol : MST { - /** - * Identity object for the symbol. Two symbols with the same identity are considered to be the same symbol. - */ - public val identity: String - - public companion object { - public val x: StringSymbol = StringSymbol("x") - public val y: StringSymbol = StringSymbol("y") - public val z: StringSymbol = StringSymbol("z") - } -} - -/** - * A [Symbol] with a [String] identity - */ -@JvmInline -public value class StringSymbol(override val identity: String) : Symbol { - override fun toString(): String = identity -} - -/** - * A delegate to create a symbol with a string identity in this scope - */ -public val symbol: ReadOnlyProperty = ReadOnlyProperty { _, property -> - StringSymbol(property.name) -} - -/** - * Ger a value from a [String]-keyed map by a [Symbol] - */ -public operator fun Map.get(symbol: Symbol): T? = get(symbol.identity) - -/** - * Set a value of [String]-keyed map by a [Symbol] - */ -public operator fun MutableMap.set(symbol: Symbol, value: T) { - set(symbol.identity, value) -} - -/** - * Get a value from a [Symbol]-keyed map by a [String] - */ -public operator fun Map.get(string: String): T? = get(StringSymbol(string)) - -/** - * Set a value of [String]-keyed map by a [Symbol] - */ -public operator fun MutableMap.set(string: String, value: T) { - set(StringSymbol(string), value) -} \ No newline at end of file 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 deleted file mode 100644 index 25d2ece51..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SymbolIndexer.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.expressions - -import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.Structure2D -import space.kscience.kmath.structures.BufferFactory -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.jvm.JvmInline - -/** - * An environment to easy transform indexed variables to symbols and back. - * TODO requires multi-receivers to be beautiful - */ -@UnstableKMathAPI -public interface SymbolIndexer { - public val symbols: List - public fun indexOf(symbol: Symbol): Int = symbols.indexOf(symbol) - - public operator fun List.get(symbol: Symbol): T { - require(size == symbols.size) { "The input list size for indexer should be ${symbols.size} but $size found" } - return get(this@SymbolIndexer.indexOf(symbol)) - } - - public operator fun Array.get(symbol: Symbol): T { - require(size == symbols.size) { "The input array size for indexer should be ${symbols.size} but $size found" } - return get(this@SymbolIndexer.indexOf(symbol)) - } - - public operator fun DoubleArray.get(symbol: Symbol): Double { - require(size == symbols.size) { "The input array size for indexer should be ${symbols.size} but $size found" } - return get(indexOf(symbol)) - } - - public operator fun Point.get(symbol: Symbol): T { - require(size == symbols.size) { "The input buffer size for indexer should be ${symbols.size} but $size found" } - return get(indexOf(symbol)) - } - - public fun DoubleArray.toMap(): Map { - require(size == symbols.size) { "The input array size for indexer should be ${symbols.size} but $size found" } - return symbols.indices.associate { symbols[it] to get(it) } - } - - public operator fun Structure2D.get(rowSymbol: Symbol, columnSymbol: Symbol): T = - get(indexOf(rowSymbol), indexOf(columnSymbol)) - - - public fun Map.toList(): List = symbols.map { getValue(it) } - - public fun Map.toPoint(bufferFactory: BufferFactory): Point = - bufferFactory(symbols.size) { getValue(symbols[it]) } - - public fun Map.toDoubleArray(): DoubleArray = DoubleArray(symbols.size) { getValue(symbols[it]) } -} - -@UnstableKMathAPI -@JvmInline -public value class SimpleSymbolIndexer(override val symbols: List) : SymbolIndexer - -/** - * Execute the block with symbol indexer based on given symbol order - */ -@UnstableKMathAPI -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 { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return with(SimpleSymbolIndexer(symbols.toList()), block) -} 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 deleted file mode 100644 index 5471cb925..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/BufferedLinearSpace.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.linear - -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferFactory -import space.kscience.kmath.structures.VirtualBuffer -import space.kscience.kmath.structures.indices - - -public class BufferedLinearSpace>( - override val elementAlgebra: A, - private val bufferFactory: BufferFactory, -) : LinearSpace { - - private fun ndRing( - rows: Int, - cols: Int, - ): BufferedRingND = AlgebraND.ring(elementAlgebra, bufferFactory, rows, cols) - - override fun buildMatrix(rows: Int, columns: Int, initializer: A.(i: Int, j: Int) -> T): Matrix = - ndRing(rows, columns).produce { (i, j) -> elementAlgebra.initializer(i, j) }.as2D() - - override fun buildVector(size: Int, initializer: A.(Int) -> T): Point = - bufferFactory(size) { elementAlgebra.initializer(it) } - - override fun Matrix.unaryMinus(): Matrix = ndRing(rowNum, colNum).run { - unwrap().map { -it }.as2D() - } - - override fun Matrix.plus(other: Matrix): Matrix = ndRing(rowNum, colNum).run { - require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::plus. Expected $shape but found ${other.shape}" } - unwrap().plus(other.unwrap()).as2D() - } - - override fun Matrix.minus(other: Matrix): Matrix = ndRing(rowNum, colNum).run { - require(shape.contentEquals(other.shape)) { "Shape mismatch on Matrix::minus. Expected $shape but found ${other.shape}" } - unwrap().minus(other.unwrap()).as2D() - } - - private fun Buffer.linearize() = if (this is VirtualBuffer) { - buildVector(size) { get(it) } - } else { - this - } - - @OptIn(PerformancePitfall::class) - override fun Matrix.dot(other: Matrix): Matrix { - require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } - return elementAlgebra { - val rows = this@dot.rows.map { it.linearize() } - val columns = other.columns.map { it.linearize() } - buildMatrix(rowNum, other.colNum) { i, j -> - val r = rows[i] - val c = columns[j] - var res = zero - for (l in r.indices) { - res += r[l] * c[l] - } - res - } - } - } - - @OptIn(PerformancePitfall::class) - override fun Matrix.dot(vector: Point): Point { - require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" } - return elementAlgebra { - val rows = this@dot.rows.map { it.linearize() } - buildVector(rowNum) { i -> - val r = rows[i] - var res = zero - for (j in r.indices) { - res += r[j] * vector[j] - } - res - } - } - } - - override fun Matrix.times(value: T): Matrix = ndRing(rowNum, colNum).run { - unwrap().map { it * value }.as2D() - } -} 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 deleted file mode 100644 index 86a35a6a4..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSolver.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.linear - -import space.kscience.kmath.nd.as1D - -/** - * A group of methods to solve for *X* in equation *X = A−1 · B*, where *A* and *B* are - * matrices or vectors. - * - * @param T the type of items. - */ -public interface LinearSolver { - /** - * Solve a dot x = b matrix equation and return x - */ - public fun solve(a: Matrix, b: Matrix): Matrix - - /** - * Solve a dot x = b vector equation and return b - */ - public fun solve(a: Matrix, b: Point): Point = solve(a, b.asMatrix()).asVector() - - /** - * Get inverse of a matrix - */ - public fun inverse(matrix: Matrix): Matrix -} - -/** - * Convert matrix to vector if it is possible. - */ -public fun Matrix.asVector(): Point = - if (this.colNum == 1) - as1D() - else - error("Can't convert matrix with more than one column to vector") - -/** - * Creates an n × 1 [VirtualMatrix], where n is the size of the given buffer. - * - * @param T the type of elements contained in the buffer. - * @receiver a buffer. - * @return the new matrix. - */ -public fun Point.asMatrix(): VirtualMatrix = VirtualMatrix(size, 1) { i, _ -> get(i) } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt deleted file mode 100644 index bb5a1b530..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LinearSpace.kt +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.linear - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferFactory -import space.kscience.kmath.structures.DoubleBuffer -import kotlin.reflect.KClass - -/** - * Alias for [Structure2D] with more familiar name. - * - * @param T the type of items. - */ -public typealias Matrix = Structure2D -public typealias MutableMatrix = MutableStructure2D - -/** - * Alias or using [Buffer] as a point/vector in a many-dimensional space. - * - * @param T the type of elements contained in the buffer. - */ -public typealias Point = Buffer - -/** - * Basic operations on matrices and vectors. - * - * @param T the type of items in the matrices. - * @param A the type of ring over [T]. - */ -public interface LinearSpace> { - public val elementAlgebra: A - - /** - * Produces a matrix with this context and given dimensions. - */ - public fun buildMatrix(rows: Int, columns: Int, initializer: A.(i: Int, j: Int) -> T): Matrix - - /** - * Produces a point compatible with matrix space (and possibly optimized for it). - */ - public fun buildVector(size: Int, initializer: A.(Int) -> T): Point - - public operator fun Matrix.unaryMinus(): Matrix = buildMatrix(rowNum, colNum) { i, j -> - -get(i, j) - } - - public operator fun Point.unaryMinus(): Point = buildVector(size) { - -get(it) - } - - /** - * Matrix sum - */ - public operator fun Matrix.plus(other: Matrix): Matrix = buildMatrix(rowNum, colNum) { i, j -> - get(i, j) + other[i, j] - } - - - /** - * Vector sum - */ - public operator fun Point.plus(other: Point): Point = buildVector(size) { - get(it) + other[it] - } - - /** - * Matrix subtraction - */ - public operator fun Matrix.minus(other: Matrix): Matrix = buildMatrix(rowNum, colNum) { i, j -> - get(i, j) - other[i, j] - } - - /** - * Vector subtraction - */ - public operator fun Point.minus(other: Point): Point = buildVector(size) { - get(it) - other[it] - } - - - /** - * Computes the dot product of this matrix and another one. - * - * @receiver the multiplicand. - * @param other the multiplier. - * @return the dot product. - */ - public infix fun Matrix.dot(other: Matrix): Matrix { - require(colNum == other.rowNum) { "Matrix dot operation dimension mismatch: ($rowNum, $colNum) x (${other.rowNum}, ${other.colNum})" } - return elementAlgebra { - buildMatrix(rowNum, other.colNum) { i, j -> - var res = zero - for (l in 0 until colNum) { - res += this@dot[i, l] * other[l, j] - } - res - } - } - } - - /** - * Computes the dot product of this matrix and a vector. - * - * @receiver the multiplicand. - * @param vector the multiplier. - * @return the dot product. - */ - public infix fun Matrix.dot(vector: Point): Point { - require(colNum == vector.size) { "Matrix dot vector operation dimension mismatch: ($rowNum, $colNum) x (${vector.size})" } - return elementAlgebra { - buildVector(rowNum) { i -> - var res = one - for (j in 0 until colNum) { - res += this@dot[i, j] * vector[j] - } - res - } - } - } - - /** - * Multiplies a matrix by its element. - * - * @receiver the multiplicand. - * @param value the multiplier. - * @receiver the product. - */ - public operator fun Matrix.times(value: T): Matrix = - buildMatrix(rowNum, colNum) { i, j -> get(i, j) * value } - - /** - * Multiplies an element by a matrix of it. - * - * @receiver the multiplicand. - * @param m the multiplier. - * @receiver the product. - */ - public operator fun T.times(m: Matrix): Matrix = m * this - - /** - * Multiplies a vector by its element. - * - * @receiver the multiplicand. - * @param value the multiplier. - * @receiver the product. - */ - public operator fun Point.times(value: T): Point = - buildVector(size) { i -> get(i) * value } - - /** - * Multiplies an element by a vector of it. - * - * @receiver the multiplicand. - * @param v the multiplier. - * @receiver the product. - */ - public operator fun T.times(v: Point): Point = v * this - - /** - * 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. - * @param type the [KClass] instance of [F]. - * @return a feature object or `null` if it isn't present. - */ - @UnstableKMathAPI - public fun getFeature(structure: Matrix, type: KClass): F? = structure.getFeature(type) - - public companion object { - - /** - * A structured matrix with custom buffer - */ - public fun > buffered( - algebra: A, - bufferFactory: BufferFactory = Buffer.Companion::boxing, - ): LinearSpace = BufferedLinearSpace(algebra, bufferFactory) - - public val real: LinearSpace = buffered(DoubleField, ::DoubleBuffer) - - /** - * Automatic buffered matrix, unboxed if it is possible - */ - public inline fun > auto(ring: A): LinearSpace = - buffered(ring, Buffer.Companion::auto) - } -} - -/** - * 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. - * @return a feature object or `null` if it isn't present. - */ -@UnstableKMathAPI -public inline fun LinearSpace.getFeature(structure: Matrix): F? = - getFeature(structure, F::class) - - -public operator fun , R> LS.invoke(block: LS.() -> R): R = run(block) - 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 deleted file mode 100644 index 145088b56..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/LupDecomposition.kt +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.linear - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.getFeature -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.BufferAccessor2D -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.MutableBufferFactory - -/** - * Common implementation of [LupDecompositionFeature]. - */ -public class LupDecomposition( - public val context: LinearSpace, - public val elementContext: Field, - public val lu: Matrix, - public val pivot: IntArray, - private val even: Boolean, -) : LupDecompositionFeature, DeterminantFeature { - /** - * Returns the matrix L of the decomposition. - * - * L is a lower-triangular matrix with [Ring.one] in diagonal - */ - override val l: Matrix = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j -> - when { - j < i -> lu[i, j] - j == i -> elementContext.one - else -> elementContext.zero - } - } + LFeature - - - /** - * Returns the matrix U of the decomposition. - * - * U is an upper-triangular matrix including the diagonal - */ - override val u: Matrix = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j -> - if (j >= i) lu[i, j] else elementContext.zero - } + UFeature - - /** - * Returns the P rows permutation matrix. - * - * P is a sparse matrix with exactly one element set to [Ring.one] in - * each row and each column, all other elements being set to [Ring.zero]. - */ - override val p: Matrix = VirtualMatrix(lu.shape[0], lu.shape[1]) { i, j -> - if (j == pivot[i]) elementContext.one else elementContext.zero - } - - /** - * Return the determinant of the matrix - * @return determinant of the matrix - */ - override val determinant: T by lazy { - elementContext { (0 until lu.shape[0]).fold(if (even) one else -one) { value, i -> value * lu[i, i] } } - } - -} - -@PublishedApi -internal fun > LinearSpace>.abs(value: T): T = - if (value > elementAlgebra.zero) value else elementAlgebra { -value } - -/** - * Create a lup decomposition of generic matrix. - */ -public fun > LinearSpace>.lup( - factory: MutableBufferFactory, - matrix: Matrix, - checkSingular: (T) -> Boolean, -): LupDecomposition { - require(matrix.rowNum == matrix.colNum) { "LU decomposition supports only square matrices" } - val m = matrix.colNum - val pivot = IntArray(matrix.rowNum) - - //TODO just waits for KEEP-176 - BufferAccessor2D(matrix.rowNum, matrix.colNum, factory).run { - elementAlgebra { - val lu = create(matrix) - - // Initialize permutation array and parity - for (row in 0 until m) pivot[row] = row - var even = true - - // Initialize permutation array and parity - for (row in 0 until m) pivot[row] = row - - // Loop over columns - for (col in 0 until m) { - // upper - for (row in 0 until col) { - val luRow = lu.row(row) - var sum = luRow[col] - for (i in 0 until row) sum -= luRow[i] * lu[i, col] - luRow[col] = sum - } - - // lower - var max = col // permutation row - var largest = -one - - for (row in col until m) { - val luRow = lu.row(row) - var sum = luRow[col] - for (i in 0 until col) sum -= luRow[i] * lu[i, col] - luRow[col] = sum - - // maintain the best permutation choice - if (abs(sum) > largest) { - largest = abs(sum) - max = row - } - } - - // Singularity check - check(!checkSingular(abs(lu[max, col]))) { "The matrix is singular" } - - // Pivot if necessary - if (max != col) { - val luMax = lu.row(max) - val luCol = lu.row(col) - - for (i in 0 until m) { - val tmp = luMax[i] - luMax[i] = luCol[i] - luCol[i] = tmp - } - - val temp = pivot[max] - pivot[max] = pivot[col] - pivot[col] = temp - even = !even - } - - // Divide the lower elements by the "winning" diagonal elt. - val luDiag = lu[col, col] - for (row in col + 1 until m) lu[row, col] /= luDiag - } - - return LupDecomposition(this@lup, elementAlgebra, lu.collect(), pivot, even) - } - } -} - -public inline fun > LinearSpace>.lup( - matrix: Matrix, - noinline checkSingular: (T) -> Boolean, -): LupDecomposition = lup(MutableBuffer.Companion::auto, matrix, checkSingular) - -public fun LinearSpace.lup(matrix: Matrix): LupDecomposition = - lup(::DoubleBuffer, matrix) { it < 1e-11 } - -public fun LupDecomposition.solveWithLup( - factory: MutableBufferFactory, - matrix: Matrix, -): Matrix { - require(matrix.rowNum == pivot.size) { "Matrix dimension mismatch. Expected ${pivot.size}, but got ${matrix.colNum}" } - - BufferAccessor2D(matrix.rowNum, matrix.colNum, factory).run { - elementContext { - // Apply permutations to b - val bp = create { _, _ -> zero } - - for (row in pivot.indices) { - val bpRow = bp.row(row) - val pRow = pivot[row] - for (col in 0 until matrix.colNum) bpRow[col] = matrix[pRow, col] - } - - // Solve LY = b - for (col in pivot.indices) { - val bpCol = bp.row(col) - - for (i in col + 1 until pivot.size) { - val bpI = bp.row(i) - val luICol = lu[i, col] - for (j in 0 until matrix.colNum) { - bpI[j] -= bpCol[j] * luICol - } - } - } - - // Solve UX = Y - for (col in pivot.size - 1 downTo 0) { - val bpCol = bp.row(col) - val luDiag = lu[col, col] - for (j in 0 until matrix.colNum) bpCol[j] /= luDiag - - for (i in 0 until col) { - val bpI = bp.row(i) - val luICol = lu[i, col] - for (j in 0 until matrix.colNum) bpI[j] -= bpCol[j] * luICol - } - } - - return context.buildMatrix(pivot.size, matrix.colNum) { i, j -> bp[i, j] } - } - } -} - -public inline fun LupDecomposition.solveWithLup(matrix: Matrix): Matrix = - solveWithLup(MutableBuffer.Companion::auto, matrix) - -/** - * Solves a system of linear equations *ax = b** using LUP decomposition. - */ -@OptIn(UnstableKMathAPI::class) -public inline fun > LinearSpace>.solveWithLup( - a: Matrix, - b: Matrix, - noinline bufferFactory: MutableBufferFactory = MutableBuffer.Companion::auto, - noinline checkSingular: (T) -> Boolean, -): Matrix { - // Use existing decomposition if it is provided by matrix - val decomposition = a.getFeature() ?: lup(bufferFactory, a, checkSingular) - return decomposition.solveWithLup(bufferFactory, b) -} - -public inline fun > LinearSpace>.inverseWithLup( - matrix: Matrix, - noinline bufferFactory: MutableBufferFactory = MutableBuffer.Companion::auto, - noinline checkSingular: (T) -> Boolean, -): Matrix = solveWithLup(matrix, one(matrix.rowNum, matrix.colNum), bufferFactory, checkSingular) - - -@OptIn(UnstableKMathAPI::class) -public fun LinearSpace.solveWithLup(a: Matrix, b: Matrix): Matrix { - // Use existing decomposition if it is provided by matrix - val bufferFactory: MutableBufferFactory = ::DoubleBuffer - val decomposition: LupDecomposition = a.getFeature() ?: lup(bufferFactory, a) { it < 1e-11 } - return decomposition.solveWithLup(bufferFactory, b) -} - -/** - * Inverses a square matrix using LUP decomposition. Non square matrix will throw an error. - */ -public fun LinearSpace.inverseWithLup(matrix: Matrix): Matrix = - solveWithLup(matrix, one(matrix.rowNum, matrix.colNum)) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt deleted file mode 100644 index 01dc21198..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixBuilder.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.linear - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring - -public class MatrixBuilder>( - public val linearSpace: LinearSpace, - public val rows: Int, - public val columns: Int, -) { - public operator fun invoke(vararg elements: T): Matrix { - require(rows * columns == elements.size) { "The number of elements ${elements.size} is not equal $rows * $columns" } - return linearSpace.buildMatrix(rows, columns) { i, j -> elements[i * columns + j] } - } - - //TODO add specific matrix builder functions like diagonal, etc -} - -/** - * Create a matrix builder with given number of rows and columns - */ -@UnstableKMathAPI -public fun > LinearSpace.matrix(rows: Int, columns: Int): MatrixBuilder = - MatrixBuilder(this, rows, columns) - -@UnstableKMathAPI -public fun LinearSpace>.vector(vararg elements: T): Point { - return buildVector(elements.size) { elements[it] } -} - -public inline fun LinearSpace>.row( - size: Int, - crossinline builder: (Int) -> T, -): Matrix = buildMatrix(1, size) { _, j -> builder(j) } - -public fun LinearSpace>.row(vararg values: T): Matrix = row(values.size, values::get) - -public inline fun LinearSpace>.column( - size: Int, - crossinline builder: (Int) -> T, -): Matrix = buildMatrix(size, 1) { i, _ -> builder(i) } - -public fun LinearSpace>.column(vararg values: T): Matrix = column(values.size, values::get) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt deleted file mode 100644 index 4c2b5c73c..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixFeatures.kt +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.linear - -import space.kscience.kmath.nd.StructureFeature - -/** - * A marker interface representing some properties of matrices or additional transformations of them. Features are used - * to optimize matrix operations performance in some cases or retrieve the APIs. - */ -public interface MatrixFeature: StructureFeature - -/** - * Matrices with this feature are considered to have only diagonal non-null elements. - */ -public interface DiagonalFeature : MatrixFeature { - public companion object : DiagonalFeature -} - -/** - * Matrices with this feature have all zero elements. - */ -public object ZeroFeature : DiagonalFeature - -/** - * Matrices with this feature have unit elements on diagonal and zero elements in all other places. - */ -public object UnitFeature : DiagonalFeature - -/** - * 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 { - /** - * The inverse matrix of the matrix that owns this feature. - */ - public val inverse: Matrix -} - -/** - * Matrices with this feature can compute their determinant. - * - * @param T the type of matrices' items. - */ -public interface DeterminantFeature : MatrixFeature { - /** - * The determinant of the matrix that owns this feature. - */ - public val determinant: T -} - -/** - * Produces a [DeterminantFeature] where the [DeterminantFeature.determinant] is [determinant]. - * - * @param determinant the value of determinant. - * @return a new [DeterminantFeature]. - */ -@Suppress("FunctionName") -public fun DeterminantFeature(determinant: T): DeterminantFeature = object : DeterminantFeature { - override val determinant: T = determinant -} - -/** - * Matrices with this feature are lower triangular ones. - */ -public object LFeature : MatrixFeature - -/** - * Matrices with this feature are upper triangular ones. - */ -public object UFeature : MatrixFeature - -/** - * Matrices with this feature support LU factorization: *a = [l] · [u]* where *a* is the owning matrix. - * - * @param T the type of matrices' items. - */ -public interface LUDecompositionFeature : MatrixFeature { - /** - * The lower triangular matrix in this decomposition. It may have [LFeature]. - */ - public val l: Matrix - - /** - * The upper triangular matrix in this decomposition. It may have [UFeature]. - */ - public val u: Matrix -} - -/** - * Matrices with this feature support LU factorization with partial pivoting: *[p] · a = [l] · [u]* where - * *a* is the owning matrix. - * - * @param T the type of matrices' items. - */ -public interface LupDecompositionFeature : MatrixFeature { - /** - * The lower triangular matrix in this decomposition. It may have [LFeature]. - */ - public val l: Matrix - - /** - * The upper triangular matrix in this decomposition. It may have [UFeature]. - */ - public val u: Matrix - - /** - * The permutation matrix in this decomposition. - */ - public val p: Matrix -} - -/** - * Matrices with this feature are orthogonal ones: *a · aT = u* where *a* is the owning matrix, *u* - * is the unit matrix ([UnitFeature]). - */ -public object OrthogonalFeature : MatrixFeature - -/** - * Matrices with this feature support QR factorization: *a = [q] · [r]* where *a* is the owning matrix. - * - * @param T the type of matrices' items. - */ -public interface QRDecompositionFeature : MatrixFeature { - /** - * The orthogonal matrix in this decomposition. It may have [OrthogonalFeature]. - */ - public val q: Matrix - - /** - * The upper triangular matrix in this decomposition. It may have [UFeature]. - */ - public val r: Matrix -} - -/** - * Matrices with this feature support Cholesky factorization: *a = [l] · [l]H* where *a* is the - * owning matrix. - * - * @param T the type of matrices' items. - */ -public interface CholeskyDecompositionFeature : MatrixFeature { - /** - * The triangular matrix in this decomposition. It may have either [UFeature] or [LFeature]. - */ - public val l: Matrix -} - -/** - * Matrices with this feature support SVD: *a = [u] · [s] · [v]H* where *a* is the owning - * matrix. - * - * @param T the type of matrices' items. - */ -public interface SingularValueDecompositionFeature : MatrixFeature { - /** - * The matrix in this decomposition. It is unitary, and it consists from left singular vectors. - */ - public val u: Matrix - - /** - * The matrix in this decomposition. Its main diagonal elements are singular values. - */ - public val s: Matrix - - /** - * The matrix in this decomposition. It is unitary, and it consists from right singular vectors. - */ - public val v: Matrix - - /** - * The buffer of singular values of this SVD. - */ - public val singularValues: Point -} - -//TODO add sparse matrix feature 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 deleted file mode 100644 index e5448899b..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/MatrixWrapper.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.linear - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.StructureFeature -import space.kscience.kmath.nd.getFeature -import space.kscience.kmath.operations.Ring -import kotlin.reflect.KClass - -/** - * A [Matrix] that holds [MatrixFeature] objects. - * - * @param T the type of items. - */ -public class MatrixWrapper internal constructor( - public val origin: Matrix, - public val features: Set, -) : Matrix by origin { - - /** - * Get the first feature matching given class. Does not guarantee that matrix has only one feature matching the - * criteria. - */ - @UnstableKMathAPI - @Suppress("UNCHECKED_CAST") - override fun getFeature(type: KClass): F? = - features.singleOrNull(type::isInstance) as? F - ?: origin.getFeature(type) - - override fun toString(): String = "MatrixWrapper(matrix=$origin, features=$features)" -} - -/** - * Return the original matrix. If this is a wrapper, return its origin. If not, this matrix. - * Origin does not necessary store all features. - */ -@UnstableKMathAPI -public val Matrix.origin: Matrix - get() = (this as? MatrixWrapper)?.origin ?: this - -/** - * Add a single feature to a [Matrix] - */ -public operator fun Matrix.plus(newFeature: MatrixFeature): MatrixWrapper = if (this is MatrixWrapper) { - MatrixWrapper(origin, features + newFeature) -} else { - MatrixWrapper(this, setOf(newFeature)) -} - -/** - * Add a collection of features to a [Matrix] - */ -public operator fun Matrix.plus(newFeatures: Collection): MatrixWrapper = - if (this is MatrixWrapper) { - MatrixWrapper(origin, features + newFeatures) - } else { - MatrixWrapper(this, newFeatures.toSet()) - } - -/** - * Diagonal matrix of ones. The matrix is virtual no actual matrix is created. - */ -public fun LinearSpace>.one( - rows: Int, - columns: Int, -): Matrix = VirtualMatrix(rows, columns) { i, j -> - if (i == j) elementAlgebra.one else elementAlgebra.zero -} + UnitFeature - - -/** - * A virtual matrix of zeroes - */ -public fun LinearSpace>.zero( - rows: Int, - columns: Int, -): Matrix = VirtualMatrix(rows, columns) { _, _ -> - elementAlgebra.zero -} + ZeroFeature - -public class TransposedFeature(public val original: Matrix) : MatrixFeature - -/** - * Create a virtual transposed matrix without copying anything. `A.transpose().transpose() === A` - */ -@OptIn(UnstableKMathAPI::class) -public fun Matrix.transpose(): Matrix = getFeature>()?.original ?: (VirtualMatrix( - colNum, - rowNum, -) { i, j -> get(j, i) } + TransposedFeature(this)) \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt deleted file mode 100644 index c3327bc6b..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/linear/VirtualMatrix.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.linear - -/** - * The matrix where each element is evaluated each time when is being accessed. - * - * @property generator the function that provides elements. - */ -public class VirtualMatrix( - override val rowNum: Int, - override val colNum: Int, - public val generator: (i: Int, j: Int) -> T, -) : Matrix { - - override val shape: IntArray get() = intArrayOf(rowNum, colNum) - - override operator fun get(i: Int, j: Int): T = generator(i, j) -} 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 deleted file mode 100644 index a643dc0bf..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/annotations.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.misc - -/** - * Marks declarations that are still experimental in the KMath APIs, which means that the design of the corresponding - * 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 -@Retention(value = AnnotationRetention.BINARY) -@RequiresOptIn("This API is unstable and could change in future", RequiresOptIn.Level.WARNING) -public annotation class UnstableKMathAPI - -/** - * 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 -@Retention(value = AnnotationRetention.BINARY) -@RequiresOptIn( - "Refer to the documentation to use this API in performance-critical code", - RequiresOptIn.Level.WARNING -) -public annotation class PerformancePitfall( - val message: String = "Potential performance problem" -) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt deleted file mode 100644 index 413f44960..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/cumulative.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.misc - -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import kotlin.jvm.JvmName - -/** - * Generic cumulative operation on iterator. - * - * @param T the type of initial iterable. - * @param R the type of resulting iterable. - * @param initial lazy evaluated. - */ -public inline fun Iterator.cumulative(initial: R, crossinline operation: (R, T) -> R): Iterator = - object : Iterator { - var state: R = initial - - override fun hasNext(): Boolean = this@cumulative.hasNext() - - override fun next(): R { - state = operation(state, this@cumulative.next()) - return state - } - } - -public inline fun Iterable.cumulative(initial: R, crossinline operation: (R, T) -> R): Iterable = - Iterable { this@cumulative.iterator().cumulative(initial, operation) } - -public inline fun Sequence.cumulative(initial: R, crossinline operation: (R, T) -> R): Sequence = - Sequence { this@cumulative.iterator().cumulative(initial, operation) } - -public inline fun List.cumulative(initial: R, crossinline operation: (R, T) -> R): List = - iterator().cumulative(initial, operation).asSequence().toList() - -//Cumulative sum - -/** - * Cumulative sum with custom space - */ -public fun Iterable.cumulativeSum(group: Ring): Iterable = - group { cumulative(zero) { element: T, sum: T -> sum + element } } - -@JvmName("cumulativeSumOfDouble") -public fun Iterable.cumulativeSum(): Iterable = cumulative(0.0) { element, sum -> sum + element } - -@JvmName("cumulativeSumOfInt") -public fun Iterable.cumulativeSum(): Iterable = cumulative(0) { element, sum -> sum + element } - -@JvmName("cumulativeSumOfLong") -public fun Iterable.cumulativeSum(): Iterable = cumulative(0L) { element, sum -> sum + element } - -public fun Sequence.cumulativeSum(group: Ring): Sequence = - group { cumulative(zero) { element: T, sum: T -> sum + element } } - -@JvmName("cumulativeSumOfDouble") -public fun Sequence.cumulativeSum(): Sequence = cumulative(0.0) { element, sum -> sum + element } - -@JvmName("cumulativeSumOfInt") -public fun Sequence.cumulativeSum(): Sequence = cumulative(0) { element, sum -> sum + element } - -@JvmName("cumulativeSumOfLong") -public fun Sequence.cumulativeSum(): Sequence = cumulative(0L) { element, sum -> sum + element } - -public fun List.cumulativeSum(group: Ring): List = - group { cumulative(zero) { element: T, sum: T -> sum + element } } - -@JvmName("cumulativeSumOfDouble") -public fun List.cumulativeSum(): List = cumulative(0.0) { element, sum -> sum + element } - -@JvmName("cumulativeSumOfInt") -public fun List.cumulativeSum(): List = cumulative(0) { element, sum -> sum + element } - -@JvmName("cumulativeSumOfLong") -public fun List.cumulativeSum(): List = cumulative(0L) { element, sum -> sum + element } diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt deleted file mode 100644 index e048eb746..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.misc - -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 deleted file mode 100644 index b925c2642..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/AlgebraND.kt +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.* -import kotlin.reflect.KClass - -/** - * An exception is thrown when the expected and actual shape of NDArray differ. - * - * @property expected the expected shape. - * @property actual the actual shape. - */ -public class ShapeMismatchException(public val expected: IntArray, public val actual: IntArray) : - RuntimeException("Shape ${actual.contentToString()} doesn't fit in expected shape ${expected.contentToString()}.") - -/** - * The base interface for all ND-algebra implementations. - * - * @param T the type of ND-structure element. - * @param C the type of the element context. - */ -public interface AlgebraND> { - /** - * The shape of ND-structures this algebra operates on. - */ - public val shape: IntArray - - /** - * The algebra over elements of ND structure. - */ - public val elementContext: C - - /** - * Produces a new NDStructure using given initializer function. - */ - public fun produce(initializer: C.(IntArray) -> T): StructureND - - /** - * Maps elements from one structure to another one by applying [transform] to them. - */ - public fun StructureND.map(transform: C.(T) -> T): StructureND - - /** - * Maps elements from one structure to another one by applying [transform] to them alongside with their indices. - */ - public fun StructureND.mapIndexed(transform: C.(index: IntArray, T) -> T): StructureND - - /** - * Combines two structures into one. - */ - public fun combine(a: StructureND, b: StructureND, transform: C.(T, T) -> T): StructureND - - /** - * Element-wise invocation of function working on [T] on a [StructureND]. - */ - public operator fun Function1.invoke(structure: StructureND): StructureND = - structure.map { value -> this@invoke(value) } - - /** - * 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. - * @param type the [KClass] instance of [F]. - * @return a feature object or `null` if it isn't present. - */ - @UnstableKMathAPI - public fun getFeature(structure: StructureND, type: KClass): F? = - structure.getFeature(type) - - public companion object -} - - -/** - * 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. - * @return a feature object or `null` if it isn't present. - */ -@UnstableKMathAPI -public inline fun AlgebraND.getFeature(structure: StructureND): F? = - getFeature(structure, F::class) - -/** - * Checks if given elements are consistent with this context. - * - * @param structures the structures to check. - * @return the array of valid structures. - */ -internal fun > AlgebraND.checkShape(vararg structures: StructureND): Array> = - structures - .map(StructureND::shape) - .singleOrNull { !shape.contentEquals(it) } - ?.let>> { throw ShapeMismatchException(shape, it) } - ?: structures - -/** - * Checks if given element is consistent with this context. - * - * @param element the structure to check. - * @return the valid structure. - */ -internal fun > AlgebraND.checkShape(element: StructureND): StructureND { - if (!element.shape.contentEquals(shape)) throw ShapeMismatchException(shape, element.shape) - return element -} - -/** - * Space of [StructureND]. - * - * @param T the type of the element contained in ND structure. - * @param S the type of group over structure elements. - */ -public interface GroupND> : Group>, AlgebraND { - /** - * Element-wise addition. - * - * @param a the augend. - * @param b the addend. - * @return the sum. - */ - override fun add(a: StructureND, b: StructureND): StructureND = - combine(a, b) { aValue, bValue -> add(aValue, bValue) } - - // TODO move to extensions after KEEP-176 - - /** - * Adds an ND structure to an element of it. - * - * @receiver the augend. - * @param arg the addend. - * @return the sum. - */ - public operator fun StructureND.plus(arg: T): StructureND = this.map { value -> add(arg, value) } - - /** - * Subtracts an element from ND structure of it. - * - * @receiver the dividend. - * @param arg the divisor. - * @return the quotient. - */ - public operator fun StructureND.minus(arg: T): StructureND = this.map { value -> add(arg, -value) } - - /** - * Adds an element to ND structure of it. - * - * @receiver the augend. - * @param arg the addend. - * @return the sum. - */ - public operator fun T.plus(arg: StructureND): StructureND = arg.map { value -> add(this@plus, value) } - - /** - * Subtracts an ND structure from an element of it. - * - * @receiver the dividend. - * @param arg the divisor. - * @return the quotient. - */ - public operator fun T.minus(arg: StructureND): StructureND = arg.map { value -> add(-this@minus, value) } - - public companion object -} - -/** - * Ring of [StructureND]. - * - * @param T the type of the element contained in ND structure. - * @param R the type of ring over structure elements. - */ -public interface RingND> : Ring>, GroupND { - /** - * Element-wise multiplication. - * - * @param a the multiplicand. - * @param b the multiplier. - * @return the product. - */ - override fun multiply(a: StructureND, b: StructureND): StructureND = - combine(a, b) { aValue, bValue -> multiply(aValue, bValue) } - - //TODO move to extensions after KEEP-176 - - /** - * Multiplies an ND structure by an element of it. - * - * @receiver the multiplicand. - * @param arg the multiplier. - * @return the product. - */ - public operator fun StructureND.times(arg: T): StructureND = this.map { value -> multiply(arg, value) } - - /** - * Multiplies an element by a ND structure of it. - * - * @receiver the multiplicand. - * @param arg the multiplier. - * @return the product. - */ - public operator fun T.times(arg: StructureND): StructureND = arg.map { value -> multiply(this@times, value) } - - public companion object -} - -/** - * Field of [StructureND]. - * - * @param T the type of the element contained in ND structure. - * @param F the type field over structure elements. - */ -public interface FieldND> : Field>, RingND { - /** - * Element-wise division. - * - * @param a the dividend. - * @param b the divisor. - * @return the quotient. - */ - override fun divide(a: StructureND, b: StructureND): StructureND = - combine(a, b) { aValue, bValue -> divide(aValue, bValue) } - - //TODO move to extensions after KEEP-176 - /** - * Divides an ND structure by an element of it. - * - * @receiver the dividend. - * @param arg the divisor. - * @return the quotient. - */ - public operator fun StructureND.div(arg: T): StructureND = this.map { value -> divide(arg, value) } - - /** - * Divides an element by an ND structure of it. - * - * @receiver the dividend. - * @param arg the divisor. - * @return the quotient. - */ - public operator fun T.div(arg: StructureND): 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() -// -// /** -// * Create a nd-field for [Double] values or pull it from cache if it was created previously. -// */ -// public fun real(vararg shape: Int): RealNDField = realNDFieldCache.getOrPut(shape) { RealNDField(shape) } -// -// /** -// * Create an ND field with boxing generic buffer. -// */ -// public fun > boxing( -// field: F, -// vararg shape: Int, -// bufferFactory: BufferFactory = Buffer.Companion::boxing, -// ): BufferedNDField = BufferedNDField(shape, field, bufferFactory) -// -// /** -// * Create a most suitable implementation for nd-field using reified class. -// */ -// @Suppress("UNCHECKED_CAST") -// public inline fun > auto(field: F, vararg shape: Int): NDField = -// when { -// T::class == Double::class -> real(*shape) as NDField -// T::class == Complex::class -> complex(*shape) as BufferedNDField -// else -> BoxingNDField(shape, field, Buffer.Companion::auto) -// } -// } -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt deleted file mode 100644 index 9ece51ff8..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferAlgebraND.kt +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferFactory -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -public interface BufferAlgebraND> : AlgebraND { - public val strides: Strides - public val bufferFactory: BufferFactory - - override fun produce(initializer: A.(IntArray) -> T): BufferND = BufferND( - strides, - bufferFactory(strides.linearSize) { offset -> - elementContext.initializer(strides.index(offset)) - } - ) - - public val StructureND.buffer: Buffer - get() = when { - !shape.contentEquals(this@BufferAlgebraND.shape) -> throw ShapeMismatchException( - this@BufferAlgebraND.shape, - shape - ) - this is BufferND && this.strides == this@BufferAlgebraND.strides -> this.buffer - else -> bufferFactory(strides.linearSize) { offset -> get(strides.index(offset)) } - } - - override fun StructureND.map(transform: A.(T) -> T): BufferND { - val buffer = bufferFactory(strides.linearSize) { offset -> - elementContext.transform(buffer[offset]) - } - return BufferND(strides, buffer) - } - - override fun StructureND.mapIndexed(transform: A.(index: IntArray, T) -> T): BufferND { - val buffer = bufferFactory(strides.linearSize) { offset -> - elementContext.transform( - strides.index(offset), - buffer[offset] - ) - } - return BufferND(strides, buffer) - } - - override fun combine(a: StructureND, b: StructureND, transform: A.(T, T) -> T): BufferND { - val buffer = bufferFactory(strides.linearSize) { offset -> - elementContext.transform(a.buffer[offset], b.buffer[offset]) - } - return BufferND(strides, buffer) - } -} - -public open class BufferedGroupND>( - final override val shape: IntArray, - final override val elementContext: A, - final override val bufferFactory: BufferFactory, -) : GroupND, BufferAlgebraND { - override val strides: Strides = DefaultStrides(shape) - override val zero: BufferND by lazy { produce { zero } } - override fun StructureND.unaryMinus(): StructureND = produce { -get(it) } -} - -public open class BufferedRingND>( - shape: IntArray, - elementContext: R, - bufferFactory: BufferFactory, -) : BufferedGroupND(shape, elementContext, bufferFactory), RingND { - override val one: BufferND by lazy { produce { one } } -} - -public open class BufferedFieldND>( - shape: IntArray, - elementContext: R, - bufferFactory: BufferFactory, -) : BufferedRingND(shape, elementContext, bufferFactory), FieldND { - - override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } -} - -// group factories -public fun > AlgebraND.Companion.group( - space: A, - bufferFactory: BufferFactory, - vararg shape: Int, -): BufferedGroupND = BufferedGroupND(shape, space, bufferFactory) - -public inline fun , R> A.ndGroup( - noinline bufferFactory: BufferFactory, - vararg shape: Int, - action: BufferedGroupND.() -> R, -): R { - contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return AlgebraND.group(this, bufferFactory, *shape).run(action) -} - -//ring factories -public fun > AlgebraND.Companion.ring( - ring: A, - bufferFactory: BufferFactory, - vararg shape: Int, -): BufferedRingND = BufferedRingND(shape, ring, bufferFactory) - -public inline fun , R> A.ndRing( - noinline bufferFactory: BufferFactory, - vararg shape: Int, - action: BufferedRingND.() -> R, -): R { - contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return AlgebraND.ring(this, bufferFactory, *shape).run(action) -} - -//field factories -public fun > AlgebraND.Companion.field( - field: A, - bufferFactory: BufferFactory, - vararg shape: Int, -): BufferedFieldND = BufferedFieldND(shape, field, bufferFactory) - -@Suppress("UNCHECKED_CAST") -public inline fun > AlgebraND.Companion.auto( - field: A, - vararg shape: Int, -): FieldND = when (field) { - DoubleField -> DoubleFieldND(shape) as FieldND - else -> BufferedFieldND(shape, field, Buffer.Companion::auto) -} - -public inline fun , R> A.ndField( - noinline bufferFactory: BufferFactory, - vararg shape: Int, - action: BufferedFieldND.() -> R, -): R { - contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return AlgebraND.field(this, bufferFactory, *shape).run(action) -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt deleted file mode 100644 index 694e0ceae..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/BufferND.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferFactory -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.MutableBufferFactory - -/** - * Represents [StructureND] over [Buffer]. - * - * @param T the type of items. - * @param strides The strides to access elements of [Buffer] by linear indices. - * @param buffer The underlying buffer. - */ -public open class BufferND( - public val strides: Strides, - public val buffer: Buffer, -) : StructureND { - - init { - if (strides.linearSize != buffer.size) { - error("Expected buffer side of ${strides.linearSize}, but found ${buffer.size}") - } - } - - override operator fun get(index: IntArray): T = buffer[strides.offset(index)] - - override val shape: IntArray get() = strides.shape - - @PerformancePitfall - override fun elements(): Sequence> = strides.indices().map { - it to this[it] - } - - override fun toString(): String = StructureND.toString(this) -} - -/** - * Transform structure to a new structure using provided [BufferFactory] and optimizing if argument is [BufferND] - */ -public inline fun StructureND.mapToBuffer( - factory: BufferFactory = Buffer.Companion::auto, - crossinline transform: (T) -> R, -): BufferND { - return if (this is BufferND) - BufferND(this.strides, factory.invoke(strides.linearSize) { transform(buffer[it]) }) - else { - val strides = DefaultStrides(shape) - BufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) - } -} - -/** - * Represents [MutableStructureND] over [MutableBuffer]. - * - * @param T the type of items. - * @param strides The strides to access elements of [MutableBuffer] by linear indices. - * @param mutableBuffer The underlying buffer. - */ -public class MutableBufferND( - strides: Strides, - public val mutableBuffer: MutableBuffer, -) : MutableStructureND, BufferND(strides, mutableBuffer) { - override fun set(index: IntArray, value: T) { - mutableBuffer[strides.offset(index)] = value - } -} - -/** - * Transform structure to a new structure using provided [MutableBufferFactory] and optimizing if argument is [MutableBufferND] - */ -public inline fun MutableStructureND.mapToMutableBuffer( - factory: MutableBufferFactory = MutableBuffer.Companion::auto, - crossinline transform: (T) -> R, -): MutableBufferND { - return if (this is MutableBufferND) - MutableBufferND(this.strides, factory.invoke(strides.linearSize) { transform(mutableBuffer[it]) }) - else { - val strides = DefaultStrides(shape) - MutableBufferND(strides, factory.invoke(strides.linearSize) { transform(get(strides.index(it))) }) - } -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt deleted file mode 100644 index a448e351e..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/DoubleFieldND.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.NumbersAddOperations -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.structures.DoubleBuffer -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -@OptIn(UnstableKMathAPI::class) -public class DoubleFieldND( - shape: IntArray, -) : BufferedFieldND(shape, DoubleField, ::DoubleBuffer), - NumbersAddOperations>, - ScaleOperations>, - ExtendedField> { - - override val zero: BufferND by lazy { produce { zero } } - override val one: BufferND by lazy { produce { one } } - - override fun number(value: Number): BufferND { - val d = value.toDouble() // minimize conversions - return produce { d } - } - - override val StructureND.buffer: DoubleBuffer - get() = when { - !shape.contentEquals(this@DoubleFieldND.shape) -> throw ShapeMismatchException( - this@DoubleFieldND.shape, - shape - ) - this is BufferND && this.strides == this@DoubleFieldND.strides -> this.buffer as DoubleBuffer - else -> DoubleBuffer(strides.linearSize) { offset -> get(strides.index(offset)) } - } - - @Suppress("OVERRIDE_BY_INLINE") - override inline fun StructureND.map( - transform: DoubleField.(Double) -> Double, - ): BufferND { - val buffer = DoubleBuffer(strides.linearSize) { offset -> DoubleField.transform(buffer.array[offset]) } - return BufferND(strides, buffer) - } - - @Suppress("OVERRIDE_BY_INLINE") - override inline fun produce(initializer: DoubleField.(IntArray) -> Double): BufferND { - val array = DoubleArray(strides.linearSize) { offset -> - val index = strides.index(offset) - DoubleField.initializer(index) - } - return BufferND(strides, DoubleBuffer(array)) - } - - @Suppress("OVERRIDE_BY_INLINE") - override inline fun StructureND.mapIndexed( - transform: DoubleField.(index: IntArray, Double) -> Double, - ): BufferND = BufferND( - strides, - buffer = DoubleBuffer(strides.linearSize) { offset -> - DoubleField.transform( - strides.index(offset), - buffer.array[offset] - ) - }) - - @Suppress("OVERRIDE_BY_INLINE") - override inline fun combine( - a: StructureND, - b: StructureND, - transform: DoubleField.(Double, Double) -> Double, - ): BufferND { - val buffer = DoubleBuffer(strides.linearSize) { offset -> - DoubleField.transform(a.buffer.array[offset], b.buffer.array[offset]) - } - return BufferND(strides, buffer) - } - - override fun scale(a: StructureND, value: Double): StructureND = a.map { it * value } - - override fun power(arg: StructureND, pow: Number): BufferND = arg.map { power(it, pow) } - - override fun exp(arg: StructureND): BufferND = arg.map { exp(it) } - override fun ln(arg: StructureND): BufferND = arg.map { ln(it) } - - override fun sin(arg: StructureND): BufferND = arg.map { sin(it) } - override fun cos(arg: StructureND): BufferND = arg.map { cos(it) } - override fun tan(arg: StructureND): BufferND = arg.map { tan(it) } - override fun asin(arg: StructureND): BufferND = arg.map { asin(it) } - override fun acos(arg: StructureND): BufferND = arg.map { acos(it) } - override fun atan(arg: StructureND): BufferND = arg.map { atan(it) } - - override fun sinh(arg: StructureND): BufferND = arg.map { sinh(it) } - override fun cosh(arg: StructureND): BufferND = arg.map { cosh(it) } - override fun tanh(arg: StructureND): BufferND = arg.map { tanh(it) } - override fun asinh(arg: StructureND): BufferND = arg.map { asinh(it) } - override fun acosh(arg: StructureND): BufferND = arg.map { acosh(it) } - override fun atanh(arg: StructureND): BufferND = arg.map { atanh(it) } -} - -public fun AlgebraND.Companion.real(vararg shape: Int): DoubleFieldND = DoubleFieldND(shape) - -/** - * Produce a context for n-dimensional operations inside this real field - */ -public inline fun DoubleField.nd(vararg shape: Int, action: DoubleFieldND.() -> R): R { - contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return DoubleFieldND(shape).run(action) -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt deleted file mode 100644 index f96978cfc..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/ShortRingND.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.NumbersAddOperations -import space.kscience.kmath.operations.ShortRing -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.ShortBuffer -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -@OptIn(UnstableKMathAPI::class) -public class ShortRingND( - shape: IntArray, -) : BufferedRingND(shape, ShortRing, Buffer.Companion::auto), - NumbersAddOperations> { - - override val zero: BufferND by lazy { produce { zero } } - override val one: BufferND by lazy { produce { one } } - - override fun number(value: Number): BufferND { - val d = value.toShort() // minimize conversions - return produce { d } - } -} - -/** - * Fast element production using function inlining. - */ -public inline fun BufferedRingND.produceInline(crossinline initializer: ShortRing.(Int) -> Short): BufferND = - BufferND(strides, ShortBuffer(ShortArray(strides.linearSize) { offset -> ShortRing.initializer(offset) })) - -public inline fun ShortRing.nd(vararg shape: Int, action: ShortRingND.() -> R): R { - contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) } - return ShortRingND(shape).run(action) -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt deleted file mode 100644 index d0e2354d2..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure1D.kt +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.asMutableBuffer -import space.kscience.kmath.structures.asSequence -import kotlin.jvm.JvmInline - -/** - * A structure that is guaranteed to be one-dimensional - */ -public interface Structure1D : StructureND, Buffer { - override val dimension: Int get() = 1 - - override operator fun get(index: IntArray): T { - require(index.size == 1) { "Index dimension mismatch. Expected 1 but found ${index.size}" } - return get(index[0]) - } - - override operator fun iterator(): Iterator = (0 until size).asSequence().map(::get).iterator() - - public companion object -} - -/** - * A mutable structure that is guaranteed to be one-dimensional - */ -public interface MutableStructure1D : Structure1D, MutableStructureND, MutableBuffer { - override operator fun set(index: IntArray, value: T) { - require(index.size == 1) { "Index dimension mismatch. Expected 1 but found ${index.size}" } - set(index[0], value) - } -} - -/** - * A 1D wrapper for nd-structure - */ -@JvmInline -private value class Structure1DWrapper(val structure: StructureND) : Structure1D { - override val shape: IntArray get() = structure.shape - override val size: Int get() = structure.shape[0] - - override operator fun get(index: Int): T = structure[index] - - @PerformancePitfall - override fun elements(): Sequence> = structure.elements() -} - -/** - * A 1D wrapper for a mutable nd-structure - */ -private class MutableStructure1DWrapper(val structure: MutableStructureND) : MutableStructure1D { - override val shape: IntArray get() = structure.shape - override val size: Int get() = structure.shape[0] - - @PerformancePitfall - override fun elements(): Sequence> = structure.elements() - - override fun get(index: Int): T = structure[index] - override fun set(index: Int, value: T) { - structure[intArrayOf(index)] = value - } - - @PerformancePitfall - override fun copy(): MutableBuffer = structure - .elements() - .map(Pair::second) - .toMutableList() - .asMutableBuffer() -} - - -/** - * A structure wrapper for buffer - */ -@JvmInline -private value class Buffer1DWrapper(val buffer: Buffer) : Structure1D { - override val shape: IntArray get() = intArrayOf(buffer.size) - override val size: Int get() = buffer.size - - @PerformancePitfall - override fun elements(): Sequence> = buffer.asSequence().mapIndexed { index, value -> - intArrayOf(index) to value - } - - override operator fun get(index: Int): T = buffer[index] -} - -internal class MutableBuffer1DWrapper(val buffer: MutableBuffer) : MutableStructure1D { - override val shape: IntArray get() = intArrayOf(buffer.size) - override val size: Int get() = buffer.size - - @PerformancePitfall - override fun elements(): Sequence> = buffer.asSequence().mapIndexed { index, value -> - intArrayOf(index) to value - } - - override operator fun get(index: Int): T = buffer[index] - override fun set(index: Int, value: T) { - buffer[index] = value - } - - override fun copy(): MutableBuffer = buffer.copy() -} - -/** - * Represent a [StructureND] as [Structure1D]. Throw error in case of dimension mismatch. - */ -public fun StructureND.as1D(): Structure1D = this as? Structure1D ?: if (shape.size == 1) { - when (this) { - is BufferND -> Buffer1DWrapper(this.buffer) - else -> Structure1DWrapper(this) - } -} else error("Can't create 1d-structure from ${shape.size}d-structure") - -public fun MutableStructureND.as1D(): MutableStructure1D = - this as? MutableStructure1D ?: if (shape.size == 1) { - MutableStructure1DWrapper(this) - } else error("Can't create 1d-structure from ${shape.size}d-structure") - -/** - * Represent this buffer as 1D structure - */ -public fun Buffer.asND(): Structure1D = Buffer1DWrapper(this) - -/** - * Expose inner buffer of this [Structure1D] if possible - */ -internal fun Structure1D.unwrap(): Buffer = when { - this is Buffer1DWrapper -> buffer - this is Structure1DWrapper && structure is BufferND -> structure.buffer - else -> this -} - diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt deleted file mode 100644 index 7fb8ea251..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/Structure2D.kt +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.MutableListBuffer -import space.kscience.kmath.structures.VirtualBuffer -import kotlin.jvm.JvmInline -import kotlin.reflect.KClass - -/** - * A structure that is guaranteed to be two-dimensional. - * - * @param T the type of items. - */ -public interface Structure2D : StructureND { - /** - * The number of rows in this structure. - */ - public val rowNum: Int - - /** - * The number of columns in this structure. - */ - public val colNum: Int - - override val shape: IntArray get() = intArrayOf(rowNum, colNum) - - /** - * The buffer of rows of this structure. It gets elements from the structure dynamically. - */ - @PerformancePitfall - public val rows: List> - get() = List(rowNum) { i -> VirtualBuffer(colNum) { j -> get(i, j) } } - - /** - * The buffer of columns of this structure. It gets elements from the structure dynamically. - */ - @PerformancePitfall - public val columns: List> - get() = List(colNum) { j -> VirtualBuffer(rowNum) { i -> get(i, j) } } - - /** - * Retrieves an element from the structure by two indices. - * - * @param i the first index. - * @param j the second index. - * @return an element. - */ - public operator fun get(i: Int, j: Int): T - - override operator fun get(index: IntArray): T { - require(index.size == 2) { "Index dimension mismatch. Expected 2 but found ${index.size}" } - return get(index[0], index[1]) - } - - @PerformancePitfall - override fun elements(): Sequence> = sequence { - for (i in 0 until rowNum) - for (j in 0 until colNum) yield(intArrayOf(i, j) to get(i, j)) - } - - public companion object -} - -/** - * Represents mutable [Structure2D]. - */ -public interface MutableStructure2D : Structure2D, MutableStructureND { - /** - * Inserts an item at the specified indices. - * - * @param i the first index. - * @param j the second index. - * @param value the value. - */ - public operator fun set(i: Int, j: Int, value: T) - - /** - * The buffer of rows of this structure. It gets elements from the structure dynamically. - */ - @PerformancePitfall - override val rows: List> - get() = List(rowNum) { i -> MutableBuffer1DWrapper(MutableListBuffer(colNum) { j -> get(i, j) })} - - /** - * The buffer of columns of this structure. It gets elements from the structure dynamically. - */ - @PerformancePitfall - override val columns: List> - get() = List(colNum) { j -> MutableBuffer1DWrapper(MutableListBuffer(rowNum) { i -> get(i, j) }) } -} - -/** - * A 2D wrapper for nd-structure - */ -@JvmInline -private value class Structure2DWrapper(val structure: StructureND) : Structure2D { - override val shape: IntArray get() = structure.shape - - override val rowNum: Int get() = shape[0] - override val colNum: Int get() = shape[1] - - override operator fun get(i: Int, j: Int): T = structure[i, j] - - @UnstableKMathAPI - override fun getFeature(type: KClass): F? = structure.getFeature(type) - - @PerformancePitfall - override fun elements(): Sequence> = structure.elements() -} - -/** - * A 2D wrapper for a mutable nd-structure - */ -private class MutableStructure2DWrapper(val structure: MutableStructureND): MutableStructure2D -{ - override val shape: IntArray get() = structure.shape - - override val rowNum: Int get() = shape[0] - override val colNum: Int get() = shape[1] - - override operator fun get(i: Int, j: Int): T = structure[i, j] - - override fun set(index: IntArray, value: T) { - structure[index] = value - } - - override operator fun set(i: Int, j: Int, value: T){ - structure[intArrayOf(i, j)] = value - } - - @PerformancePitfall - override fun elements(): Sequence> = structure.elements() - - override fun equals(other: Any?): Boolean = false - - override fun hashCode(): Int = 0 -} - -/** - * 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") -} - -/** - * Expose inner [StructureND] if possible - */ -internal fun Structure2D.unwrap(): StructureND = - if (this is Structure2DWrapper) structure - else this - -internal fun MutableStructure2D.unwrap(): MutableStructureND = - if (this is MutableStructure2DWrapper) structure else this - diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt deleted file mode 100644 index 45153f7bd..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/nd/StructureND.kt +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.nd - -import space.kscience.kmath.linear.LinearSpace -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferFactory -import kotlin.jvm.JvmName -import kotlin.native.concurrent.ThreadLocal -import kotlin.reflect.KClass - -public interface StructureFeature - -/** - * 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. - * - * StructureND is in general identity-free. [StructureND.contentEquals] should be used in tests to compare contents. - * - * @param T the type of items. - */ -public interface StructureND { - /** - * 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 - - /** - * The count of dimensions in this structure. It should be equal to size of [shape]. - */ - public val dimension: Int get() = shape.size - - /** - * Returns the value at the specified indices. - * - * @param index the indices. - * @return the value. - */ - public operator fun get(index: IntArray): T - - /** - * Returns the sequence of all the elements associated by their indices. - * - * @return the lazy sequence of pairs of indices to values. - */ - @PerformancePitfall - public fun elements(): Sequence> - - /** - * Feature is some additional structure information that allows to access it special properties or hints. - * If the feature is not present, `null` is returned. - */ - @UnstableKMathAPI - public fun getFeature(type: KClass): F? = null - - public companion object { - /** - * Indicates whether some [StructureND] is equal to another one. - */ - @PerformancePitfall - public fun contentEquals(st1: StructureND, st2: StructureND): Boolean { - if (st1 === st2) return true - - // fast comparison of buffers if possible - if (st1 is BufferND && st2 is BufferND && st1.strides == st2.strides) - return Buffer.contentEquals(st1.buffer, st2.buffer) - - //element by element comparison if it could not be avoided - return st1.elements().all { (index, value) -> value == st2[index] } - } - - /** - * Debug output to string - */ - public fun toString(structure: StructureND<*>): String { - val bufferRepr: String = when (structure.shape.size) { - 1 -> (0 until structure.shape[0]).map { structure[it] } - .joinToString(prefix = "[", postfix = "]", separator = ", ") - 2 -> (0 until structure.shape[0]).joinToString(prefix = "[", postfix = "]", separator = ", ") { i -> - (0 until structure.shape[1]).joinToString(prefix = "[", postfix = "]", separator = ", ") { j -> - structure[i, j].toString() - } - } - else -> "..." - } - val className = structure::class.simpleName ?: "StructureND" - - return "$className(shape=${structure.shape.contentToString()}, buffer=$bufferRepr)" - } - - /** - * Creates a NDStructure with explicit buffer factory. - * - * Strides should be reused if possible. - */ - public fun buffered( - strides: Strides, - bufferFactory: BufferFactory = Buffer.Companion::boxing, - initializer: (IntArray) -> T, - ): BufferND = BufferND(strides, bufferFactory(strides.linearSize) { i -> initializer(strides.index(i)) }) - - /** - * Inline create NDStructure with non-boxing buffer implementation if it is possible - */ - public inline fun auto( - strides: Strides, - crossinline initializer: (IntArray) -> T, - ): BufferND = BufferND(strides, Buffer.auto(strides.linearSize) { i -> initializer(strides.index(i)) }) - - public inline fun auto( - type: KClass, - strides: Strides, - crossinline initializer: (IntArray) -> T, - ): BufferND = BufferND(strides, Buffer.auto(type, strides.linearSize) { i -> initializer(strides.index(i)) }) - - public fun buffered( - shape: IntArray, - bufferFactory: BufferFactory = Buffer.Companion::boxing, - initializer: (IntArray) -> T, - ): BufferND = buffered(DefaultStrides(shape), bufferFactory, initializer) - - public inline fun auto( - shape: IntArray, - crossinline initializer: (IntArray) -> T, - ): BufferND = auto(DefaultStrides(shape), initializer) - - @JvmName("autoVarArg") - public inline fun auto( - vararg shape: Int, - crossinline initializer: (IntArray) -> T, - ): BufferND = - auto(DefaultStrides(shape), initializer) - - public inline fun auto( - type: KClass, - vararg shape: Int, - crossinline initializer: (IntArray) -> T, - ): BufferND = auto(type, DefaultStrides(shape), initializer) - } -} - -/** - * 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. - * - * @param index the indices. - * @return the value. - */ -public operator fun StructureND.get(vararg index: Int): T = get(index) - -@UnstableKMathAPI -public inline fun StructureND<*>.getFeature(): T? = getFeature(T::class) - -/** - * Represents mutable [StructureND]. - */ -public interface MutableStructureND : StructureND { - /** - * Inserts an item at the specified indices. - * - * @param index the indices. - * @param value the value. - */ - public operator fun set(index: IntArray, value: T) -} - -/** - * Transform a structure element-by element in place. - */ -@OptIn(PerformancePitfall::class) -public inline fun MutableStructureND.mapInPlace(action: (IntArray, T) -> T): Unit = - elements().forEach { (index, oldValue) -> this[index] = action(index, oldValue) } - -/** - * A way to convert ND indices to linear one and back. - */ -public interface Strides { - /** - * Shape of NDStructure - */ - public val shape: IntArray - - /** - * Array strides - */ - public val strides: IntArray - - /** - * Get linear index from multidimensional index - */ - public fun offset(index: IntArray): Int = index.mapIndexed { i, value -> - if (value < 0 || value >= shape[i]) throw IndexOutOfBoundsException("Index $value out of shape bounds: (0,${this.shape[i]})") - value * strides[i] - }.sum() - - /** - * Get multidimensional from linear - */ - public fun index(offset: Int): IntArray - - /** - * The size of linear buffer to accommodate all elements of ND-structure corresponding to strides - */ - public val linearSize: Int - - // TODO introduce a fast way to calculate index of the next element? - - /** - * Iterate over ND indices in a natural order - */ - public fun indices(): Sequence = (0 until linearSize).asSequence().map(::index) -} - -/** - * Simple implementation of [Strides]. - */ -public class DefaultStrides private constructor(override val shape: IntArray) : Strides { - override val linearSize: Int - get() = strides[shape.size] - - /** - * Strides for memory access - */ - override val strides: IntArray by lazy { - sequence { - var current = 1 - yield(1) - - shape.forEach { - current *= it - yield(current) - } - }.toList().toIntArray() - } - - override fun index(offset: Int): IntArray { - val res = IntArray(shape.size) - var current = offset - var strideIndex = strides.size - 2 - - while (strideIndex >= 0) { - res[strideIndex] = (current / strides[strideIndex]) - current %= strides[strideIndex] - strideIndex-- - } - - return res - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is DefaultStrides) return false - if (!shape.contentEquals(other.shape)) return false - return true - } - - override fun hashCode(): Int = shape.contentHashCode() - - @ThreadLocal - public companion object { - private val defaultStridesCache = HashMap() - - /** - * Cached builder for default strides - */ - public operator fun invoke(shape: IntArray): Strides = - defaultStridesCache.getOrPut(shape) { DefaultStrides(shape) } - } -} - -public inline fun StructureND.combine( - struct: StructureND, - crossinline block: (T, T) -> T, -): StructureND { - require(shape.contentEquals(struct.shape)) { "Shape mismatch in structure combination" } - return StructureND.auto(shape) { block(this[it], struct[it]) } -} 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 deleted file mode 100644 index daff58d9a..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/Algebra.kt +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.expressions.Symbol - -/** - * Stub for DSL the [Algebra] is. - */ -@DslMarker -public annotation class KMathContext - -/** - * Represents an algebraic structure. - * - * @param T the type of element of this structure. - */ -public interface Algebra { - /** - * Wraps a raw string to [T] object. This method is designed for three purposes: - * - * 1. Mathematical constants (`e`, `pi`). - * 1. Variables for expression-like contexts (`a`, `b`, `c`…). - * 1. Literals (`{1, 2}`, (`(3; 4)`)). - * - * If algebra can't parse the string, then this method must throw [kotlin.IllegalStateException]. - * - * @param value the raw string. - * @return an object or `null` if symbol could not be bound to the context. - */ - public fun bindSymbolOrNull(value: String): T? = null - - /** - * The same as [bindSymbolOrNull] but throws an error if symbol could not be bound - */ - public fun bindSymbol(value: String): T = - bindSymbolOrNull(value) ?: error("Symbol '$value' is not supported in $this") - - /** - * Dynamically dispatches a unary operation with the certain name. - * - * Implementations must fulfil the following requirements: - * - * 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. - */ - public fun unaryOperationFunction(operation: String): (arg: T) -> T = - error("Unary operation $operation not defined in $this") - - /** - * Dynamically invokes a unary operation with the certain name. - * - * Implementations must fulfil the following requirements: - * - * 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. - * @return a result of operation. - */ - public fun unaryOperation(operation: String, arg: T): T = unaryOperationFunction(operation)(arg) - - /** - * Dynamically dispatches a binary operation with the certain name. - * - * Implementations must fulfil the following requirements: - * - * 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. - */ - public fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = - error("Binary operation '$operation' not defined in $this") - - /** - * Dynamically invokes a binary operation with the certain name. - * - * Implementations must fulfil the following requirements: - * - * 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. - * @param right the second argument of operation. - * @return a result of operation. - */ - public fun binaryOperation(operation: String, left: T, right: T): T = - binaryOperationFunction(operation)(left, right) -} - -public fun Algebra.bindSymbolOrNull(symbol: Symbol): T? = bindSymbolOrNull(symbol.identity) - -public fun Algebra.bindSymbol(symbol: Symbol): T = bindSymbol(symbol.identity) - -/** - * Call a block with an [Algebra] as receiver. - */ -// TODO add contract when KT-32313 is fixed -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 - * associative, binary operation [add]. - * - * @param T the type of element of this semispace. - */ -public interface GroupOperations : Algebra { - /** - * Addition of two elements. - * - * @param a the augend. - * @param b the addend. - * @return the sum. - */ - 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. - - /** - * The negation of this element. - * - * @receiver this value. - * @return the additive inverse of this value. - */ - public operator fun T.unaryMinus(): T - - /** - * Returns this value. - * - * @receiver this value. - * @return this value. - */ - public operator fun T.unaryPlus(): T = this - - /** - * Addition of two elements. - * - * @receiver the augend. - * @param b the addend. - * @return the sum. - */ - public operator fun T.plus(b: T): T = add(this, b) - - /** - * Subtraction of two elements. - * - * @receiver the minuend. - * @param b the subtrahend. - * @return the difference. - */ - public operator fun T.minus(b: T): T = add(this, -b) - - override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { - PLUS_OPERATION -> { arg -> +arg } - MINUS_OPERATION -> { arg -> -arg } - else -> super.unaryOperationFunction(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) - } - - public companion object { - /** - * The identifier of addition and unary positive operator. - */ - public const val PLUS_OPERATION: String = "+" - - /** - * The identifier of subtraction and unary negative operator. - */ - public const val MINUS_OPERATION: String = "-" - } -} - -/** - * Represents group i.e., algebraic structure with associative, binary operation [add]. - * - * @param T the type of element of this semispace. - */ -public interface Group : GroupOperations { - /** - * The neutral element of addition. - */ - public val zero: T -} - -/** - * 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. - */ -public interface RingOperations : GroupOperations { - /** - * Multiplies two elements. - * - * @param a the multiplier. - * @param b the multiplicand. - */ - public fun multiply(a: T, b: T): T - - /** - * Multiplies this element by scalar. - * - * @receiver the multiplier. - * @param b the multiplicand. - */ - public operator fun T.times(b: T): T = multiply(this, b) - - override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { - TIMES_OPERATION -> ::multiply - else -> super.binaryOperationFunction(operation) - } - - public companion object { - /** - * The identifier of multiplication. - */ - public const val TIMES_OPERATION: String = "*" - } -} - -/** - * 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. - */ -public interface Ring : Group, RingOperations { - /** - * The neutral element of multiplication - */ - public val one: T -} - -/** - * 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. - */ -public interface FieldOperations : RingOperations { - /** - * Division of two elements. - * - * @param a the dividend. - * @param b the divisor. - * @return the quotient. - */ - public fun divide(a: T, b: T): T - - /** - * Division of two elements. - * - * @receiver the dividend. - * @param b the divisor. - * @return the quotient. - */ - public operator fun T.div(b: T): T = divide(this, b) - - override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = when (operation) { - DIV_OPERATION -> ::divide - else -> super.binaryOperationFunction(operation) - } - - public companion object { - /** - * The identifier of division. - */ - public const val DIV_OPERATION: String = "/" - } -} - -/** - * 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 { - 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 deleted file mode 100644 index 7669e073a..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/AlgebraElements.kt +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.misc.UnstableKMathAPI - -/** - * The generic mathematics elements that is able to store its context - * - * @param C the type of mathematical context for this element. - * @param T the type wrapped by this wrapper. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public interface AlgebraElement> { - /** - * The context this element belongs to. - */ - public val context: C -} -// -///** -// * Divides this element by number. -// * -// * @param k the divisor. -// * @return the quotient. -// */ -//public operator fun , S : Space> T.div(k: Number): T = -// context.multiply(this, 1.0 / k.toDouble()) -// -///** -// * Multiplies this element by number. -// * -// * @param k the multiplicand. -// * @return the product. -// */ -//public operator fun , S : Space> T.times(k: Number): T = -// context.multiply(this, k.toDouble()) - -/** - * Subtracts element from this one. - * - * @param b the subtrahend. - * @return the difference. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public operator fun , S : NumbersAddOperations> T.minus(b: T): T = - context.add(this, context.run { -b }) - -/** - * Adds element to this one. - * - * @receiver the augend. - * @param b the addend. - * @return the sum. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public operator fun , S : Ring> T.plus(b: T): T = - context.add(this, b) - -///** -// * Number times element -// */ -//public operator fun , S : Space> Number.times(element: T): T = -// element.times(this) - -/** - * Multiplies this element by another one. - * - * @receiver the multiplicand. - * @param b the multiplier. - * @return the product. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public operator fun , R : Ring> T.times(b: T): T = - context.multiply(this, b) - - -/** - * Divides this element by another one. - * - * @param b the divisor. - * @return the quotient. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public operator fun , F : Field> T.div(b: T): T = - context.divide(this, b) - - -/** - * The element of [Group]. - * - * @param T the type of space operation results. - * @param I self type of the element. Needed for static type checking. - * @param S the type of space. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public interface GroupElement, S : Group> : AlgebraElement - -/** - * The element of [Ring]. - * - * @param T the type of ring operation results. - * @param I self type of the element. Needed for static type checking. - * @param R the type of ring. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public interface RingElement, R : Ring> : GroupElement - -/** - * The element of [Field]. - * - * @param T the type of field operation results. - * @param I self type of the element. Needed for static type checking. - * @param F the type of field. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public interface FieldElement, F : Field> : RingElement diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt deleted file mode 100644 index 2dd61270d..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/BigInt.kt +++ /dev/null @@ -1,537 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.AlgebraND -import space.kscience.kmath.nd.BufferedRingND -import space.kscience.kmath.operations.BigInt.Companion.BASE -import space.kscience.kmath.operations.BigInt.Companion.BASE_SIZE -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.MutableBuffer -import kotlin.math.log2 -import kotlin.math.max -import kotlin.math.min -import kotlin.math.sign - -private typealias Magnitude = UIntArray -private typealias TBase = ULong - -/** - * Kotlin Multiplatform implementation of Big Integer numbers (KBigInteger). - * - * @author Robert Drynkin - * @author Peter Klimai - */ -@OptIn(UnstableKMathAPI::class) -public object BigIntField : Field, NumbersAddOperations, ScaleOperations { - override val zero: BigInt = BigInt.ZERO - override val one: BigInt = BigInt.ONE - - override fun number(value: Number): BigInt = value.toLong().toBigInt() - - @Suppress("EXTENSION_SHADOWED_BY_MEMBER") - override fun BigInt.unaryMinus(): BigInt = -this - override fun add(a: BigInt, b: BigInt): BigInt = a.plus(b) - override fun scale(a: BigInt, value: Double): BigInt = a.times(number(value)) - override fun multiply(a: BigInt, b: BigInt): BigInt = a.times(b) - override fun divide(a: BigInt, b: BigInt): BigInt = a.div(b) - - public operator fun String.unaryPlus(): BigInt = this.parseBigInteger() ?: error("Can't parse $this as big integer") - public operator fun String.unaryMinus(): BigInt = - -(this.parseBigInteger() ?: error("Can't parse $this as big integer")) -} - -public class BigInt internal constructor( - private val sign: Byte, - private val magnitude: Magnitude, -) : Comparable { - 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) - } - - override fun equals(other: Any?): Boolean = other is BigInt && compareTo(other) == 0 - - override fun hashCode(): Int = magnitude.hashCode() + sign - - public fun abs(): BigInt = if (sign == 0.toByte()) this else BigInt(1, magnitude) - - public operator fun unaryMinus(): BigInt = - if (this.sign == 0.toByte()) this else BigInt((-this.sign).toByte(), this.magnitude) - - public operator fun plus(b: BigInt): BigInt = when { - b.sign == 0.toByte() -> this - sign == 0.toByte() -> b - this == -b -> ZERO - sign == b.sign -> BigInt(sign, addMagnitudes(magnitude, b.magnitude)) - - else -> { - val comp = compareMagnitudes(magnitude, b.magnitude) - - if (comp == 1) - BigInt(sign, subtractMagnitudes(magnitude, b.magnitude)) - else - BigInt((-sign).toByte(), subtractMagnitudes(b.magnitude, magnitude)) - } - } - - public operator fun minus(b: BigInt): BigInt = this + (-b) - - public operator fun times(b: BigInt): BigInt = when { - this.sign == 0.toByte() -> ZERO - b.sign == 0.toByte() -> ZERO - b.magnitude.size == 1 -> this * b.magnitude[0] * b.sign.toInt() - this.magnitude.size == 1 -> b * this.magnitude[0] * this.sign.toInt() - else -> BigInt((this.sign * b.sign).toByte(), multiplyMagnitudes(this.magnitude, b.magnitude)) - } - - public operator fun times(other: UInt): BigInt = when { - sign == 0.toByte() -> ZERO - other == 0U -> ZERO - other == 1U -> this - else -> BigInt(sign, multiplyMagnitudeByUInt(magnitude, other)) - } - - public fun pow(exponent: UInt): BigInt = BigIntField.power(this, exponent) - - public operator fun times(other: Int): BigInt = when { - other > 0 -> this * kotlin.math.abs(other).toUInt() - other != Int.MIN_VALUE -> -this * kotlin.math.abs(other).toUInt() - else -> times(other.toBigInt()) - } - - public operator fun div(other: UInt): BigInt = BigInt(this.sign, divideMagnitudeByUInt(this.magnitude, other)) - - public operator fun div(other: Int): BigInt = BigInt( - (this.sign * other.sign).toByte(), - divideMagnitudeByUInt(this.magnitude, kotlin.math.abs(other).toUInt()) - ) - - private fun division(other: BigInt): Pair { - // Long division algorithm: - // https://en.wikipedia.org/wiki/Division_algorithm#Integer_division_(unsigned)_with_remainder - // TODO: Implement more effective algorithm - var q = ZERO - var r = ZERO - - val bitSize = - (BASE_SIZE * (this.magnitude.size - 1) + log2(this.magnitude.lastOrNull()?.toFloat() ?: (0f + 1))).toInt() - - for (i in bitSize downTo 0) { - r = r shl 1 - r = r or ((abs(this) shr i) and ONE) - - if (r >= abs(other)) { - r -= abs(other) - q += (ONE shl i) - } - } - - return Pair(BigInt((this.sign * other.sign).toByte(), q.magnitude), r) - } - - public operator fun div(other: BigInt): BigInt = division(other).first - - public infix fun shl(i: Int): BigInt { - if (this == ZERO) return ZERO - if (i == 0) return this - val fullShifts = i / BASE_SIZE + 1 - val relShift = i % BASE_SIZE - val shiftLeft = { x: UInt -> if (relShift >= 32) 0U else x shl relShift } - val shiftRight = { x: UInt -> if (BASE_SIZE - relShift >= 32) 0U else x shr (BASE_SIZE - relShift) } - val newMagnitude = Magnitude(magnitude.size + fullShifts) - - for (j in magnitude.indices) { - newMagnitude[j + fullShifts - 1] = shiftLeft(this.magnitude[j]) - - if (j != 0) - newMagnitude[j + fullShifts - 1] = newMagnitude[j + fullShifts - 1] or shiftRight(this.magnitude[j - 1]) - } - - newMagnitude[magnitude.size + fullShifts - 1] = shiftRight(magnitude.last()) - return BigInt(this.sign, stripLeadingZeros(newMagnitude)) - } - - public infix fun shr(i: Int): BigInt { - if (this == ZERO) return ZERO - if (i == 0) return this - val fullShifts = i / BASE_SIZE - val relShift = i % BASE_SIZE - val shiftRight = { x: UInt -> if (relShift >= 32) 0U else x shr relShift } - val shiftLeft = { x: UInt -> if (BASE_SIZE - relShift >= 32) 0U else x shl (BASE_SIZE - relShift) } - if (this.magnitude.size - fullShifts <= 0) return ZERO - val newMagnitude: Magnitude = Magnitude(magnitude.size - fullShifts) - - for (j in fullShifts until magnitude.size) { - newMagnitude[j - fullShifts] = shiftRight(magnitude[j]) - - if (j != magnitude.size - 1) - newMagnitude[j - fullShifts] = newMagnitude[j - fullShifts] or shiftLeft(magnitude[j + 1]) - } - - return BigInt(this.sign, stripLeadingZeros(newMagnitude)) - } - - public infix fun or(other: BigInt): BigInt { - if (this == ZERO) return other - if (other == ZERO) return this - val resSize = max(magnitude.size, other.magnitude.size) - val newMagnitude: Magnitude = Magnitude(resSize) - - for (i in 0 until resSize) { - if (i < magnitude.size) newMagnitude[i] = newMagnitude[i] or magnitude[i] - if (i < other.magnitude.size) newMagnitude[i] = newMagnitude[i] or other.magnitude[i] - } - - return BigInt(1, stripLeadingZeros(newMagnitude)) - } - - public infix fun and(other: BigInt): BigInt { - if ((this == ZERO) or (other == ZERO)) return ZERO - val resSize = min(this.magnitude.size, other.magnitude.size) - val newMagnitude: Magnitude = Magnitude(resSize) - for (i in 0 until resSize) newMagnitude[i] = this.magnitude[i] and other.magnitude[i] - return BigInt(1, stripLeadingZeros(newMagnitude)) - } - - public operator fun rem(other: Int): Int { - val res = this - (this / other) * other - return if (res == ZERO) 0 else res.sign * res.magnitude[0].toInt() - } - - public operator fun rem(other: BigInt): BigInt = this - (this / other) * other - - public fun modPow(exponent: BigInt, m: BigInt): BigInt = when { - exponent == ZERO -> ONE - exponent % 2 == 1 -> (this * modPow(exponent - ONE, m)) % m - - else -> { - val sqRoot = modPow(exponent / 2, m) - (sqRoot * sqRoot) % m - } - } - - override fun toString(): String { - if (this.sign == 0.toByte()) { - return "0x0" - } - var res: String = if (this.sign == (-1).toByte()) "-0x" else "0x" - var numberStarted = false - - for (i in this.magnitude.size - 1 downTo 0) { - for (j in BASE_SIZE / 4 - 1 downTo 0) { - val curByte = (this.magnitude[i] shr 4 * j) and 0xfU - if (numberStarted or (curByte != 0U)) { - numberStarted = true - res += hexMapping[curByte] - } - } - } - - return res - } - - public companion object { - public const val BASE: ULong = 0xffffffffUL - public const val BASE_SIZE: Int = 32 - public val ZERO: BigInt = BigInt(0, uintArrayOf()) - public val ONE: BigInt = BigInt(1, uintArrayOf(1u)) - private const val KARATSUBA_THRESHOLD = 80 - - private val hexMapping: HashMap = hashMapOf( - 0U to "0", 1U to "1", 2U to "2", 3U to "3", - 4U to "4", 5U to "5", 6U to "6", 7U to "7", - 8U to "8", 9U to "9", 10U to "a", 11U to "b", - 12U to "c", 13U to "d", 14U to "e", 15U to "f" - ) - - private fun compareMagnitudes(mag1: Magnitude, mag2: Magnitude): Int { - return when { - mag1.size > mag2.size -> 1 - mag1.size < mag2.size -> -1 - - else -> { - for (i in mag1.size - 1 downTo 0) return when { - mag1[i] > mag2[i] -> 1 - mag1[i] < mag2[i] -> -1 - else -> continue - } - - 0 - } - } - } - - private fun addMagnitudes(mag1: Magnitude, mag2: Magnitude): Magnitude { - val resultLength = max(mag1.size, mag2.size) + 1 - val result = Magnitude(resultLength) - var carry = 0uL - - for (i in 0 until resultLength - 1) { - val res = when { - i >= mag1.size -> mag2[i].toULong() + carry - i >= mag2.size -> mag1[i].toULong() + carry - else -> mag1[i].toULong() + mag2[i].toULong() + carry - } - - result[i] = (res and BASE).toUInt() - carry = res shr BASE_SIZE - } - - result[resultLength - 1] = carry.toUInt() - return stripLeadingZeros(result) - } - - private fun subtractMagnitudes(mag1: Magnitude, mag2: Magnitude): Magnitude { - val resultLength = mag1.size - val result = Magnitude(resultLength) - var carry = 0L - - for (i in 0 until resultLength) { - var res = - if (i < mag2.size) mag1[i].toLong() - mag2[i].toLong() - carry - else mag1[i].toLong() - carry - - carry = if (res < 0) 1 else 0 - res += carry * (BASE + 1UL).toLong() - - result[i] = res.toUInt() - } - - return stripLeadingZeros(result) - } - - private fun multiplyMagnitudeByUInt(mag: Magnitude, x: UInt): Magnitude { - val resultLength = mag.size + 1 - val result = Magnitude(resultLength) - var carry = 0uL - - for (i in mag.indices) { - val cur = carry + mag[i].toULong() * x.toULong() - result[i] = (cur and BASE).toUInt() - carry = cur shr BASE_SIZE - } - - result[resultLength - 1] = (carry and BASE).toUInt() - - return stripLeadingZeros(result) - } - - internal fun multiplyMagnitudes(mag1: Magnitude, mag2: Magnitude): Magnitude = when { - mag1.size + mag2.size < KARATSUBA_THRESHOLD || mag1.isEmpty() || mag2.isEmpty() -> - naiveMultiplyMagnitudes(mag1, mag2) - // TODO implement Fourier - else -> karatsubaMultiplyMagnitudes(mag1, mag2) - } - - internal fun naiveMultiplyMagnitudes(mag1: Magnitude, mag2: Magnitude): Magnitude { - val resultLength = mag1.size + mag2.size - val result = Magnitude(resultLength) - - for (i in mag1.indices) { - var carry = 0uL - - for (j in mag2.indices) { - val cur: ULong = result[i + j].toULong() + mag1[i].toULong() * mag2[j].toULong() + carry - result[i + j] = (cur and BASE).toUInt() - carry = cur shr BASE_SIZE - } - - result[i + mag2.size] = (carry and BASE).toUInt() - } - - return stripLeadingZeros(result) - } - - internal fun karatsubaMultiplyMagnitudes(mag1: Magnitude, mag2: Magnitude): Magnitude { - //https://en.wikipedia.org/wiki/Karatsuba_algorithm - val halfSize = min(mag1.size, mag2.size) / 2 - val x0 = mag1.sliceArray(0 until halfSize).toBigInt(1) - val x1 = mag1.sliceArray(halfSize until mag1.size).toBigInt(1) - val y0 = mag2.sliceArray(0 until halfSize).toBigInt(1) - val y1 = mag2.sliceArray(halfSize until mag2.size).toBigInt(1) - - val z0 = x0 * y0 - val z2 = x1 * y1 - val z1 = (x0 - x1) * (y1 - y0) + z0 + z2 - - return (z2.shl(2 * halfSize * BASE_SIZE) + z1.shl(halfSize * BASE_SIZE) + z0).magnitude - } - - private fun divideMagnitudeByUInt(mag: Magnitude, x: UInt): Magnitude { - val resultLength = mag.size - val result = Magnitude(resultLength) - var carry = 0uL - - for (i in mag.size - 1 downTo 0) { - val cur: ULong = mag[i].toULong() + (carry shl BASE_SIZE) - result[i] = (cur / x).toUInt() - carry = cur % x - } - - return stripLeadingZeros(result) - } - } -} - -private fun stripLeadingZeros(mag: Magnitude): Magnitude { - if (mag.isEmpty() || mag.last() != 0U) return mag - var resSize = mag.size - 1 - - while (mag[resSize] == 0U) { - if (resSize == 0) break - resSize -= 1 - } - - return mag.sliceArray(IntRange(0, resSize)) -} - -/** - * Returns the absolute value of the given value [x]. - */ -public fun abs(x: BigInt): BigInt = x.abs() - -/** - * Convert this [Int] to [BigInt] - */ -public fun Int.toBigInt(): BigInt = BigInt(sign.toByte(), uintArrayOf(kotlin.math.abs(this).toUInt())) - -/** - * Convert this [Long] to [BigInt] - */ -public fun Long.toBigInt(): BigInt = BigInt( - sign.toByte(), - stripLeadingZeros( - uintArrayOf( - (kotlin.math.abs(this).toULong() and BASE).toUInt(), - ((kotlin.math.abs(this).toULong() shr BASE_SIZE) and BASE).toUInt() - ) - ) -) - -/** - * Convert UInt to [BigInt] - */ -public fun UInt.toBigInt(): BigInt = BigInt(1, uintArrayOf(this)) - -/** - * Convert ULong to [BigInt] - */ -public fun ULong.toBigInt(): BigInt = BigInt( - 1, - stripLeadingZeros( - uintArrayOf( - (this and BASE).toUInt(), - ((this shr BASE_SIZE) and BASE).toUInt() - ) - ) -) - -/** - * Create a [BigInt] with this array of magnitudes with protective copy - */ -public fun UIntArray.toBigInt(sign: Byte): BigInt { - require(sign != 0.toByte() || !isNotEmpty()) - return BigInt(sign, copyOf()) -} - -/** - * Returns `null` if a valid number cannot be read from a string - */ -public fun String.parseBigInteger(): BigInt? { - if (isEmpty()) return null - val sign: Int - - val positivePartIndex = when (this[0]) { - '+' -> { - sign = +1 - 1 - } - '-' -> { - sign = -1 - 1 - } - else -> { - sign = +1 - 0 - } - } - - var isEmpty = true - - return if (this.startsWith("0X", startIndex = positivePartIndex, ignoreCase = true)) { - // hex representation - - val uInts = ArrayList(length).apply { add(0U) } - var offset = 0 - fun addDigit(value: UInt) { - uInts[uInts.lastIndex] += value shl offset - offset += 4 - if (offset == 32) { - uInts.add(0U) - offset = 0 - } - } - - for (index in lastIndex downTo positivePartIndex + 2) { - when (val ch = this[index]) { - '_' -> continue - in '0'..'9' -> addDigit((ch - '0').toUInt()) - in 'A'..'F' -> addDigit((ch - 'A').toUInt() + 10U) - in 'a'..'f' -> addDigit((ch - 'a').toUInt() + 10U) - else -> return null - } - isEmpty = false - } - - while (uInts.isNotEmpty() && uInts.last() == 0U) - uInts.removeLast() - - if (isEmpty) null else BigInt(sign.toByte(), uInts.toUIntArray()) - } else { - // decimal representation - - val positivePart = buildList(length) { - for (index in positivePartIndex until length) - when (val a = this@parseBigInteger[index]) { - '_' -> continue - in '0'..'9' -> add(a) - else -> return null - } - } - - val offset = positivePart.size % 9 - isEmpty = offset == 0 - - fun parseUInt(fromIndex: Int, toIndex: Int): UInt? { - var res = 0U - for (i in fromIndex until toIndex) { - res = res * 10U + (positivePart[i].digitToIntOrNull()?.toUInt() ?: return null) - } - return res - } - - var res = parseUInt(0, offset)?.toBigInt() ?: return null - - for (index in offset..positivePart.lastIndex step 9) { - isEmpty = false - res = res * 1_000_000_000U + (parseUInt(index, index + 9) ?: return null).toBigInt() - } - if (isEmpty) null else res * sign - } -} - -public inline fun Buffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): Buffer = - boxing(size, initializer) - -public inline fun MutableBuffer.Companion.bigInt(size: Int, initializer: (Int) -> BigInt): MutableBuffer = - boxing(size, initializer) - -public fun AlgebraND.Companion.bigInt(vararg shape: Int): BufferedRingND = - BufferedRingND(shape, BigIntField, Buffer.Companion::bigInt) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt deleted file mode 100644 index d50f1e79e..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/LogicAlgebra.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.expressions.symbol -import space.kscience.kmath.misc.UnstableKMathAPI - -/** - * An algebra for generic boolean logic - */ -@UnstableKMathAPI -public interface LogicAlgebra : Algebra { - - /** - * Represent constant [Boolean] as [T] - */ - public fun const(boolean: Boolean): T - - override fun bindSymbolOrNull(value: String): T? = value.lowercase().toBooleanStrictOrNull()?.let(::const) - - override fun unaryOperation(operation: String, arg: T): T = when (operation) { - Boolean::not.name -> arg.not() - else -> super.unaryOperation(operation, arg) - } - - override fun unaryOperationFunction(operation: String): (arg: T) -> T = { unaryOperation(operation, it) } - - override fun binaryOperation(operation: String, left: T, right: T): T = when (operation) { - Boolean::and.name -> left.and(right) - Boolean::or.name -> left.or(right) - else -> super.binaryOperation(operation, left, right) - } - - override fun binaryOperationFunction(operation: String): (left: T, right: T) -> T = { l, r -> - binaryOperation(operation, l, r) - } - - /** - * Logic 'not' - */ - public operator fun T.not(): T - - /** - * Logic 'and' - */ - public infix fun T.and(other: T): T - - /** - * Logic 'or' - */ - public infix fun T.or(other: T): T - - /** - * Logic 'xor' - */ - public infix fun T.xor(other: T): T - - - public companion object { - public val TRUE: Symbol by symbol - public val FALSE: Symbol by symbol - } -} - -/** - * An implementation of [LogicAlgebra] for primitive booleans - */ -@UnstableKMathAPI -@Suppress("EXTENSION_SHADOWED_BY_MEMBER") -public object BooleanAlgebra : LogicAlgebra { - - override fun const(boolean: Boolean): Boolean = boolean - - override fun Boolean.not(): Boolean = !this - - override fun Boolean.and(other: Boolean): Boolean = this && other - - override fun Boolean.or(other: Boolean): Boolean = this || other - - override fun Boolean.xor(other: Boolean): Boolean = this xor other -} \ No newline at end of file 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 deleted file mode 100644 index a3d8f5ffe..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/NumericAlgebra.kt +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.misc.UnstableKMathAPI -import kotlin.math.E -import kotlin.math.PI - -/** - * An algebraic structure where elements can have numeric representation. - * - * @param T the type of element of this structure. - */ -public interface NumericAlgebra : Algebra { - /** - * Wraps a number to [T] object. - * - * @param value the number to wrap. - * @return an object. - */ - public fun number(value: Number): T - - /** - * Dynamically dispatches a binary operation with the certain name with numeric first argument. - * - * Implementations must fulfil the following requirements: - * - * 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. - */ - public fun leftSideNumberOperationFunction(operation: String): (left: Number, right: T) -> T = - { l, r -> binaryOperationFunction(operation)(number(l), r) } - - /** - * Dynamically invokes a binary operation with the certain name with numeric first argument. - * - * Implementations must fulfil the following requirements: - * - * 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. - * @param right the second argument of operation. - * @return a result of operation. - */ - public fun leftSideNumberOperation(operation: String, left: Number, right: T): T = - leftSideNumberOperationFunction(operation)(left, right) - - /** - * Dynamically dispatches a binary operation with the certain name with numeric first argument. - * - * Implementations must fulfil the following requirements: - * - * 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. - */ - public fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = - { l, r -> binaryOperationFunction(operation)(l, number(r)) } - - /** - * Dynamically invokes a binary operation with the certain name with numeric second argument. - * - * Implementations must fulfil the following requirements: - * - * 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. - * @param right the second argument of operation. - * @return a result of operation. - */ - public fun rightSideNumberOperation(operation: String, left: T, right: Number): T = - rightSideNumberOperationFunction(operation)(left, right) - - override fun bindSymbolOrNull(value: String): T? = when (value) { - "pi" -> number(PI) - "e" -> number(E) - else -> super.bindSymbolOrNull(value) - } -} - -/** - * The π mathematical constant. - */ -public val NumericAlgebra.pi: T get() = bindSymbolOrNull("pi") ?: number(PI) - -/** - * The *e* mathematical constant. - */ -public val NumericAlgebra.e: T get() = number(E) - -/** - * Scale by scalar operations - */ -public interface ScaleOperations : Algebra { - /** - * Scaling an element by a scalar. - * - * @param a the multiplier. - * @param value the multiplicand. - * @return the produce. - */ - public fun scale(a: T, value: Double): T - - /** - * Multiplication of this element by a scalar. - * - * @receiver the multiplier. - * @param k the multiplicand. - * @return the product. - */ - public operator fun T.times(k: Number): T = scale(this, k.toDouble()) - - /** - * Division of this element by scalar. - * - * @receiver the dividend. - * @param k the divisor. - * @return the quotient. - */ - public operator fun T.div(k: Number): T = scale(this, 1.0 / k.toDouble()) - - /** - * Multiplication of this number by element. - * - * @receiver the multiplier. - * @param b the multiplicand. - * @return the product. - */ - public operator fun Number.times(b: T): T = b * this -} - -/** - * A combination of [NumericAlgebra] and [Ring] that adds intrinsic simple operations on numbers like `T+1` - * TODO to be removed and replaced by extensions after multiple receivers are there - */ -@UnstableKMathAPI -public interface NumbersAddOperations : Ring, NumericAlgebra { - /** - * Addition of element and scalar. - * - * @receiver the augend. - * @param b the addend. - */ - public operator fun T.plus(b: Number): T = this + number(b) - - /** - * Addition of scalar and element. - * - * @receiver the augend. - * @param b the addend. - */ - public operator fun Number.plus(b: T): T = b + this - - /** - * Subtraction of element from number. - * - * @receiver the minuend. - * @param b the subtrahend. - * @receiver the difference. - */ - public operator fun T.minus(b: Number): T = this - number(b) - - /** - * Subtraction of number from element. - * - * @receiver the minuend. - * @param b the subtrahend. - * @receiver the difference. - */ - public operator fun Number.minus(b: T): T = -b + this -} \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt deleted file mode 100644 index 7f44eda49..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/OptionalOperations.kt +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.misc.UnstableKMathAPI - -/** - * A container for trigonometric operations for specific type. - * - * @param T the type of element of this structure. - */ -public interface TrigonometricOperations : Algebra { - /** - * Computes the sine of [arg]. - */ - public fun sin(arg: T): T - - /** - * Computes the cosine of [arg]. - */ - public fun cos(arg: T): T - - /** - * Computes the tangent of [arg]. - */ - public fun tan(arg: T): T - - /** - * Computes the inverse sine of [arg]. - */ - public fun asin(arg: T): T - - /** - * Computes the inverse cosine of [arg]. - */ - public fun acos(arg: T): T - - /** - * Computes the inverse tangent of [arg]. - */ - public fun atan(arg: T): T - - public companion object { - /** - * The identifier of sine. - */ - public const val SIN_OPERATION: String = "sin" - - /** - * The identifier of cosine. - */ - public const val COS_OPERATION: String = "cos" - - /** - * The identifier of tangent. - */ - public const val TAN_OPERATION: String = "tan" - - /** - * The identifier of inverse sine. - */ - public const val ASIN_OPERATION: String = "asin" - - /** - * The identifier of inverse cosine. - */ - public const val ACOS_OPERATION: String = "acos" - - /** - * The identifier of inverse tangent. - */ - public const val ATAN_OPERATION: String = "atan" - } -} - -/** - * Computes the sine of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> sin(arg: T): T = arg.context.sin(arg) - -/** - * Computes the cosine of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> cos(arg: T): T = arg.context.cos(arg) - -/** - * Computes the tangent of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> tan(arg: T): T = arg.context.tan(arg) - -/** - * Computes the inverse sine of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> asin(arg: T): T = arg.context.asin(arg) - -/** - * Computes the inverse cosine of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> acos(arg: T): T = arg.context.acos(arg) - -/** - * Computes the inverse tangent of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> atan(arg: T): T = arg.context.atan(arg) - -/** - * A context extension to include power operations based on exponentiation. - * - * @param T the type of element of this structure. - */ -public interface PowerOperations : Algebra { - /** - * Raises [arg] to the power [pow]. - */ - public fun power(arg: T, pow: Number): T - - /** - * Computes the square root of the value [arg]. - */ - public fun sqrt(arg: T): T = power(arg, 0.5) - - /** - * Raises this value to the power [pow]. - */ - public infix fun T.pow(pow: Number): T = power(this, pow) - - public companion object { - /** - * The identifier of exponentiation. - */ - public const val POW_OPERATION: String = "pow" - - /** - * The identifier of square root. - */ - public const val SQRT_OPERATION: String = "sqrt" - } -} - -/** - * Raises this element to the power [power]. - * - * @receiver the base. - * @param power the exponent. - * @return the base raised to the power. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public infix fun >> T.pow(power: Double): T = context.power(this, power) - -/** - * Computes the square root of the value [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> sqrt(arg: T): T = arg pow 0.5 - -/** - * Computes the square of the value [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> sqr(arg: T): T = arg pow 2.0 - -/** - * A container for operations related to `exp` and `ln` functions. - * - * @param T the type of element of this structure. - */ -public interface ExponentialOperations : Algebra { - /** - * Computes Euler's number `e` raised to the power of the value [arg]. - */ - public fun exp(arg: T): T - - /** - * Computes the natural logarithm (base `e`) of the value [arg]. - */ - public fun ln(arg: T): T - - /** - * Computes the hyperbolic sine of [arg]. - */ - public fun sinh(arg: T): T - - /** - * Computes the hyperbolic cosine of [arg]. - */ - public fun cosh(arg: T): T - - /** - * Computes the hyperbolic tangent of [arg]. - */ - public fun tanh(arg: T): T - - /** - * Computes the inverse hyperbolic sine of [arg]. - */ - public fun asinh(arg: T): T - - /** - * Computes the inverse hyperbolic cosine of [arg]. - */ - public fun acosh(arg: T): T - - /** - * Computes the inverse hyperbolic tangent of [arg]. - */ - public fun atanh(arg: T): T - - public companion object { - /** - * The identifier of exponential function. - */ - public const val EXP_OPERATION: String = "exp" - - /** - * The identifier of natural logarithm. - */ - public const val LN_OPERATION: String = "ln" - - /** - * The identifier of hyperbolic sine. - */ - public const val SINH_OPERATION: String = "sinh" - - /** - * The identifier of hyperbolic cosine. - */ - public const val COSH_OPERATION: String = "cosh" - - /** - * The identifier of hyperbolic tangent. - */ - public const val TANH_OPERATION: String = "tanh" - - /** - * The identifier of inverse hyperbolic sine. - */ - public const val ASINH_OPERATION: String = "asinh" - - /** - * The identifier of inverse hyperbolic cosine. - */ - public const val ACOSH_OPERATION: String = "acosh" - - /** - * The identifier of inverse hyperbolic tangent. - */ - public const val ATANH_OPERATION: String = "atanh" - } -} - -/** - * The identifier of exponential function. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> exp(arg: T): T = arg.context.exp(arg) - -/** - * The identifier of natural logarithm. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> ln(arg: T): T = arg.context.ln(arg) - - -/** - * Computes the hyperbolic sine of [arg]. - */ -@UnstableKMathAPI -public fun >> sinh(arg: T): T = arg.context.sinh(arg) - -/** - * Computes the hyperbolic cosine of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> cosh(arg: T): T = arg.context.cosh(arg) - -/** - * Computes the hyperbolic tangent of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> tanh(arg: T): T = arg.context.tanh(arg) - -/** - * Computes the inverse hyperbolic sine of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> asinh(arg: T): T = arg.context.asinh(arg) - -/** - * Computes the inverse hyperbolic cosine of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> acosh(arg: T): T = arg.context.acosh(arg) - -/** - * Computes the inverse hyperbolic tangent of [arg]. - */ -@UnstableKMathAPI -@Deprecated("AlgebraElements are considered odd and will be removed in future releases.") -public fun >> atanh(arg: T): T = arg.context.atanh(arg) - -/** - * A container for norm functional on element. - * - * @param T the type of element having norm defined. - * @param R the type of norm. - */ -public interface Norm { - /** - * 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). - */ -@UnstableKMathAPI -public fun >, R> norm(arg: T): R = arg.context.norm(arg) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt deleted file mode 100644 index b26ebb2ea..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/algebraExtensions.kt +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations - -/** - * Returns the sum of all elements in the iterable in this [Ring]. - * - * @receiver the algebra that provides addition. - * @param data the iterable to sum up. - * @return the sum. - */ -public fun Ring.sum(data: Iterable): T = data.fold(zero) { left, right -> - add(left, right) -} - -//TODO replace by sumOf with multi-receivers - -/** - * Returns the sum of all elements in the sequence in this [Ring]. - * - * @receiver the algebra that provides addition. - * @param data the sequence to sum up. - * @return the sum. - */ -public fun Ring.sum(data: Sequence): T = data.fold(zero) { left, right -> - add(left, right) -} - -/** - * Returns an average value of elements in the iterable in this [Ring]. - * - * @receiver the algebra that provides addition and division. - * @param data the iterable to find average. - * @return the average value. - * @author Iaroslav Postovalov - */ -public fun S.average(data: Iterable): T where S : Ring, S : ScaleOperations = - sum(data) / data.count() - -/** - * Returns an average value of elements in the sequence in this [Ring]. - * - * @receiver the algebra that provides addition and division. - * @param data the sequence to find average. - * @return the average value. - * @author Iaroslav Postovalov - */ -public fun S.average(data: Sequence): T where S : Ring, S : ScaleOperations = - sum(data) / data.count() - -/** - * Absolute of the comparable [value] - */ -public fun > Ring.abs(value: T): T = if (value > zero) value else -value - -/** - * Returns the sum of all elements in the iterable in provided space. - * - * @receiver the collection to sum up. - * @param group the algebra that provides addition. - * @return the sum. - */ -public fun Iterable.sumWith(group: Ring): T = group.sum(this) - -/** - * Returns the sum of all elements in the sequence in provided space. - * - * @receiver the collection to sum up. - * @param group the algebra that provides addition. - * @return the sum. - */ -public fun Sequence.sumWith(group: Ring): T = group.sum(this) - -/** - * Returns an average value of elements in the iterable in this [Ring]. - * - * @receiver the iterable to find average. - * @param space the algebra that provides addition and division. - * @return the average value. - * @author Iaroslav Postovalov - */ -public fun Iterable.averageWith(space: S): T where S : Ring, S : ScaleOperations = - space.average(this) - -/** - * Returns an average value of elements in the sequence in this [Ring]. - * - * @receiver the sequence to find average. - * @param space the algebra that provides addition and division. - * @return the average value. - * @author Iaroslav Postovalov - */ -public fun Sequence.averageWith(space: S): T where S : Ring, S : ScaleOperations = - space.average(this) - -/** - * Raises [arg] to the non-negative integer power [exponent]. - * - * Special case: 0 ^ 0 is 1. - * - * @receiver the algebra to provide multiplication. - * @param arg the base. - * @param exponent the exponent. - * @return the base raised to the power. - * @author Evgeniy Zhelenskiy - */ -public fun Ring.power(arg: T, exponent: UInt): T = when { - arg == zero && exponent > 0U -> zero - arg == one -> arg - arg == -one -> powWithoutOptimization(arg, exponent % 2U) - else -> powWithoutOptimization(arg, exponent) -} - -private fun Ring.powWithoutOptimization(base: T, exponent: UInt): T = when (exponent) { - 0U -> one - 1U -> base - else -> { - val pre = powWithoutOptimization(base, exponent shr 1).let { it * it } - if (exponent and 1U == 0U) pre else pre * base - } -} - - -/** - * Raises [arg] to the integer power [exponent]. - * - * Special case: 0 ^ 0 is 1. - * - * @receiver the algebra to provide multiplication and division. - * @param arg the base. - * @param exponent the exponent. - * @return the base raised to the power. - * @author Iaroslav Postovalov, Evgeniy Zhelenskiy - */ -public fun Field.power(arg: T, exponent: Int): T = when { - exponent < 0 -> one / (this as Ring).power(arg, if (exponent == Int.MIN_VALUE) Int.MAX_VALUE.toUInt().inc() else (-exponent).toUInt()) - else -> (this as Ring).power(arg, exponent.toUInt()) -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt deleted file mode 100644 index e75d815cf..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/operations/numbers.kt +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations - -import kotlin.math.pow as kpow - -/** - * Advanced Number-like semifield that implements basic operations. - */ -public interface ExtendedFieldOperations : - FieldOperations, - TrigonometricOperations, - PowerOperations, - ExponentialOperations { - override fun tan(arg: T): T = sin(arg) / cos(arg) - override fun tanh(arg: T): T = sinh(arg) / cosh(arg) - - override fun unaryOperationFunction(operation: String): (arg: T) -> T = when (operation) { - TrigonometricOperations.COS_OPERATION -> ::cos - TrigonometricOperations.SIN_OPERATION -> ::sin - TrigonometricOperations.TAN_OPERATION -> ::tan - TrigonometricOperations.ACOS_OPERATION -> ::acos - TrigonometricOperations.ASIN_OPERATION -> ::asin - TrigonometricOperations.ATAN_OPERATION -> ::atan - PowerOperations.SQRT_OPERATION -> ::sqrt - ExponentialOperations.EXP_OPERATION -> ::exp - ExponentialOperations.LN_OPERATION -> ::ln - ExponentialOperations.COSH_OPERATION -> ::cosh - ExponentialOperations.SINH_OPERATION -> ::sinh - ExponentialOperations.TANH_OPERATION -> ::tanh - ExponentialOperations.ACOSH_OPERATION -> ::acosh - ExponentialOperations.ASINH_OPERATION -> ::asinh - ExponentialOperations.ATANH_OPERATION -> ::atanh - else -> super.unaryOperationFunction(operation) - } -} - -/** - * Advanced Number-like field that implements basic operations. - */ -public interface ExtendedField : ExtendedFieldOperations, Field, NumericAlgebra, ScaleOperations { - override fun sinh(arg: T): T = (exp(arg) - exp(-arg)) / 2.0 - override fun cosh(arg: T): T = (exp(arg) + exp(-arg)) / 2.0 - override fun tanh(arg: T): T = (exp(arg) - exp(-arg)) / (exp(-arg) + exp(arg)) - 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 - - override fun rightSideNumberOperationFunction(operation: String): (left: T, right: Number) -> T = - when (operation) { - PowerOperations.POW_OPERATION -> ::power - else -> super.rightSideNumberOperationFunction(operation) - } -} - -/** - * A field for [Double] without boxing. Does not produce appropriate field element. - */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public object DoubleField : 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 = 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) - - 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) - - override inline fun sqrt(arg: Double): Double = kotlin.math.sqrt(arg) - override inline fun power(arg: Double, pow: Number): Double = arg.kpow(pow.toDouble()) - override inline fun exp(arg: Double): Double = kotlin.math.exp(arg) - override inline fun ln(arg: Double): Double = kotlin.math.ln(arg) - - override inline fun norm(arg: Double): Double = abs(arg) - - override inline fun Double.unaryMinus(): Double = -this - override inline fun Double.plus(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 [Float] without boxing. Does not produce appropriate field element. - */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public object FloatField : ExtendedField, Norm { - override inline val zero: Float get() = 0.0f - override inline val one: Float get() = 1.0f - - override fun number(value: Number): Float = value.toFloat() - - override fun binaryOperationFunction(operation: String): (left: Float, right: Float) -> Float = - when (operation) { - PowerOperations.POW_OPERATION -> ::power - else -> super.binaryOperationFunction(operation) - } - - override inline fun add(a: Float, b: Float): Float = a + b - override fun scale(a: Float, value: Double): Float = a * value.toFloat() - - override inline fun multiply(a: Float, b: Float): Float = a * b - - override inline fun divide(a: Float, b: Float): Float = a / b - - override inline fun sin(arg: Float): Float = kotlin.math.sin(arg) - override inline fun cos(arg: Float): Float = kotlin.math.cos(arg) - 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) - - 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) - - override inline fun sqrt(arg: Float): Float = kotlin.math.sqrt(arg) - override inline fun power(arg: Float, pow: Number): Float = arg.kpow(pow.toFloat()) - override inline fun exp(arg: Float): Float = kotlin.math.exp(arg) - override inline fun ln(arg: Float): Float = kotlin.math.ln(arg) - - override inline fun norm(arg: Float): Float = abs(arg) - - override inline fun Float.unaryMinus(): Float = -this - override inline fun Float.plus(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 -} - -/** - * A field for [Int] without boxing. Does not produce corresponding ring element. - */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public object IntRing : Ring, Norm, NumericAlgebra { - override inline val zero: Int - get() = 0 - - override inline val one: Int - get() = 1 - - 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) - - 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 -} - -/** - * A field for [Short] without boxing. Does not produce appropriate ring element. - */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public object ShortRing : Ring, Norm, NumericAlgebra { - override inline val zero: Short - get() = 0 - - override inline val one: Short - get() = 1 - - 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() - - 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() -} - -/** - * A field for [Byte] without boxing. Does not produce appropriate ring element. - */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public object ByteRing : Ring, Norm, NumericAlgebra { - override inline val zero: Byte - get() = 0 - - override inline val one: Byte - get() = 1 - - 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() - - 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() -} - -/** - * A field for [Double] without boxing. Does not produce appropriate ring element. - */ -@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public object LongRing : Ring, Norm, NumericAlgebra { - override inline val zero: Long - get() = 0L - - override inline val one: Long - get() = 1L - - 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) - - 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/Buffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt deleted file mode 100644 index 6a97d18c2..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/Buffer.kt +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import kotlin.jvm.JvmInline -import kotlin.reflect.KClass - -/** - * Function that produces [Buffer] from its size and function that supplies values. - * - * @param T the type of buffer. - */ -public typealias BufferFactory = (Int, (Int) -> T) -> Buffer - -/** - * Function that produces [MutableBuffer] from its size and function that supplies values. - * - * @param T the type of buffer. - */ -public typealias MutableBufferFactory = (Int, (Int) -> T) -> MutableBuffer - -/** - * A generic read-only random-access structure for both primitives and objects. - * - * [Buffer] is in general identity-free. [Buffer.contentEquals] should be used for content equality checks. - * - * @param T the type of elements contained in the buffer. - */ -public interface Buffer { - /** - * The size of this buffer. - */ - public val size: Int - - /** - * Gets element at given index. - */ - public operator fun get(index: Int): T - - /** - * Iterates over all elements. - */ - public operator fun iterator(): Iterator - - public companion object { - /** - * Check the element-by-element match of content of two buffers. - */ - public fun contentEquals(first: Buffer, second: Buffer): Boolean { - if (first.size != second.size) return false - for (i in first.indices) { - if (first[i] != second[i]) return false - } - return true - } - - /** - * Creates a [ListBuffer] of given type [T] with given [size]. Each element is calculated by calling the - * specified [initializer] function. - */ - public inline fun boxing(size: Int, initializer: (Int) -> T): Buffer = - List(size, initializer).asBuffer() - - /** - * Creates a [Buffer] of given [type]. If the type is primitive, specialized buffers are used ([IntBuffer], - * [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. - * - * The [size] is specified, and each element is calculated by calling the specified [initializer] function. - */ - @Suppress("UNCHECKED_CAST") - public inline fun auto(type: KClass, size: Int, initializer: (Int) -> T): Buffer = - when (type) { - Double::class -> MutableBuffer.double(size) { initializer(it) as Double } as Buffer - Short::class -> MutableBuffer.short(size) { initializer(it) as Short } as Buffer - Int::class -> MutableBuffer.int(size) { initializer(it) as Int } as Buffer - Long::class -> MutableBuffer.long(size) { initializer(it) as Long } as Buffer - Float::class -> MutableBuffer.float(size) { initializer(it) as Float } as Buffer - else -> boxing(size, initializer) - } - - /** - * Creates a [Buffer] of given type [T]. If the type is primitive, specialized buffers are used ([IntBuffer], - * [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. - * - * The [size] is specified, and each element is calculated by calling the specified [initializer] function. - */ - @Suppress("UNCHECKED_CAST") - public inline fun auto(size: Int, initializer: (Int) -> T): Buffer = - auto(T::class, size, initializer) - } -} - -/** - * Returns an [IntRange] of the valid indices for this [Buffer]. - */ -public val Buffer<*>.indices: IntRange get() = 0 until size - -/** - * A generic mutable random-access structure for both primitives and objects. - * - * @param T the type of elements contained in the buffer. - */ -public interface MutableBuffer : Buffer { - /** - * Sets the array element at the specified [index] to the specified [value]. - */ - public operator fun set(index: Int, value: T) - - /** - * Returns a shallow copy of the buffer. - */ - public fun copy(): MutableBuffer - - public companion object { - /** - * Creates a [DoubleBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun double(size: Int, initializer: (Int) -> Double): DoubleBuffer = - DoubleBuffer(size, initializer) - - /** - * Creates a [ShortBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun short(size: Int, initializer: (Int) -> Short): ShortBuffer = - ShortBuffer(size, initializer) - - /** - * Creates a [IntBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun int(size: Int, initializer: (Int) -> Int): IntBuffer = - IntBuffer(size, initializer) - - /** - * Creates a [LongBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun long(size: Int, initializer: (Int) -> Long): LongBuffer = - LongBuffer(size, initializer) - - - /** - * Creates a [FloatBuffer] with the specified [size], where each element is calculated by calling the specified - * [initializer] function. - */ - public inline fun float(size: Int, initializer: (Int) -> Float): FloatBuffer = - FloatBuffer(size, initializer) - - - /** - * Create a boxing mutable buffer of given type - */ - public inline fun boxing(size: Int, initializer: (Int) -> T): MutableBuffer = - MutableListBuffer(MutableList(size, initializer)) - - /** - * Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used - * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. - * - * The [size] is specified, and each element is calculated by calling the specified [initializer] function. - */ - @Suppress("UNCHECKED_CAST") - public inline fun auto(type: KClass, size: Int, initializer: (Int) -> T): MutableBuffer = - when (type) { - Double::class -> double(size) { initializer(it) as Double } as MutableBuffer - Short::class -> short(size) { initializer(it) as Short } as MutableBuffer - Int::class -> int(size) { initializer(it) as Int } as MutableBuffer - Float::class -> float(size) { initializer(it) as Float } as MutableBuffer - Long::class -> long(size) { initializer(it) as Long } as MutableBuffer - else -> boxing(size, initializer) - } - - /** - * Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used - * ([IntBuffer], [DoubleBuffer], etc.), [ListBuffer] is returned otherwise. - * - * The [size] is specified, and each element is calculated by calling the specified [initializer] function. - */ - @Suppress("UNCHECKED_CAST") - public inline fun auto(size: Int, initializer: (Int) -> T): MutableBuffer = - auto(T::class, size, initializer) - } -} - -/** - * [Buffer] implementation over [List]. - * - * @param T the type of elements contained in the buffer. - * @property list The underlying list. - */ -public class ListBuffer(public val list: List) : Buffer { - - public constructor(size: Int, initializer: (Int) -> T) : this(List(size, initializer)) - - override val size: Int get() = list.size - - override operator fun get(index: Int): T = list[index] - override operator fun iterator(): Iterator = list.iterator() -} - -/** - * Returns an [ListBuffer] that wraps the original list. - */ -public fun List.asBuffer(): ListBuffer = ListBuffer(this) - -/** - * [MutableBuffer] implementation over [MutableList]. - * - * @param T the type of elements contained in the buffer. - * @property list The underlying list. - */ -@JvmInline -public value class MutableListBuffer(public val list: MutableList) : MutableBuffer { - - public constructor(size: Int, initializer: (Int) -> T) : this(MutableList(size, initializer)) - - override val size: Int get() = list.size - - override operator fun get(index: Int): T = list[index] - - override operator fun set(index: Int, value: T) { - list[index] = value - } - - override operator fun iterator(): Iterator = list.iterator() - override fun copy(): MutableBuffer = MutableListBuffer(ArrayList(list)) -} - -/** - * Returns an [MutableListBuffer] that wraps the original list. - */ -public fun MutableList.asMutableBuffer(): MutableListBuffer = MutableListBuffer(this) - -/** - * [MutableBuffer] implementation over [Array]. - * - * @param T the type of elements contained in the buffer. - * @property array The underlying array. - */ -public class ArrayBuffer(internal val array: Array) : MutableBuffer { - // Can't inline because array is invariant - override val size: Int get() = array.size - - override operator fun get(index: Int): T = array[index] - - override operator fun set(index: Int, value: T) { - array[index] = value - } - - override operator fun iterator(): Iterator = array.iterator() - override fun copy(): MutableBuffer = ArrayBuffer(array.copyOf()) -} - - -/** - * Returns an [ArrayBuffer] that wraps the original array. - */ -public fun Array.asBuffer(): ArrayBuffer = ArrayBuffer(this) - -/** - * Immutable wrapper for [MutableBuffer]. - * - * @param T the type of elements contained in the buffer. - * @property buffer The underlying buffer. - */ -@JvmInline -public value class ReadOnlyBuffer(public val buffer: MutableBuffer) : Buffer { - override val size: Int get() = buffer.size - - override operator fun get(index: Int): T = buffer[index] - - override operator fun iterator(): Iterator = buffer.iterator() -} - -/** - * A buffer with content calculated on-demand. The calculated content is not stored, so it is recalculated on each call. - * Useful when one needs single element from the buffer. - * - * @param T the type of elements provided by the buffer. - */ -public class VirtualBuffer(override val size: Int, private val generator: (Int) -> T) : Buffer { - override operator fun get(index: Int): T { - if (index < 0 || index >= size) throw IndexOutOfBoundsException("Expected index from 0 to ${size - 1}, but found $index") - return generator(index) - } - - override operator fun iterator(): Iterator = (0 until size).asSequence().map(generator).iterator() -} - -/** - * Convert this buffer to read-only buffer. - */ -public fun Buffer.asReadOnly(): Buffer = if (this is MutableBuffer) ReadOnlyBuffer(this) else this \ No newline at end of file diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt deleted file mode 100644 index 5f1f8a738..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/BufferAccessor2D.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import space.kscience.kmath.nd.DefaultStrides -import space.kscience.kmath.nd.Structure2D -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.as2D - -/** - * A context that allows to operate on a [MutableBuffer] as on 2d array - */ -internal class BufferAccessor2D( - val rowNum: Int, - val colNum: Int, - val factory: MutableBufferFactory, -) { - operator fun Buffer.get(i: Int, j: Int): T = get(i * colNum + j) - - operator fun MutableBuffer.set(i: Int, j: Int, value: T) { - set(i * colNum + j, value) - } - - inline fun create(crossinline init: (i: Int, j: Int) -> T): MutableBuffer = - factory(rowNum * colNum) { offset -> init(offset / colNum, offset % colNum) } - - fun create(mat: Structure2D): MutableBuffer = create { i, j -> mat[i, j] } - - //TODO optimize wrapper - fun MutableBuffer.collect(): Structure2D = StructureND.buffered( - DefaultStrides(intArrayOf(rowNum, colNum)), - factory - ) { (i, j) -> - get(i, j) - }.as2D() - - inner class Row(val buffer: MutableBuffer, val rowIndex: Int) : MutableBuffer { - override val size: Int get() = colNum - - override operator fun get(index: Int): T = buffer[rowIndex, index] - - override operator fun set(index: Int, value: T) { - buffer[rowIndex, index] = value - } - - override fun copy(): MutableBuffer = factory(colNum) { get(it) } - override operator fun iterator(): Iterator = (0 until colNum).map(::get).iterator() - - } - - /** - * Get row - */ - fun MutableBuffer.row(i: Int): Row = Row(this, i) -} 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 deleted file mode 100644 index b94a36bab..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBuffer.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import kotlin.jvm.JvmInline - -/** - * Specialized [MutableBuffer] implementation over [DoubleArray]. - * - * @property array the underlying array. - */ -@JvmInline -public value class DoubleBuffer(public val array: DoubleArray) : MutableBuffer { - override val size: Int get() = array.size - - override operator fun get(index: Int): Double = array[index] - - override operator fun set(index: Int, value: Double) { - array[index] = value - } - - override operator fun iterator(): DoubleIterator = array.iterator() - - override fun copy(): DoubleBuffer = DoubleBuffer(array.copyOf()) -} - -/** - * Creates a new [DoubleBuffer] with the specified [size], where each element is calculated by calling the specified - * [init] function. - * - * The function [init] is called for each array element sequentially starting from the first one. - * It should return the value for a buffer element given its index. - */ -public inline fun DoubleBuffer(size: Int, init: (Int) -> Double): DoubleBuffer = DoubleBuffer(DoubleArray(size) { init(it) }) - -/** - * Returns a new [DoubleBuffer] of given elements. - */ -public fun DoubleBuffer(vararg doubles: Double): DoubleBuffer = DoubleBuffer(doubles) - -/** - * Simplified [DoubleBuffer] to array comparison - */ -public fun DoubleBuffer.contentEquals(vararg doubles: Double): Boolean = array.contentEquals(doubles) - -/** - * Returns a new [DoubleArray] containing all the elements of this [Buffer]. - */ -public fun Buffer.toDoubleArray(): DoubleArray = when (this) { - is DoubleBuffer -> array.copyOf() - else -> DoubleArray(size, ::get) -} - -/** - * Returns [DoubleBuffer] over this array. - * - * @receiver the array. - * @return the new buffer. - */ -public fun DoubleArray.asBuffer(): DoubleBuffer = DoubleBuffer(this) 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 deleted file mode 100644 index 264d4ffbb..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/DoubleBufferField.kt +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.ExtendedFieldOperations -import kotlin.math.* - -/** - * [ExtendedFieldOperations] over [DoubleBuffer]. - */ -public object DoubleBufferFieldOperations : ExtendedFieldOperations> { - override fun Buffer.unaryMinus(): DoubleBuffer = if (this is DoubleBuffer) { - DoubleBuffer(size) { -array[it] } - } else { - DoubleBuffer(size) { -get(it) } - } - - override fun add(a: Buffer, b: Buffer): DoubleBuffer { - require(b.size == a.size) { - "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " - } - - return if (a is DoubleBuffer && b is DoubleBuffer) { - val aArray = a.array - val bArray = b.array - DoubleBuffer(DoubleArray(a.size) { aArray[it] + bArray[it] }) - } else DoubleBuffer(DoubleArray(a.size) { a[it] + b[it] }) - } -// -// override fun multiply(a: Buffer, k: Number): RealBuffer { -// val kValue = k.toDouble() -// -// return if (a is RealBuffer) { -// val aArray = a.array -// RealBuffer(DoubleArray(a.size) { aArray[it] * kValue }) -// } else RealBuffer(DoubleArray(a.size) { a[it] * kValue }) -// } -// -// override fun divide(a: Buffer, k: Number): RealBuffer { -// val kValue = k.toDouble() -// -// return if (a is RealBuffer) { -// val aArray = a.array -// RealBuffer(DoubleArray(a.size) { aArray[it] / kValue }) -// } else RealBuffer(DoubleArray(a.size) { a[it] / kValue }) -// } - - override fun multiply(a: Buffer, b: Buffer): DoubleBuffer { - require(b.size == a.size) { - "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " - } - - return if (a is DoubleBuffer && b is DoubleBuffer) { - val aArray = a.array - val bArray = b.array - DoubleBuffer(DoubleArray(a.size) { aArray[it] * bArray[it] }) - } else - DoubleBuffer(DoubleArray(a.size) { a[it] * b[it] }) - } - - override fun divide(a: Buffer, b: Buffer): DoubleBuffer { - require(b.size == a.size) { - "The size of the first buffer ${a.size} should be the same as for second one: ${b.size} " - } - - return if (a is DoubleBuffer && b is DoubleBuffer) { - val aArray = a.array - val bArray = b.array - DoubleBuffer(DoubleArray(a.size) { aArray[it] / bArray[it] }) - } else DoubleBuffer(DoubleArray(a.size) { a[it] / b[it] }) - } - - override fun sin(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { sin(array[it]) }) - } else DoubleBuffer(DoubleArray(arg.size) { sin(arg[it]) }) - - override fun cos(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { cos(array[it]) }) - } else DoubleBuffer(DoubleArray(arg.size) { cos(arg[it]) }) - - override fun tan(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { tan(array[it]) }) - } else DoubleBuffer(DoubleArray(arg.size) { tan(arg[it]) }) - - override fun asin(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { asin(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { asin(arg[it]) }) - - override fun acos(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { acos(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { acos(arg[it]) }) - - override fun atan(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { atan(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { atan(arg[it]) }) - - override fun sinh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { sinh(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { sinh(arg[it]) }) - - override fun cosh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { cosh(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { cosh(arg[it]) }) - - override fun tanh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { tanh(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { tanh(arg[it]) }) - - override fun asinh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { asinh(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { asinh(arg[it]) }) - - override fun acosh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { acosh(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { acosh(arg[it]) }) - - override fun atanh(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { atanh(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { atanh(arg[it]) }) - - override fun power(arg: Buffer, pow: Number): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { array[it].pow(pow.toDouble()) }) - } else - DoubleBuffer(DoubleArray(arg.size) { arg[it].pow(pow.toDouble()) }) - - override fun exp(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { exp(array[it]) }) - } else DoubleBuffer(DoubleArray(arg.size) { exp(arg[it]) }) - - override fun ln(arg: Buffer): DoubleBuffer = if (arg is DoubleBuffer) { - val array = arg.array - DoubleBuffer(DoubleArray(arg.size) { ln(array[it]) }) - } else - DoubleBuffer(DoubleArray(arg.size) { ln(arg[it]) }) -} - -/** - * [ExtendedField] over [DoubleBuffer]. - * - * @property size the size of buffers to operate on. - */ -public class DoubleBufferField(public val size: Int) : ExtendedField> { - override val zero: Buffer by lazy { DoubleBuffer(size) { 0.0 } } - override val one: Buffer by lazy { DoubleBuffer(size) { 1.0 } } - - override fun number(value: Number): Buffer = DoubleBuffer(size) { value.toDouble() } - - override fun Buffer.unaryMinus(): Buffer = DoubleBufferFieldOperations.run { - -this@unaryMinus - } - - override fun add(a: Buffer, b: Buffer): DoubleBuffer { - require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } - return DoubleBufferFieldOperations.add(a, b) - } - - override fun scale(a: Buffer, value: Double): DoubleBuffer { - require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } - - return if (a is DoubleBuffer) { - val aArray = a.array - DoubleBuffer(DoubleArray(a.size) { aArray[it] * value }) - } else DoubleBuffer(DoubleArray(a.size) { a[it] * value }) - } - - override fun multiply(a: Buffer, b: Buffer): DoubleBuffer { - require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } - return DoubleBufferFieldOperations.multiply(a, b) - } - - override fun divide(a: Buffer, b: Buffer): DoubleBuffer { - require(a.size == size) { "The buffer size ${a.size} does not match context size $size" } - return DoubleBufferFieldOperations.divide(a, b) - } - - override fun sin(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.sin(arg) - } - - override fun cos(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.cos(arg) - } - - override fun tan(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.tan(arg) - } - - override fun asin(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.asin(arg) - } - - override fun acos(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.acos(arg) - } - - override fun atan(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.atan(arg) - } - - override fun sinh(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.sinh(arg) - } - - override fun cosh(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.cosh(arg) - } - - override fun tanh(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.tanh(arg) - } - - override fun asinh(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.asinh(arg) - } - - override fun acosh(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.acosh(arg) - } - - override fun atanh(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.atanh(arg) - } - - override fun power(arg: Buffer, pow: Number): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.power(arg, pow) - } - - override fun exp(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.exp(arg) - } - - override fun ln(arg: Buffer): DoubleBuffer { - require(arg.size == size) { "The buffer size ${arg.size} does not match context size $size" } - return DoubleBufferFieldOperations.ln(arg) - } -} diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt deleted file mode 100644 index 665558829..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FlaggedBuffer.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import kotlin.experimental.and - -/** - * Represents flags to supply additional info about values of buffer. - * - * @property mask bit mask value of this flag. - */ -public enum class ValueFlag(public val mask: Byte) { - /** - * Reports the value is NaN. - */ - NAN(0b0000_0001), - - /** - * Reports the value doesn't present in the buffer (when the type of value doesn't support `null`). - */ - MISSING(0b0000_0010), - - /** - * Reports the value is negative infinity. - */ - NEGATIVE_INFINITY(0b0000_0100), - - /** - * Reports the value is positive infinity - */ - POSITIVE_INFINITY(0b0000_1000) -} - -/** - * A buffer with flagged values. - */ -public interface FlaggedBuffer : Buffer { - public fun getFlag(index: Int): Byte -} - -/** - * The value is valid if all flags are down - */ -public fun FlaggedBuffer<*>.isValid(index: Int): Boolean = getFlag(index) != 0.toByte() - -public fun FlaggedBuffer<*>.hasFlag(index: Int, flag: ValueFlag): Boolean = (getFlag(index) and flag.mask) != 0.toByte() - -public fun FlaggedBuffer<*>.isMissing(index: Int): Boolean = hasFlag(index, ValueFlag.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 { - init { - require(values.size == flags.size) { "Values and flags must have the same dimensions" } - } - - override fun getFlag(index: Int): Byte = flags[index] - - override val size: Int get() = values.size - - override operator fun get(index: Int): Double? = if (isValid(index)) values[index] else null - - override operator fun iterator(): Iterator = values.indices.asSequence().map { - if (isValid(it)) values[it] else null - }.iterator() -} - -public inline fun FlaggedDoubleBuffer.forEachValid(block: (Double) -> Unit) { - indices - .asSequence() - .filter(::isValid) - .forEach { block(values[it]) } -} 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 deleted file mode 100644 index dc7903cbf..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/FloatBuffer.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import kotlin.jvm.JvmInline - -/** - * Specialized [MutableBuffer] implementation over [FloatArray]. - * - * @property array the underlying array. - * @author Iaroslav Postovalov - */ -@JvmInline -public value class FloatBuffer(public val array: FloatArray) : MutableBuffer { - override val size: Int get() = array.size - - override operator fun get(index: Int): Float = array[index] - - override operator fun set(index: Int, value: Float) { - array[index] = value - } - - override operator fun iterator(): FloatIterator = array.iterator() - - override fun copy(): MutableBuffer = - FloatBuffer(array.copyOf()) -} - -/** - * Creates a new [FloatBuffer] with the specified [size], where each element is calculated by calling the specified - * [init] function. - * - * The function [init] is called for each array element sequentially starting from the first one. - * It should return the value for a buffer element given its index. - */ -public inline fun FloatBuffer(size: Int, init: (Int) -> Float): FloatBuffer = FloatBuffer(FloatArray(size) { init(it) }) - -/** - * Returns a new [FloatBuffer] of given elements. - */ -public fun FloatBuffer(vararg floats: Float): FloatBuffer = FloatBuffer(floats) - -/** - * Returns a new [FloatArray] containing all the elements of this [Buffer]. - */ -public fun Buffer.toFloatArray(): FloatArray = when (this) { - is FloatBuffer -> array.copyOf() - else -> FloatArray(size, ::get) -} - -/** - * Returns [FloatBuffer] over this array. - * - * @receiver the array. - * @return the new buffer. - */ -public fun FloatArray.asBuffer(): FloatBuffer = FloatBuffer(this) 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 deleted file mode 100644 index ca078746c..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/IntBuffer.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import kotlin.jvm.JvmInline - -/** - * Specialized [MutableBuffer] implementation over [IntArray]. - * - * @property array the underlying array. - */ -@JvmInline -public value class IntBuffer(public val array: IntArray) : MutableBuffer { - override val size: Int get() = array.size - - override operator fun get(index: Int): Int = array[index] - - override operator fun set(index: Int, value: Int) { - array[index] = value - } - - override operator fun iterator(): IntIterator = array.iterator() - - override fun copy(): MutableBuffer = - IntBuffer(array.copyOf()) -} - -/** - * Creates a new [IntBuffer] with the specified [size], where each element is calculated by calling the specified - * [init] function. - * - * The function [init] is called for each array element sequentially starting from the first one. - * 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) }) - -/** - * Returns a new [IntBuffer] of given elements. - */ -public fun IntBuffer(vararg ints: Int): IntBuffer = IntBuffer(ints) - -/** - * Returns a new [IntArray] containing all the elements of this [Buffer]. - */ -public fun Buffer.toIntArray(): IntArray = when (this) { - is IntBuffer -> array.copyOf() - else -> IntArray(size, ::get) -} - -/** - * Returns [IntBuffer] over this array. - * - * @receiver the array. - * @return the new buffer. - */ -public fun IntArray.asBuffer(): IntBuffer = IntBuffer(this) diff --git a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt b/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt deleted file mode 100644 index a0b5c78fa..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/LongBuffer.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import kotlin.jvm.JvmInline - -/** - * Specialized [MutableBuffer] implementation over [LongArray]. - * - * @property array the underlying array. - */ -@JvmInline -public value class LongBuffer(public val array: LongArray) : MutableBuffer { - override val size: Int get() = array.size - - override operator fun get(index: Int): Long = array[index] - - override operator fun set(index: Int, value: Long) { - array[index] = value - } - - override operator fun iterator(): LongIterator = array.iterator() - - override fun copy(): MutableBuffer = - LongBuffer(array.copyOf()) -} - -/** - * Creates a new [LongBuffer] with the specified [size], where each element is calculated by calling the specified - * [init] function. - * - * The function [init] is called for each array element sequentially starting from the first one. - * 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) }) - -/** - * Returns a new [LongBuffer] of given elements. - */ -public fun LongBuffer(vararg longs: Long): LongBuffer = LongBuffer(longs) - -/** - * Returns a new [LongArray] containing all the elements of this [Buffer]. - */ -public fun Buffer.toLongArray(): LongArray = when (this) { - is LongBuffer -> array.copyOf() - else -> LongArray(size, ::get) -} - -/** - * Returns [LongBuffer] over this array. - * - * @receiver the array. - * @return the new buffer. - */ -public fun LongArray.asBuffer(): LongBuffer = LongBuffer(this) 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 deleted file mode 100644 index 996785570..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/MemoryBuffer.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import space.kscience.kmath.memory.* - -/** - * A non-boxing buffer over [Memory] object. - * - * @param T the type of elements contained in the buffer. - * @property memory the underlying memory segment. - * @property spec the spec of [T] type. - */ -public open class MemoryBuffer(protected val memory: Memory, protected val spec: MemorySpec) : Buffer { - override val size: Int get() = memory.size / spec.objectSize - - private val reader: MemoryReader = memory.reader() - - override operator fun get(index: Int): T = reader.read(spec, spec.objectSize * index) - override operator fun iterator(): Iterator = (0 until size).asSequence().map { get(it) }.iterator() - - public companion object { - public fun create(spec: MemorySpec, size: Int): MemoryBuffer = - MemoryBuffer(Memory.allocate(size * spec.objectSize), spec) - - public inline fun create( - spec: MemorySpec, - size: Int, - initializer: (Int) -> T, - ): MemoryBuffer = MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer -> - (0 until size).forEach { buffer[it] = initializer(it) } - } - } -} - -/** - * A mutable non-boxing buffer over [Memory] object. - * - * @param T the type of elements contained in the buffer. - * @property memory the underlying memory segment. - * @property spec the spec of [T] type. - */ -public class MutableMemoryBuffer(memory: Memory, spec: MemorySpec) : MemoryBuffer(memory, spec), - MutableBuffer { - - private val writer: MemoryWriter = memory.writer() - - 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 = - MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec) - - public inline fun create( - spec: MemorySpec, - size: Int, - initializer: (Int) -> T, - ): MutableMemoryBuffer = MutableMemoryBuffer(Memory.allocate(size * spec.objectSize), spec).also { buffer -> - (0 until size).forEach { buffer[it] = initializer(it) } - } - } -} 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 deleted file mode 100644 index 1d2b0188a..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/ShortBuffer.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import kotlin.jvm.JvmInline - -/** - * Specialized [MutableBuffer] implementation over [ShortArray]. - * - * @property array the underlying array. - */ -@JvmInline -public value class ShortBuffer(public val array: ShortArray) : MutableBuffer { - override val size: Int get() = array.size - - override operator fun get(index: Int): Short = array[index] - - override operator fun set(index: Int, value: Short) { - array[index] = value - } - - override operator fun iterator(): ShortIterator = array.iterator() - override fun copy(): MutableBuffer = ShortBuffer(array.copyOf()) -} - -/** - * Creates a new [ShortBuffer] with the specified [size], where each element is calculated by calling the specified - * [init] function. - * - * The function [init] is called for each array element sequentially starting from the first one. - * It should return the value for a buffer element given its index. - */ -public inline fun ShortBuffer(size: Int, init: (Int) -> Short): ShortBuffer = ShortBuffer(ShortArray(size) { init(it) }) - -/** - * Returns a new [ShortBuffer] of given elements. - */ -public fun ShortBuffer(vararg shorts: Short): ShortBuffer = ShortBuffer(shorts) - -/** - * Returns a new [ShortArray] containing all the elements of this [Buffer]. - */ -public fun Buffer.toShortArray(): ShortArray = when (this) { - is ShortBuffer -> array.copyOf() - else -> ShortArray(size, ::get) -} - -/** - * Returns [ShortBuffer] over this array. - * - * @receiver the array. - * @return the new buffer. - */ -public fun ShortArray.asBuffer(): ShortBuffer = ShortBuffer(this) 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 deleted file mode 100644 index bc3f5b64b..000000000 --- a/kmath-core/src/commonMain/kotlin/space/kscience/kmath/structures/bufferOperation.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import space.kscience.kmath.misc.UnstableKMathAPI - -/** - * Typealias for buffer transformations. - */ -public typealias BufferTransform = (Buffer) -> Buffer - -/** - * Typealias for buffer transformations with suspend function. - */ -public typealias SuspendBufferTransform = suspend (Buffer) -> Buffer - - -/** - * Creates a sequence that returns all elements from this [Buffer]. - */ -public fun Buffer.asSequence(): Sequence = Sequence(::iterator) - -/** - * Creates an iterable that returns all elements from this [Buffer]. - */ -public fun Buffer.asIterable(): Iterable = Iterable(::iterator) - -/** - * Returns a new [List] containing all elements of this buffer. - */ -public fun Buffer.toList(): List = when (this) { - is ArrayBuffer -> array.toList() - is ListBuffer -> list.toList() - is MutableListBuffer -> list.toList() - else -> asSequence().toList() -} - -/** - * Returns a new [MutableList] filled with all elements of this buffer. - * **NOTE:** this method uses a protective copy, so it should not be used in performance-critical code. - */ -@UnstableKMathAPI -public fun Buffer.toMutableList(): MutableList = when (this) { - is ArrayBuffer -> array.toMutableList() - is ListBuffer -> list.toMutableList() - is MutableListBuffer -> list.toMutableList() - else -> MutableList(size, ::get) -} - -/** - * Returns a new [Array] containing all elements of this buffer. - * **NOTE:** this method uses a protective copy, so it should not be used in performance-critical code. - */ -@UnstableKMathAPI -public inline fun Buffer.toTypedArray(): Array = Array(size, ::get) - -/** - * Create a new buffer from this one with the given mapping function and using [Buffer.Companion.auto] buffer factory. - */ -public inline fun Buffer.map(block: (T) -> R): Buffer = - Buffer.auto(size) { block(get(it)) } - -/** - * Create a new buffer from this one with the given mapping function. - * Provided [bufferFactory] is used to construct the new buffer. - */ -public inline fun Buffer.map( - bufferFactory: BufferFactory, - crossinline block: (T) -> R, -): Buffer = bufferFactory(size) { block(get(it)) } - -/** - * Create a new buffer from this one with the given indexed mapping function. - * Provided [BufferFactory] is used to construct the new buffer. - */ -public inline fun Buffer.mapIndexed( - bufferFactory: BufferFactory = Buffer.Companion::auto, - crossinline block: (index: Int, value: T) -> R, -): Buffer = bufferFactory(size) { block(it, get(it)) } - -/** - * Fold given buffer according to [operation] - */ -public inline fun Buffer.fold(initial: R, operation: (acc: R, T) -> R): R { - var accumulator = initial - for (index in this.indices) accumulator = operation(accumulator, get(index)) - return accumulator -} - -/** - * Zip two buffers using given [transform]. - */ -@UnstableKMathAPI -public inline fun Buffer.zip( - other: Buffer, - bufferFactory: BufferFactory = Buffer.Companion::auto, - crossinline transform: (T1, T2) -> R, -): Buffer { - require(size == other.size) { "Buffer size mismatch in zip: expected $size but found ${other.size}" } - return bufferFactory(size) { transform(get(it), other[it]) } -} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/expressions/ExpressionFieldTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/expressions/ExpressionFieldTest.kt new file mode 100644 index 000000000..033b2792f --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/expressions/ExpressionFieldTest.kt @@ -0,0 +1,53 @@ +package scientifik.kmath.expressions + +import scientifik.kmath.operations.Complex +import scientifik.kmath.operations.ComplexField +import scientifik.kmath.operations.RealField +import kotlin.test.Test +import kotlin.test.assertEquals + +class ExpressionFieldTest { + @Test + fun testExpression() { + val context = ExpressionField(RealField) + val expression = with(context) { + val x = variable("x", 2.0) + x * x + 2 * x + one + } + assertEquals(expression("x" to 1.0), 4.0) + assertEquals(expression(), 9.0) + } + + @Test + fun testComplex() { + val context = ExpressionField(ComplexField) + val expression = with(context) { + val x = variable("x", Complex(2.0, 0.0)) + x * x + 2 * x + one + } + assertEquals(expression("x" to Complex(1.0, 0.0)), Complex(4.0, 0.0)) + assertEquals(expression(), Complex(9.0, 0.0)) + } + + @Test + fun separateContext() { + fun ExpressionField.expression(): Expression { + val x = variable("x") + return x * x + 2 * x + one + } + + val expression = ExpressionField(RealField).expression() + assertEquals(expression("x" to 1.0), 4.0) + } + + @Test + fun valueExpression() { + val expressionBuilder: ExpressionField.() -> Expression = { + val x = variable("x") + x * x + 2 * x + one + } + + val expression = ExpressionField(RealField).expressionBuilder() + assertEquals(expression("x" to 1.0), 4.0) + } +} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/MatrixTest.kt similarity index 52% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt rename to kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/MatrixTest.kt index 507f816d3..dcd510e32 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/MatrixTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/MatrixTest.kt @@ -1,32 +1,23 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +package scientifik.kmath.linear -package space.kscience.kmath.linear - -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.nd.as2D +import scientifik.kmath.structures.Matrix +import scientifik.kmath.structures.NDStructure +import scientifik.kmath.structures.as2D import kotlin.test.Test import kotlin.test.assertEquals -import kotlin.test.assertTrue -@UnstableKMathAPI -@OptIn(PerformancePitfall::class) -@Suppress("UNUSED_VARIABLE") class MatrixTest { + @Test fun testTranspose() { - val matrix = LinearSpace.real.one(3, 3) + val matrix = MatrixContext.real.one(3, 3) val transposed = matrix.transpose() - assertTrue { StructureND.contentEquals(matrix, transposed) } + assertEquals(matrix, transposed) } @Test fun testBuilder() { - val matrix = LinearSpace.real.matrix(2, 3)( + val matrix = Matrix.build(2, 3)( 1.0, 0.0, 0.0, 0.0, 1.0, 2.0 ) @@ -48,7 +39,7 @@ class MatrixTest { infix fun Matrix.pow(power: Int): Matrix { var res = this repeat(power - 1) { - res = LinearSpace.real.run { res dot this@pow } + res = res dot this } return res } @@ -58,18 +49,17 @@ class MatrixTest { @Test fun test2DDot() { - val firstMatrix = StructureND.auto(2, 3) { (i, j) -> (i + j).toDouble() }.as2D() - val secondMatrix = StructureND.auto(3, 2) { (i, j) -> (i + j).toDouble() }.as2D() - - LinearSpace.real.run { + val firstMatrix = NDStructure.auto(2,3){ (i, j) -> (i + j).toDouble() }.as2D() + val secondMatrix = NDStructure.auto(3,2){ (i, j) -> (i + j).toDouble() }.as2D() + MatrixContext.real.run { // val firstMatrix = produce(2, 3) { i, j -> (i + j).toDouble() } // val secondMatrix = produce(3, 2) { i, j -> (i + j).toDouble() } val result = firstMatrix dot secondMatrix assertEquals(2, result.rowNum) assertEquals(2, result.colNum) - assertEquals(8.0, result[0, 1]) - assertEquals(8.0, result[1, 0]) - assertEquals(14.0, result[1, 1]) + assertEquals(8.0, result[0,1]) + assertEquals(8.0, result[1,0]) + assertEquals(14.0, result[1,1]) } } -} +} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/RealLUSolverTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/RealLUSolverTest.kt new file mode 100644 index 000000000..56a0b7aad --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/linear/RealLUSolverTest.kt @@ -0,0 +1,51 @@ +package scientifik.kmath.linear + +import scientifik.kmath.structures.Matrix +import kotlin.contracts.ExperimentalContracts +import kotlin.test.Test +import kotlin.test.assertEquals + +@ExperimentalContracts +class RealLUSolverTest { + + @Test + fun testInvertOne() { + val matrix = MatrixContext.real.one(2, 2) + val inverted = MatrixContext.real.inverse(matrix) + assertEquals(matrix, inverted) + } + + @Test + fun testDecomposition() { + val matrix = Matrix.square( + 3.0, 1.0, + 1.0, 3.0 + ) + + MatrixContext.real.run { + val lup = lup(matrix) + + //Check determinant + assertEquals(8.0, lup.determinant) + + assertEquals(lup.p dot matrix, lup.l dot lup.u) + } + } + + @Test + fun testInvert() { + val matrix = Matrix.square( + 3.0, 1.0, + 1.0, 3.0 + ) + + val inverted = MatrixContext.real.inverse(matrix) + + val expected = Matrix.square( + 0.375, -0.125, + -0.125, 0.375 + ) + + assertEquals(expected, inverted) + } +} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/misc/AutoDiffTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/misc/AutoDiffTest.kt new file mode 100644 index 000000000..9dc8f5ef7 --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/misc/AutoDiffTest.kt @@ -0,0 +1,182 @@ +package scientifik.kmath.misc + +import scientifik.kmath.operations.RealField +import scientifik.kmath.structures.asBuffer +import kotlin.math.PI +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class AutoDiffTest { + + fun Variable(int: Int) = Variable(int.toDouble()) + + fun deriv(body: AutoDiffField.() -> Variable) = RealField.deriv(body) + + @Test + fun testPlusX2() { + val x = Variable(3) // diff w.r.t this x at 3 + val y = deriv { x + x } + assertEquals(6.0, y.value) // y = x + x = 6 + assertEquals(2.0, y.deriv(x)) // dy/dx = 2 + } + + @Test + fun testPlus() { + // two variables + val x = Variable(2) + val y = Variable(3) + val z = deriv { x + y } + assertEquals(5.0, z.value) // z = x + y = 5 + assertEquals(1.0, z.deriv(x)) // dz/dx = 1 + assertEquals(1.0, z.deriv(y)) // dz/dy = 1 + } + + @Test + fun testMinus() { + // two variables + val x = Variable(7) + val y = Variable(3) + val z = deriv { x - y } + assertEquals(4.0, z.value) // z = x - y = 4 + assertEquals(1.0, z.deriv(x)) // dz/dx = 1 + assertEquals(-1.0, z.deriv(y)) // dz/dy = -1 + } + + @Test + fun testMulX2() { + val x = Variable(3) // diff w.r.t this x at 3 + val y = deriv { x * x } + assertEquals(9.0, y.value) // y = x * x = 9 + assertEquals(6.0, y.deriv(x)) // dy/dx = 2 * x = 7 + } + + @Test + fun testSqr() { + val x = Variable(3) + val y = deriv { sqr(x) } + assertEquals(9.0, y.value) // y = x ^ 2 = 9 + assertEquals(6.0, y.deriv(x)) // dy/dx = 2 * x = 7 + } + + @Test + fun testSqrSqr() { + val x = Variable(2) + val y = deriv { sqr(sqr(x)) } + assertEquals(16.0, y.value) // y = x ^ 4 = 16 + assertEquals(32.0, y.deriv(x)) // dy/dx = 4 * x^3 = 32 + } + + @Test + fun testX3() { + val x = Variable(2) // diff w.r.t this x at 2 + val y = deriv { x * x * x } + assertEquals(8.0, y.value) // y = x * x * x = 8 + assertEquals(12.0, y.deriv(x)) // dy/dx = 3 * x * x = 12 + } + + @Test + fun testDiv() { + val x = Variable(5) + val y = Variable(2) + val z = deriv { x / y } + assertEquals(2.5, z.value) // z = x / y = 2.5 + assertEquals(0.5, z.deriv(x)) // dz/dx = 1 / y = 0.5 + assertEquals(-1.25, z.deriv(y)) // dz/dy = -x / y^2 = -1.25 + } + + @Test + fun testPow3() { + val x = Variable(2) // diff w.r.t this x at 2 + val y = deriv { pow(x, 3) } + assertEquals(8.0, y.value) // y = x ^ 3 = 8 + assertEquals(12.0, y.deriv(x)) // dy/dx = 3 * x ^ 2 = 12 + } + + @Test + fun testPowFull() { + val x = Variable(2) + val y = Variable(3) + val z = deriv { pow(x, y) } + assertApprox(8.0, z.value) // z = x ^ y = 8 + assertApprox(12.0, z.deriv(x)) // dz/dx = y * x ^ (y - 1) = 12 + assertApprox(8.0 * kotlin.math.ln(2.0), z.deriv(y)) // dz/dy = x ^ y * ln(x) + } + + @Test + fun testFromPaper() { + val x = Variable(3) + val y = deriv { 2 * x + x * x * x } + assertEquals(33.0, y.value) // y = 2 * x + x * x * x = 33 + assertEquals(29.0, y.deriv(x)) // dy/dx = 2 + 3 * x * x = 29 + } + + @Test + fun testInnerVariable() { + val x = Variable(1) + val y = deriv { + Variable(1) * x + } + assertEquals(1.0, y.value) // y = x ^ n = 1 + assertEquals(1.0, y.deriv(x)) // dy/dx = n * x ^ (n - 1) = n - 1 + } + + @Test + fun testLongChain() { + val n = 10_000 + val x = Variable(1) + val y = deriv { + var res = Variable(1) + for (i in 1..n) res *= x + res + } + assertEquals(1.0, y.value) // y = x ^ n = 1 + assertEquals(n.toDouble(), y.deriv(x)) // dy/dx = n * x ^ (n - 1) = n - 1 + } + + @Test + fun testExample() { + val x = Variable(2) + val y = deriv { sqr(x) + 5 * x + 3 } + assertEquals(17.0, y.value) // the value of result (y) + assertEquals(9.0, y.deriv(x)) // dy/dx + } + + @Test + fun testSqrt() { + val x = Variable(16) + val y = deriv { sqrt(x) } + assertEquals(4.0, y.value) // y = x ^ 1/2 = 4 + assertEquals(1.0 / 8, y.deriv(x)) // dy/dx = 1/2 / x ^ 1/4 = 1/8 + } + + @Test + fun testSin() { + val x = Variable(PI / 6) + val y = deriv { sin(x) } + assertApprox(0.5, y.value) // y = sin(PI/6) = 0.5 + assertApprox(kotlin.math.sqrt(3.0) / 2, y.deriv(x)) // dy/dx = cos(PI/6) = sqrt(3)/2 + } + + @Test + fun testCos() { + val x = Variable(PI / 6) + val y = deriv { cos(x) } + assertApprox(kotlin.math.sqrt(3.0) / 2, y.value) // y = cos(PI/6) = sqrt(3)/2 + assertApprox(-0.5, y.deriv(x)) // dy/dx = -sin(PI/6) = -0.5 + } + + @Test + fun testDivGrad() { + val x = Variable(1.0) + val y = Variable(2.0) + val res = deriv { x * x + y * y } + assertEquals(6.0, res.div()) + assertTrue(res.grad(x, y).contentEquals(doubleArrayOf(2.0, 4.0).asBuffer())) + } + + private fun assertApprox(a: Double, b: Double) { + if ((a - b) > 1e-10) assertEquals(a, b) + } + +} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/misc/CumulativeKtTest.kt similarity index 60% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt rename to kmath-core/src/commonTest/kotlin/scientifik/kmath/misc/CumulativeKtTest.kt index aa7abd8ff..e7c99e7d0 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/misc/CumulativeKtTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/misc/CumulativeKtTest.kt @@ -1,9 +1,4 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.misc +package scientifik.kmath.misc import kotlin.test.Test import kotlin.test.assertEquals @@ -15,4 +10,4 @@ class CumulativeKtTest { val cumulative = initial.cumulativeSum() assertEquals(listOf(-1.0, 1.0, 2.0, 3.0), cumulative) } -} +} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntAlgebraTest.kt similarity index 63% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt rename to kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntAlgebraTest.kt index 75100b116..5ae977196 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntAlgebraTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntAlgebraTest.kt @@ -1,20 +1,9 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +package scientifik.kmath.operations -package space.kscience.kmath.operations - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.testutils.RingVerifier -import kotlin.math.pow import kotlin.test.Test import kotlin.test.assertEquals -internal class BigIntAlgebraTest { - @Test - fun verify() = BigIntField { RingVerifier(this, +"42", +"10", +"-12", 10).verify() } - +class BigIntAlgebraTest { @Test fun testKBigIntegerRingSum() { val res = BigIntField { @@ -23,18 +12,6 @@ internal class BigIntAlgebraTest { assertEquals(res, 1_000_000.toBigInt()) } - @UnstableKMathAPI - @Test - fun testKBigIntegerRingPow() { - for (num in -5..5) - for (exponent in 0U..10U) - assertEquals( - num.toDouble().pow(exponent.toInt()).toLong().toBigInt(), - num.toBigInt().pow(exponent), - "$num ^ $exponent" - ) - } - @Test fun testKBigIntegerRingSum_100_000_000__100_000_000() { BigIntField { @@ -70,3 +47,4 @@ internal class BigIntAlgebraTest { } } + diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntConstructorTest.kt similarity index 66% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt rename to kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntConstructorTest.kt index c121c86ae..2af1b7e50 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConstructorTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntConstructorTest.kt @@ -1,9 +1,4 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations +package scientifik.kmath.operations import kotlin.test.Test import kotlin.test.assertEquals @@ -24,8 +19,8 @@ class BigIntConstructorTest { @Test fun testConstructor_0xffffffffaL() { - val x = (-0xffffffffaL).toBigInt() + val x = -0xffffffffaL.toBigInt() val y = uintArrayOf(0xfffffffaU, 0xfU).toBigInt(-1) assertEquals(x, y) } -} +} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntConversionsTest.kt similarity index 51% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt rename to kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntConversionsTest.kt index 78dcdfe19..51b9509e0 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntConversionsTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntConversionsTest.kt @@ -1,49 +1,16 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations +package scientifik.kmath.operations import kotlin.test.Test import kotlin.test.assertEquals -import kotlin.test.assertNull @kotlin.ExperimentalUnsignedTypes class BigIntConversionsTest { - - @Test - fun testEmptyString() { - assertNull("".parseBigInteger()) - assertNull("+".parseBigInteger()) - assertNull("-".parseBigInteger()) - - assertNull("0x".parseBigInteger()) - assertNull("+0x".parseBigInteger()) - assertNull("-0x".parseBigInteger()) - - - assertNull("_".parseBigInteger()) - assertNull("+_".parseBigInteger()) - assertNull("-_".parseBigInteger()) - - assertNull("0x_".parseBigInteger()) - assertNull("+0x_".parseBigInteger()) - assertNull("-0x_".parseBigInteger()) - } - @Test fun testToString0x10() { val x = 0x10.toBigInt() assertEquals("0x10", x.toString()) } - @Test - fun testUnderscores() { - assertEquals("0x10", "0x_1_0_".parseBigInteger().toString()) - assertEquals("0xa", "_1_0_".parseBigInteger().toString()) - } - @Test fun testToString0x17ffffffd() { val x = 0x17ffffffdL.toBigInt() @@ -52,7 +19,7 @@ class BigIntConversionsTest { @Test fun testToString_0x17ead2ffffd() { - val x = (-0x17ead2ffffdL).toBigInt() + val x = -0x17ead2ffffdL.toBigInt() assertEquals("-0x17ead2ffffd", x.toString()) } @@ -73,4 +40,4 @@ class BigIntConversionsTest { val x = "-7059135710711894913860".parseBigInteger() assertEquals("-0x17ead2ffffd11223344", x.toString()) } -} +} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntOperationsTest.kt similarity index 82% rename from kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt rename to kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntOperationsTest.kt index 11b8b161c..72ac9f229 100644 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/BigIntOperationsTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/BigIntOperationsTest.kt @@ -1,16 +1,7 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +package scientifik.kmath.operations -package space.kscience.kmath.operations - -import kotlin.random.Random -import kotlin.random.nextUInt import kotlin.test.Test -import kotlin.test.assertContentEquals import kotlin.test.assertEquals -import kotlin.test.assertFalse @kotlin.ExperimentalUnsignedTypes class BigIntOperationsTest { @@ -40,7 +31,7 @@ class BigIntOperationsTest { @Test fun testUnaryMinus() { val x = 1234.toBigInt() - val y = (-1234).toBigInt() + val y = -1234.toBigInt() assertEquals(-x, y) } @@ -57,18 +48,18 @@ class BigIntOperationsTest { @Test fun testMinus__2_1() { - val x = (-2).toBigInt() + val x = -2.toBigInt() val y = 1.toBigInt() val res = x - y - val sum = (-3).toBigInt() + val sum = -3.toBigInt() assertEquals(sum, res) } @Test fun testMinus___2_1() { - val x = (-2).toBigInt() + val x = -2.toBigInt() val y = 1.toBigInt() val res = -x - y @@ -83,7 +74,7 @@ class BigIntOperationsTest { val y = 0xffffffffaL.toBigInt() val res = x - y - val sum = (-0xfffffcfc1L).toBigInt() + val sum = -0xfffffcfc1L.toBigInt() assertEquals(sum, res) } @@ -101,11 +92,11 @@ class BigIntOperationsTest { @Test fun testMultiply__2_3() { - val x = (-2).toBigInt() + val x = -2.toBigInt() val y = 3.toBigInt() val res = x * y - val prod = (-6).toBigInt() + val prod = -6.toBigInt() assertEquals(prod, res) } @@ -138,7 +129,7 @@ class BigIntOperationsTest { val y = -0xfff456 val res = x * y - val prod = (-0xffe579ad5dc2L).toBigInt() + val prod = -0xffe579ad5dc2L.toBigInt() assertEquals(prod, res) } @@ -154,17 +145,6 @@ class BigIntOperationsTest { assertEquals(prod, res) } - @Test - fun testKaratsuba() { - val random = Random(2222) - val x = uintArrayOf(12U, 345U) - val y = uintArrayOf(6U, 789U) - assertContentEquals(BigInt.naiveMultiplyMagnitudes(x, y), BigInt.karatsubaMultiplyMagnitudes(x, y)) - val x1 = UIntArray(Random.nextInt(100, 1000)) { random.nextUInt() } - val y1 = UIntArray(Random.nextInt(100, 1000)) { random.nextUInt() } - assertContentEquals(BigInt.naiveMultiplyMagnitudes(x1, y1), BigInt.karatsubaMultiplyMagnitudes(x1, y1)) - } - @Test fun test_shr_20() { val x = 20.toBigInt() @@ -279,7 +259,7 @@ class BigIntOperationsTest { val y = -3 val res = x / y - val div = (-6).toBigInt() + val div = -6.toBigInt() assertEquals(div, res) } @@ -287,10 +267,10 @@ class BigIntOperationsTest { @Test fun testBigDivision_20__3() { val x = 20.toBigInt() - val y = (-3).toBigInt() + val y = -3.toBigInt() val res = x / y - val div = (-6).toBigInt() + val div = -6.toBigInt() assertEquals(div, res) } @@ -398,12 +378,4 @@ class BigIntOperationsTest { return assertEquals(res, x % mod) } - - @Test - fun testNotEqualsOtherTypeInstanceButButNotFails() = assertFalse(0.toBigInt().equals("")) - - @Test - fun testIntAbsOverflow() { - assertEquals((-Int.MAX_VALUE.toLong().toBigInt() - 1.toBigInt()) * 2, 2.toBigInt() * Int.MIN_VALUE) - } -} +} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/RealFieldTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/RealFieldTest.kt new file mode 100644 index 000000000..779cfc4b8 --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/operations/RealFieldTest.kt @@ -0,0 +1,14 @@ +package scientifik.kmath.operations + +import kotlin.test.Test +import kotlin.test.assertEquals + +class RealFieldTest { + @Test + fun testSqrt() { + val sqrt = RealField { + sqrt(25 * one) + } + assertEquals(5.0, sqrt) + } +} \ No newline at end of file diff --git a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/ComplexBufferSpecTest.kt similarity index 52% rename from kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt rename to kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/ComplexBufferSpecTest.kt index 87239654d..454683dac 100644 --- a/kmath-complex/src/commonTest/kotlin/space/kscience/kmath/complex/ComplexBufferSpecTest.kt +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/ComplexBufferSpecTest.kt @@ -1,11 +1,7 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +package scientifik.kmath.structures -package space.kscience.kmath.complex - -import space.kscience.kmath.structures.Buffer +import scientifik.kmath.operations.Complex +import scientifik.kmath.operations.complex import kotlin.test.Test import kotlin.test.assertEquals diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NDFieldTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NDFieldTest.kt new file mode 100644 index 000000000..39cce5c67 --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NDFieldTest.kt @@ -0,0 +1,13 @@ +package scientifik.kmath.structures + +import kotlin.test.Test +import kotlin.test.assertEquals + + +class NDFieldTest { + @Test + fun testStrides() { + val ndArray = NDElement.real(intArrayOf(10, 10)) { (it[0] + it[1]).toDouble() } + assertEquals(ndArray[5, 5], 10.0) + } +} \ No newline at end of file diff --git a/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NumberNDFieldTest.kt b/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NumberNDFieldTest.kt new file mode 100644 index 000000000..60f1f9979 --- /dev/null +++ b/kmath-core/src/commonTest/kotlin/scientifik/kmath/structures/NumberNDFieldTest.kt @@ -0,0 +1,72 @@ +package scientifik.kmath.structures + +import scientifik.kmath.operations.Norm +import scientifik.kmath.structures.NDElement.Companion.real2D +import kotlin.math.abs +import kotlin.math.pow +import kotlin.test.Test +import kotlin.test.assertEquals + +class NumberNDFieldTest { + val array1 = real2D(3, 3) { i, j -> (i + j).toDouble() } + val array2 = real2D(3, 3) { i, j -> (i - j).toDouble() } + + @Test + fun testSum() { + val sum = array1 + array2 + assertEquals(4.0, sum[2, 2]) + } + + @Test + fun testProduct() { + val product = array1 * array2 + assertEquals(0.0, product[2, 2]) + } + + @Test + fun testGeneration() { + + val array = real2D(3, 3) { i, j -> (i * 10 + j).toDouble() } + + for (i in 0..2) { + for (j in 0..2) { + val expected = (i * 10 + j).toDouble() + assertEquals(expected, array[i, j], "Error at index [$i, $j]") + } + } + } + + @Test + fun testExternalFunction() { + val function: (Double) -> Double = { x -> x.pow(2) + 2 * x + 1 } + val result = function(array1) + 1.0 + assertEquals(10.0, result[1, 1]) + } + + @Test + fun testLibraryFunction() { + val abs: (Double) -> Double = ::abs + val result = abs(array2) + assertEquals(2.0, result[0, 2]) + } + + @Test + fun combineTest() { + val division = array1.combine(array2, Double::div) + } + + object L2Norm : Norm, Double> { + override fun norm(arg: NDStructure): Double { + return kotlin.math.sqrt(arg.elements().sumByDouble { it.second.toDouble() }) + } + } + + @Test + fun testInternalContext() { + NDField.real(*array1.shape).run { + with(L2Norm) { + 1 + norm(array1) + exp(array2) + } + } + } +} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt deleted file mode 100644 index 034839041..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/ExpressionFieldTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.expressions - -import space.kscience.kmath.operations.DoubleField -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFails - -class ExpressionFieldTest { - val x by symbol - - @Test - fun testExpression() { - val expression = with(FunctionalExpressionField(DoubleField)) { - val x by binding() - x * x + 2 * x + one - } - - assertEquals(expression(x to 1.0), 4.0) - assertFails { expression() } - } - - @Test - fun separateContext() { - fun FunctionalExpressionField.expression(): Expression { - val x by binding() - return x * x + 2 * x + one - } - - val expression = FunctionalExpressionField(DoubleField).expression() - assertEquals(expression(x to 1.0), 4.0) - } - - @Test - fun valueExpression() { - val expressionBuilder: FunctionalExpressionField.() -> Expression = { - val x by binding() - x * x + 2 * x + one - } - - val expression = FunctionalExpressionField(DoubleField).expressionBuilder() - assertEquals(expression(x to 1.0), 4.0) - } -} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt deleted file mode 100644 index 8bf852653..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/InterpretTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.expressions - -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.BooleanAlgebra -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.invoke -import kotlin.test.Test -import kotlin.test.assertEquals - - -internal class InterpretTest { - @Test - fun interpretation() { - val expr = MstField { - x * 2.0 + number(2.0) / x - 16.0 - }.toExpression(DoubleField) - assertEquals(-10.69, expr(x to 2.2), 0.02) - } - - @Test - @UnstableKMathAPI - fun booleanAlgebra() { - val expr = MstLogicAlgebra { - x and const(true) - }.toExpression(BooleanAlgebra) - - assertEquals(true, expr(x to true)) - assertEquals(false, expr(x to false)) - } -} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt deleted file mode 100644 index 7d8ff6202..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/expressions/SimpleAutoDiffTest.kt +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.expressions - -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.bindSymbol -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asBuffer -import kotlin.math.E -import kotlin.math.PI -import kotlin.math.pow -import kotlin.math.sqrt -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -internal class SimpleAutoDiffTest { - - fun dx( - xBinding: Pair, - body: SimpleAutoDiffField.(x: AutoDiffValue) -> AutoDiffValue, - ): DerivationResult = DoubleField.simpleAutoDiff(xBinding) { body(bindSymbol(xBinding.first)) } - - fun dxy( - xBinding: Pair, - yBinding: Pair, - body: SimpleAutoDiffField.(x: AutoDiffValue, y: AutoDiffValue) -> AutoDiffValue, - ): DerivationResult = DoubleField.simpleAutoDiff(xBinding, yBinding) { - body(bindSymbol(xBinding.first), bindSymbol(yBinding.first)) - } - - fun diff(block: SimpleAutoDiffField.() -> AutoDiffValue): SimpleAutoDiffExpression { - return SimpleAutoDiffExpression(DoubleField, block) - } - - val x by symbol - val y by symbol - val z by symbol - - @Test - fun testPlusX2() { - val y = DoubleField.simpleAutoDiff(x to 3.0) { - // diff w.r.t this x at 3 - val x = bindSymbol(x) - x + x - } - assertEquals(6.0, y.value) // y = x + x = 6 - assertEquals(2.0, y.derivative(x)) // dy/dx = 2 - } - - @Test - fun testPlusX2Expr() { - val expr = diff { - val x = bindSymbol(x) - x + x - } - assertEquals(6.0, expr(x to 3.0)) // y = x + x = 6 - assertEquals(2.0, expr.derivative(x)(x to 3.0)) // dy/dx = 2 - } - - - @Test - fun testPlus() { - // two variables - val z = DoubleField.simpleAutoDiff(x to 2.0, y to 3.0) { - val x = bindSymbol(x) - val y = bindSymbol(y) - x + y - } - assertEquals(5.0, z.value) // z = x + y = 5 - assertEquals(1.0, z.derivative(x)) // dz/dx = 1 - assertEquals(1.0, z.derivative(y)) // dz/dy = 1 - } - - @Test - fun testMinus() { - // two variables - val z = DoubleField.simpleAutoDiff(x to 7.0, y to 3.0) { - val x = bindSymbol(x) - val y = bindSymbol(y) - - x - y - } - assertEquals(4.0, z.value) // z = x - y = 4 - assertEquals(1.0, z.derivative(x)) // dz/dx = 1 - assertEquals(-1.0, z.derivative(y)) // dz/dy = -1 - } - - @Test - fun testMulX2() { - val y = dx(x to 3.0) { x -> - // diff w.r.t this x at 3 - x * x - } - assertEquals(9.0, y.value) // y = x * x = 9 - assertEquals(6.0, y.derivative(x)) // dy/dx = 2 * x = 7 - } - - @Test - fun testSqr() { - val y = dx(x to 3.0) { x -> sqr(x) } - assertEquals(9.0, y.value) // y = x ^ 2 = 9 - assertEquals(6.0, y.derivative(x)) // dy/dx = 2 * x = 7 - } - - @Test - fun testSqrSqr() { - val y = dx(x to 2.0) { x -> sqr(sqr(x)) } - assertEquals(16.0, y.value) // y = x ^ 4 = 16 - assertEquals(32.0, y.derivative(x)) // dy/dx = 4 * x^3 = 32 - } - - @Test - fun testX3() { - val y = dx(x to 2.0) { x -> - // diff w.r.t this x at 2 - x * x * x - } - assertEquals(8.0, y.value) // y = x * x * x = 8 - assertEquals(12.0, y.derivative(x)) // dy/dx = 3 * x * x = 12 - } - - @Test - fun testDiv() { - val z = dxy(x to 5.0, y to 2.0) { x, y -> - x / y - } - assertEquals(2.5, z.value) // z = x / y = 2.5 - assertEquals(0.5, z.derivative(x)) // dz/dx = 1 / y = 0.5 - assertEquals(-1.25, z.derivative(y)) // dz/dy = -x / y^2 = -1.25 - } - - @Test - fun testPow3() { - val y = dx(x to 2.0) { x -> - // diff w.r.t this x at 2 - pow(x, 3) - } - assertEquals(8.0, y.value) // y = x ^ 3 = 8 - assertEquals(12.0, y.derivative(x)) // dy/dx = 3 * x ^ 2 = 12 - } - - @Test - fun testPowFull() { - val z = dxy(x to 2.0, y to 3.0) { x, y -> - pow(x, y) - } - assertApprox(8.0, z.value) // z = x ^ y = 8 - assertApprox(12.0, z.derivative(x)) // dz/dx = y * x ^ (y - 1) = 12 - assertApprox(8.0 * kotlin.math.ln(2.0), z.derivative(y)) // dz/dy = x ^ y * ln(x) - } - - @Test - fun testFromPaper() { - val y = dx(x to 3.0) { x -> 2 * x + x * x * x } - assertEquals(33.0, y.value) // y = 2 * x + x * x * x = 33 - assertEquals(29.0, y.derivative(x)) // dy/dx = 2 + 3 * x * x = 29 - } - - @Test - fun testInnerVariable() { - val y = dx(x to 1.0) { x -> - const(1.0) * x - } - assertEquals(1.0, y.value) // y = x ^ n = 1 - assertEquals(1.0, y.derivative(x)) // dy/dx = n * x ^ (n - 1) = n - 1 - } - - @Test - fun testLongChain() { - val n = 10_000 - val y = dx(x to 1.0) { x -> - var res = const(1.0) - for (i in 1..n) res *= x - res - } - assertEquals(1.0, y.value) // y = x ^ n = 1 - assertEquals(n.toDouble(), y.derivative(x)) // dy/dx = n * x ^ (n - 1) = n - 1 - } - - @Test - fun testExample() { - val y = dx(x to 2.0) { x -> sqr(x) + 5 * x + 3 } - assertEquals(17.0, y.value) // the value of result (y) - assertEquals(9.0, y.derivative(x)) // dy/dx - } - - @Test - fun testSqrt() { - val y = dx(x to 16.0) { x -> sqrt(x) } - assertEquals(4.0, y.value) // y = x ^ 1/2 = 4 - assertEquals(1.0 / 8, y.derivative(x)) // dy/dx = 1/2 / x ^ 1/4 = 1/8 - } - - @Test - fun testSin() { - val y = dx(x to PI / 6.0) { x -> sin(x) } - assertApprox(0.5, y.value) // y = sin(PI/6) = 0.5 - assertApprox(sqrt(3.0) / 2, y.derivative(x)) // dy/dx = cos(pi/6) = sqrt(3)/2 - } - - @Test - fun testCos() { - val y = dx(x to PI / 6) { x -> cos(x) } - assertApprox(sqrt(3.0) / 2, y.value) //y = cos(pi/6) = sqrt(3)/2 - assertApprox(-0.5, y.derivative(x)) // dy/dx = -sin(pi/6) = -0.5 - } - - @Test - fun testTan() { - val y = dx(x to PI / 6) { x -> tan(x) } - assertApprox(1.0 / sqrt(3.0), y.value) // y = tan(pi/6) = 1/sqrt(3) - assertApprox(4.0 / 3.0, y.derivative(x)) // dy/dx = sec(pi/6)^2 = 4/3 - } - - @Test - fun testAsin() { - val y = dx(x to PI / 6) { x -> asin(x) } - assertApprox(kotlin.math.asin(PI / 6.0), y.value) // y = asin(pi/6) - assertApprox(6.0 / sqrt(36 - PI * PI), y.derivative(x)) // dy/dx = 6/sqrt(36-pi^2) - } - - @Test - fun testAcos() { - val y = dx(x to PI / 6) { x -> acos(x) } - assertApprox(kotlin.math.acos(PI / 6.0), y.value) // y = acos(pi/6) - assertApprox(-6.0 / sqrt(36.0 - PI * PI), y.derivative(x)) // dy/dx = -6/sqrt(36-pi^2) - } - - @Test - fun testAtan() { - val y = dx(x to PI / 6) { x -> atan(x) } - assertApprox(kotlin.math.atan(PI / 6.0), y.value) // y = atan(pi/6) - assertApprox(36.0 / (36.0 + PI * PI), y.derivative(x)) // dy/dx = 36/(36+pi^2) - } - - @Test - fun testSinh() { - val y = dx(x to 0.0) { x -> sinh(x) } - assertApprox(kotlin.math.sinh(0.0), y.value) // y = sinh(0) - assertApprox(kotlin.math.cosh(0.0), y.derivative(x)) // dy/dx = cosh(0) - } - - @Test - fun testCosh() { - val y = dx(x to 0.0) { x -> cosh(x) } - assertApprox(1.0, y.value) //y = cosh(0) - assertApprox(0.0, y.derivative(x)) // dy/dx = sinh(0) - } - - @Test - fun testTanh() { - val y = dx(x to 1.0) { x -> tanh(x) } - assertApprox((E * E - 1) / (E * E + 1), y.value) // y = tanh(pi/6) - assertApprox(1.0 / kotlin.math.cosh(1.0).pow(2), y.derivative(x)) // dy/dx = sech(pi/6)^2 - } - - @Test - fun testAsinh() { - val y = dx(x to PI / 6) { x -> asinh(x) } - assertApprox(kotlin.math.asinh(PI / 6.0), y.value) // y = asinh(pi/6) - assertApprox(6.0 / sqrt(36 + PI * PI), y.derivative(x)) // dy/dx = 6/sqrt(pi^2+36) - } - - @Test - fun testAcosh() { - val y = dx(x to PI / 6) { x -> acosh(x) } - assertApprox(kotlin.math.acosh(PI / 6.0), y.value) // y = acosh(pi/6) - assertApprox(-6.0 / sqrt(36.0 - PI * PI), y.derivative(x)) // dy/dx = -6/sqrt(36-pi^2) - } - - @Test - fun testAtanh() { - val y = dx(x to PI / 6) { x -> atanh(x) } - assertApprox(kotlin.math.atanh(PI / 6.0), y.value) // y = atanh(pi/6) - assertApprox(-36.0 / (PI * PI - 36.0), y.derivative(x)) // dy/dx = -36/(pi^2-36) - } - - @Test - fun testDivGrad() { - val res = dxy(x to 1.0, y to 2.0) { x, y -> x * x + y * y } - assertEquals(6.0, res.div()) - assertTrue(Buffer.contentEquals(res.grad(x, y), doubleArrayOf(2.0, 4.0).asBuffer())) - } - - private fun assertApprox(a: Double, b: Double) { - if ((a - b) > 1e-10) assertEquals(a, b) - } -} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt deleted file mode 100644 index 98b0bf02a..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/linear/DoubleLUSolverTest.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.linear - -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.StructureND -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -@OptIn(PerformancePitfall::class) -fun assertMatrixEquals(expected: StructureND, actual: StructureND) { - assertTrue { StructureND.contentEquals(expected, actual) } -} - -@UnstableKMathAPI -class DoubleLUSolverTest { - - @Test - fun testInvertOne() { - val matrix = LinearSpace.real.one(2, 2) - val inverted = LinearSpace.real.inverseWithLup(matrix) - assertMatrixEquals(matrix, inverted) - } - - @Test - fun testDecomposition() { - LinearSpace.real.run { - val matrix = matrix(2, 2)( - 3.0, 1.0, - 2.0, 3.0 - ) - - val lup = lup(matrix) - - //Check determinant - assertEquals(7.0, lup.determinant) - - assertMatrixEquals(lup.p dot matrix, lup.l dot lup.u) - } - } - - @Test - fun testInvert() { - val matrix = LinearSpace.real.matrix(2, 2)( - 3.0, 1.0, - 1.0, 3.0 - ) - - val inverted = LinearSpace.real.inverseWithLup(matrix) - - val expected = LinearSpace.real.matrix(2, 2)( - 0.375, -0.125, - -0.125, 0.375 - ) - - assertMatrixEquals(expected, inverted) - } -} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt deleted file mode 100644 index 9be75d68e..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/operations/DoubleFieldTest.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations - -import space.kscience.kmath.testutils.FieldVerifier -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class DoubleFieldTest { - @Test - fun verify() = FieldVerifier(DoubleField, 42.0, 66.0, 2.0, 5).verify() - - @Test - fun testSqrt() { - val sqrt = DoubleField { sqrt(25 * one) } - assertEquals(5.0, sqrt) - } - - @Test - fun testPow() = DoubleField { - val num = 5 * one - assertEquals(5.0, power(num, 1), 0.01) - assertEquals(25.0, power(num, 2), 0.01) - assertEquals(1.0, power(num, 0), 0.01) - assertEquals(0.2, power(num, -1), 0.01) - assertEquals(0.04, power(num, -2), 0.01) - assertEquals(0.0, power(num, Int.MIN_VALUE), 0.01) - assertEquals(1.0, power(zero, 0), 0.01) - } -} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt deleted file mode 100644 index f623b00e8..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NDFieldTest.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import space.kscience.kmath.nd.AlgebraND -import space.kscience.kmath.nd.get -import space.kscience.kmath.nd.real -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.testutils.FieldVerifier -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class NDFieldTest { - @Test - fun verify() { - (AlgebraND.real(12, 32)) { FieldVerifier(this, one + 3, one - 23, one * 12, 6.66) } - } - - @Test - fun testStrides() { - val ndArray = AlgebraND.real(10, 10).produce { (it[0] + it[1]).toDouble() } - assertEquals(ndArray[5, 5], 10.0) - } -} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt deleted file mode 100644 index 86e9bb083..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/structures/NumberNDFieldTest.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import space.kscience.kmath.linear.LinearSpace -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.Norm -import space.kscience.kmath.operations.invoke -import kotlin.math.abs -import kotlin.math.pow -import kotlin.test.Test -import kotlin.test.assertEquals - -@Suppress("UNUSED_VARIABLE") -class NumberNDFieldTest { - val algebra = AlgebraND.real(3, 3) - val array1 = algebra.produce { (i, j) -> (i + j).toDouble() } - val array2 = algebra.produce { (i, j) -> (i - j).toDouble() } - - @Test - fun testSum() { - algebra { - val sum = array1 + array2 - assertEquals(4.0, sum[2, 2]) - } - } - - @Test - fun testProduct() { - algebra { - val product = array1 * array2 - assertEquals(0.0, product[2, 2]) - } - } - - @Test - fun testGeneration() { - - val array = LinearSpace.real.buildMatrix(3, 3) { i, j -> - (i * 10 + j).toDouble() - } - - for (i in 0..2) - for (j in 0..2) { - val expected = (i * 10 + j).toDouble() - assertEquals(expected, array[i, j], "Error at index [$i, $j]") - } - } - - @Test - fun testExternalFunction() { - algebra { - val function: (Double) -> Double = { x -> x.pow(2) + 2 * x + 1 } - val result = function(array1) + 1.0 - assertEquals(10.0, result[1, 1]) - } - } - - @Test - fun testLibraryFunction() { - algebra { - val abs: (Double) -> Double = ::abs - val result = abs(array2) - assertEquals(2.0, result[0, 2]) - } - } - - @Test - fun combineTest() { - val division = array1.combine(array2, Double::div) - } - - object L2Norm : Norm, Double> { - @OptIn(PerformancePitfall::class) - override fun norm(arg: StructureND): Double = - kotlin.math.sqrt(arg.elements().sumOf { it.second.toDouble() }) - } - - @Test - fun testInternalContext() { - algebra { - (AlgebraND.real(*array1.shape)) { with(L2Norm) { 1 + norm(array1) + exp(array2) } } - } - } -} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt deleted file mode 100644 index 544e05707..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/AlgebraicVerifier.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.testutils - -import space.kscience.kmath.operations.Algebra - -internal interface AlgebraicVerifier where A : Algebra { - val algebra: A - - fun verify() -} 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 deleted file mode 100644 index d0a312bb2..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/FieldVerifier.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.testutils - -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke -import kotlin.test.assertEquals -import kotlin.test.assertNotEquals - -internal class FieldVerifier>( - algebra: A, a: T, b: T, c: T, x: Number, -) : RingVerifier(algebra, a, b, c, x) { - - override fun verify() { - super.verify() - - algebra { - assertEquals(a + b, b + a, "Addition in $algebra is not commutative.") - assertEquals(a * b, b * a, "Multiplication in $algebra is not commutative.") - assertNotEquals(a / b, b / a, "Division in $algebra is not anti-commutative.") - assertNotEquals((a / b) / c, a / (b / c), "Division in $algebra is associative.") - assertEquals((a + b) / c, (a / c) + (b / c), "Division in $algebra is not right-distributive.") - assertEquals(a, a / one, "$one in $algebra is not neutral division element.") - assertEquals(one, one / a * a, "$algebra does not provide single reciprocal element.") - assertEquals(zero / a, zero, "$zero in $algebra is not left neutral element for division.") - assertEquals(-one, a / (-a), "Division by sign reversal element in $algebra does not give ${-one}.") - } - } -} 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 deleted file mode 100644 index 3b0b49f31..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/RingVerifier.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.testutils - -import space.kscience.kmath.operations.Ring -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) : - SpaceVerifier(algebra, a, b, c, x) where A : Ring, A : ScaleOperations { - - override fun verify() { - super.verify() - - algebra { - assertEquals(a + b, b + a, "Addition in $algebra is not commutative.") - assertEquals(a * b * c, a * (b * c), "Multiplication in $algebra is not associative.") - assertEquals(c * (a + b), (c * a) + (c * b), "Multiplication in $algebra is not distributive.") - assertEquals(a * one, one * a, "$one in $algebra is not a neutral multiplication element.") - assertEquals(a, one * a, "$one in $algebra is not a neutral multiplication element.") - assertEquals(a, a * one, "$one in $algebra is not a neutral multiplication element.") - assertEquals(a, one * a, "$one in $algebra is not a neutral multiplication element.") - assertEquals(a, a * one * one, "Multiplication by $one in $algebra is not idempotent.") - assertEquals(a, a * one * one * one, "Multiplication by $one in $algebra is not idempotent.") - assertEquals(a, a * one * one * one * one, "Multiplication by $one in $algebra is not idempotent.") - assertEquals(zero, a * zero, "Multiplication by $zero in $algebra doesn't give $zero.") - assertEquals(zero, zero * a, "Multiplication by $zero in $algebra doesn't give $zero.") - assertEquals(a * zero, a * zero, "Multiplication by $zero in $algebra doesn't give $zero.") - } - } -} diff --git a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt b/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt deleted file mode 100644 index 4afa97ce5..000000000 --- a/kmath-core/src/commonTest/kotlin/space/kscience/kmath/testutils/SpaceVerifier.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.testutils - -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.operations.invoke -import kotlin.test.assertEquals -import kotlin.test.assertNotEquals - -internal open class SpaceVerifier( - override val algebra: S, - val a: T, - val b: T, - val c: T, - val x: Number, -) : AlgebraicVerifier> where S : Ring, S : ScaleOperations { - override fun verify() { - algebra { - assertEquals(a + b + c, a + (b + c), "Addition in $algebra is not associative.") - assertEquals(x * (a + b), x * a + x * b, "Addition in $algebra is not distributive.") - assertEquals((a + b) * x, a * x + b * x, "Addition in $algebra is not distributive.") - assertEquals(a + zero, zero + a, "$zero in $algebra is not a neutral addition element.") - assertEquals(a, a + zero, "$zero in $algebra is not a neutral addition element.") - assertEquals(a, zero + a, "$zero in $algebra is not a neutral addition element.") - assertEquals(a - b, -(b - a), "Subtraction in $algebra is not anti-commutative.") - assertNotEquals(a - b - c, a - (b - c), "Subtraction in $algebra is associative.") - assertEquals(x * (a - b), x * a - x * b, "Subtraction in $algebra is not distributive.") - assertEquals(a, a - zero, "$zero in $algebra is not a neutral addition element.") - assertEquals(a * x, x * a, "Multiplication by scalar in $algebra is not commutative.") - assertEquals(x * (a + b), (x * a) + (x * b), "Multiplication by scalar in $algebra is not distributive.") - } - } -} 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 deleted file mode 100644 index a24243cb4..000000000 --- a/kmath-core/src/jsMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.misc - -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/scientifik/kmath/operations/bigNumbers.kt b/kmath-core/src/jvmMain/kotlin/scientifik/kmath/operations/bigNumbers.kt new file mode 100644 index 000000000..76ca199c5 --- /dev/null +++ b/kmath-core/src/jvmMain/kotlin/scientifik/kmath/operations/bigNumbers.kt @@ -0,0 +1,32 @@ +package scientifik.kmath.operations + +import scientifik.kmath.structures.* +import java.math.BigDecimal +import java.math.BigInteger +import java.math.MathContext + +object JBigIntegerField : Field { + override val zero: BigInteger = BigInteger.ZERO + override val one: BigInteger = BigInteger.ONE + + override fun add(a: BigInteger, b: BigInteger): BigInteger = a.add(b) + + override fun multiply(a: BigInteger, k: Number): BigInteger = a.multiply(k.toInt().toBigInteger()) + + override fun multiply(a: BigInteger, b: BigInteger): BigInteger = a.multiply(b) + + override fun divide(a: BigInteger, b: BigInteger): BigInteger = a.div(b) +} + +class JBigDecimalField(val mathContext: MathContext = MathContext.DECIMAL64) : Field { + override val zero: BigDecimal = BigDecimal.ZERO + override val one: BigDecimal = BigDecimal.ONE + + override fun add(a: BigDecimal, b: BigDecimal): BigDecimal = a.add(b) + + override fun multiply(a: BigDecimal, k: Number): BigDecimal = + a.multiply(k.toDouble().toBigDecimal(mathContext), 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) +} \ No newline at end of file diff --git a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt b/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt deleted file mode 100644 index c50919e88..000000000 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/misc/numbersJVM.kt +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.misc - -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 deleted file mode 100644 index 69dd858c4..000000000 --- a/kmath-core/src/jvmMain/kotlin/space/kscience/kmath/operations/BigNumbers.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.operations - -import java.math.BigDecimal -import java.math.BigInteger -import java.math.MathContext - -/** - * A field over [BigInteger]. - */ -public object JBigIntegerField : Ring, NumericAlgebra { - override val zero: BigInteger get() = BigInteger.ZERO - - override val one: BigInteger get() = BigInteger.ONE - - 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) - - override operator fun BigInteger.unaryMinus(): BigInteger = negate() -} - -/** - * An abstract field over [BigDecimal]. - * - * @property mathContext the [MathContext] to use. - */ -public abstract class JBigDecimalFieldBase internal constructor( - private val mathContext: MathContext = MathContext.DECIMAL64, -) : Field, PowerOperations, NumericAlgebra, ScaleOperations { - override val zero: BigDecimal - get() = BigDecimal.ZERO - - override val one: BigDecimal - get() = BigDecimal.ONE - - override fun add(a: BigDecimal, b: BigDecimal): BigDecimal = a.add(b) - override operator fun BigDecimal.minus(b: BigDecimal): BigDecimal = subtract(b) - override fun number(value: Number): BigDecimal = BigDecimal.valueOf(value.toDouble()) - - override fun scale(a: BigDecimal, value: Double): BigDecimal = - a.multiply(value.toBigDecimal(mathContext), mathContext) - - override fun multiply(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) -} - -/** - * A field over [BigDecimal]. - */ -public class JBigDecimalField(mathContext: MathContext = MathContext.DECIMAL64) : JBigDecimalFieldBase(mathContext) { - public companion object : JBigDecimalFieldBase() -} 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 deleted file mode 100644 index a24243cb4..000000000 --- a/kmath-core/src/nativeMain/kotlin/space/kscience/kmath/misc/numbers.kt +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.misc - -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 317691ae5..373d9b8ac 100644 --- a/kmath-coroutines/build.gradle.kts +++ b/kmath-coroutines/build.gradle.kts @@ -1,27 +1,23 @@ plugins { - kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("scientifik.mpp") + //id("scientifik.atomic") } kotlin.sourceSets { - all { - with(languageSettings) { - useExperimentalAnnotation("kotlinx.coroutines.InternalCoroutinesApi") - useExperimentalAnnotation("kotlinx.coroutines.ExperimentalCoroutinesApi") - useExperimentalAnnotation("kotlinx.coroutines.FlowPreview") - } - } - commonMain { dependencies { api(project(":kmath-core")) - api(project(":kmath-complex")) - api("org.jetbrains.kotlinx:kotlinx-coroutines-core:${ru.mipt.npm.gradle.KScienceVersions.coroutinesVersion}") + api("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:${Scientifik.coroutinesVersion}") + } + } + jvmMain { + dependencies { + api("org.jetbrains.kotlinx:kotlinx-coroutines-core:${Scientifik.coroutinesVersion}") + } + } + jsMain { + dependencies { + api("org.jetbrains.kotlinx:kotlinx-coroutines-core-js:${Scientifik.coroutinesVersion}") } } } - -readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL -} \ No newline at end of file diff --git a/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/chains/BlockingIntChain.kt b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/chains/BlockingIntChain.kt new file mode 100644 index 000000000..6ec84d5c7 --- /dev/null +++ b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/chains/BlockingIntChain.kt @@ -0,0 +1,12 @@ +package scientifik.kmath.chains + +/** + * Performance optimized chain for integer values + */ +abstract class BlockingIntChain : Chain { + abstract fun nextInt(): Int + + override suspend fun next(): Int = nextInt() + + fun nextBlock(size: Int): IntArray = IntArray(size) { nextInt() } +} \ No newline at end of file diff --git a/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/chains/BlockingRealChain.kt b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/chains/BlockingRealChain.kt new file mode 100644 index 000000000..6b69d2734 --- /dev/null +++ b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/chains/BlockingRealChain.kt @@ -0,0 +1,12 @@ +package scientifik.kmath.chains + +/** + * Performance optimized chain for real values + */ +abstract class BlockingRealChain : Chain { + abstract fun nextDouble(): Double + + override suspend fun next(): Double = nextDouble() + + fun nextBlock(size: Int): DoubleArray = DoubleArray(size) { nextDouble() } +} \ No newline at end of file diff --git a/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/chains/Chain.kt b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/chains/Chain.kt new file mode 100644 index 000000000..5635499e5 --- /dev/null +++ b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/chains/Chain.kt @@ -0,0 +1,176 @@ +/* + * Copyright 2018 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package scientifik.kmath.chains + +import kotlinx.coroutines.InternalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.FlowCollector +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock + + +/** + * A not-necessary-Markov chain of some type + * @param R - the chain element type + */ +interface Chain: Flow { + /** + * Generate next value, changing state if needed + */ + suspend fun next(): R + + /** + * Create a copy of current chain state. Consuming resulting chain does not affect initial chain + */ + fun fork(): Chain + + @OptIn(InternalCoroutinesApi::class) + override suspend fun collect(collector: FlowCollector) { + kotlinx.coroutines.flow.flow { + while (true){ + emit(next()) + } + }.collect(collector) + } + + companion object +} + + +fun Iterator.asChain(): Chain = SimpleChain { next() } +fun Sequence.asChain(): Chain = iterator().asChain() + +/** + * A simple chain of independent tokens + */ +class SimpleChain(private val gen: suspend () -> R) : Chain { + override suspend fun next(): R = gen() + override fun fork(): Chain = this +} + +/** + * A stateless Markov chain + */ +class MarkovChain(private val seed: suspend () -> R, private val gen: suspend (R) -> R) : Chain { + + private val mutex = Mutex() + + private var value: R? = null + + fun value() = value + + override suspend fun next(): R { + mutex.withLock { + val newValue = gen(value ?: seed()) + value = newValue + return newValue + } + } + + override fun fork(): Chain { + return 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 + */ +class StatefulChain( + private val state: S, + private val seed: S.() -> R, + private val forkState: ((S) -> S), + private val gen: suspend S.(R) -> R +) : Chain { + + private val mutex = Mutex() + + private var value: R? = null + + fun value() = value + + override suspend fun next(): R { + mutex.withLock { + val newValue = state.gen(value ?: state.seed()) + value = newValue + return newValue + } + } + + override fun fork(): Chain { + return StatefulChain(forkState(state), seed, forkState, gen) + } +} + +/** + * A chain that repeats the same value + */ +class ConstantChain(val value: T) : Chain { + override suspend fun next(): T = value + + override fun fork(): Chain { + return 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 + */ +fun Chain.map(func: suspend (T) -> R): Chain = object : Chain { + override suspend fun next(): R = func(this@map.next()) + override fun fork(): Chain = this@map.fork().map(func) +} + +/** + * [block] must be a pure function or at least not use external random variables, otherwise fork could be broken + */ +fun Chain.filter(block: (T) -> Boolean): Chain = object : Chain { + override suspend fun next(): T { + var next: T + do { + next = this@filter.next() + } while (!block(next)) + return next + } + + override fun fork(): Chain = this@filter.fork().filter(block) +} + +/** + * Map the whole chain + */ +fun Chain.collect(mapper: suspend (Chain) -> R): Chain = object : Chain { + override suspend fun next(): R = mapper(this@collect) + override fun fork(): Chain = this@collect.fork().collect(mapper) +} + +fun Chain.collectWithState(state: S, stateFork: (S) -> S, mapper: suspend S.(Chain) -> R): Chain = + object : Chain { + override suspend fun next(): R = state.mapper(this@collectWithState) + override fun fork(): Chain = this@collectWithState.fork().collectWithState(stateFork(state), stateFork, mapper) + } + +/** + * Zip two chains together using given transformation + */ +fun Chain.zip(other: Chain, block: suspend (T, U) -> R): Chain = object : Chain { + override suspend fun next(): R = block(this@zip.next(), other.next()) + + override fun fork(): Chain = this@zip.fork().zip(other.fork(), block) +} \ No newline at end of file diff --git a/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/chains/flowExtra.kt b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/chains/flowExtra.kt new file mode 100644 index 000000000..bfd16d763 --- /dev/null +++ b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/chains/flowExtra.kt @@ -0,0 +1,27 @@ +package scientifik.kmath.chains + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.scan +import kotlinx.coroutines.flow.scanReduce +import scientifik.kmath.operations.Space +import scientifik.kmath.operations.SpaceOperations + + +@ExperimentalCoroutinesApi +fun Flow.cumulativeSum(space: SpaceOperations): Flow = with(space) { + scanReduce { sum: T, element: T -> sum + element } +} + +@ExperimentalCoroutinesApi +fun Flow.mean(space: Space): Flow = with(space) { + class Accumulator(var sum: T, var num: Int) + + scan(Accumulator(zero, 0)) { sum, element -> + sum.apply { + this.sum += element + this.num += 1 + } + }.map { it.sum / it.num } +} \ No newline at end of file diff --git a/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/coroutines/coroutinesExtra.kt b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/coroutines/coroutinesExtra.kt new file mode 100644 index 000000000..fdde62304 --- /dev/null +++ b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/coroutines/coroutinesExtra.kt @@ -0,0 +1,102 @@ +package scientifik.kmath.coroutines + +import kotlinx.coroutines.* +import kotlinx.coroutines.channels.produce +import kotlinx.coroutines.flow.* + +val Dispatchers.Math: CoroutineDispatcher get() = Dispatchers.Default + +/** + * An imitator of [Deferred] which holds a suspended function block and dispatcher + */ +internal class LazyDeferred(val dispatcher: CoroutineDispatcher, val block: suspend CoroutineScope.() -> T) { + private var deferred: Deferred? = null + + internal fun start(scope: CoroutineScope) { + if (deferred == null) { + deferred = scope.async(dispatcher, block = block) + } + } + + suspend fun await(): T = deferred?.await() ?: error("Coroutine not started") +} + +class AsyncFlow internal constructor(internal val deferredFlow: Flow>) : Flow { + @InternalCoroutinesApi + override suspend fun collect(collector: FlowCollector) { + deferredFlow.collect { + collector.emit((it.await())) + } + } +} + +@FlowPreview +fun Flow.async( + dispatcher: CoroutineDispatcher = Dispatchers.Default, + block: suspend CoroutineScope.(T) -> R +): AsyncFlow { + val flow = map { + LazyDeferred(dispatcher) { block(it) } + } + return AsyncFlow(flow) +} + +@FlowPreview +fun AsyncFlow.map(action: (T) -> R) = + AsyncFlow(deferredFlow.map { input -> + //TODO add function composition + LazyDeferred(input.dispatcher) { + input.start(this) + action(input.await()) + } + }) + +@ExperimentalCoroutinesApi +@FlowPreview +suspend fun AsyncFlow.collect(concurrency: Int, collector: FlowCollector) { + require(concurrency >= 1) { "Buffer size should be more than 1, but was $concurrency" } + coroutineScope { + //Starting up to N deferred coroutines ahead of time + val channel = produce(capacity = concurrency - 1) { + deferredFlow.collect { value -> + value.start(this@coroutineScope) + send(value) + } + } + + (channel as Job).invokeOnCompletion { + if (it is CancellationException && it.cause == null) cancel() + } + + for (element in channel) { + collector.emit(element.await()) + } + + val producer = channel as Job + if (producer.isCancelled) { + producer.join() + //throw producer.getCancellationException() + } + } +} + +@ExperimentalCoroutinesApi +@FlowPreview +suspend fun AsyncFlow.collect(concurrency: Int, action: suspend (value: T) -> Unit): Unit { + collect(concurrency, object : FlowCollector { + override suspend fun emit(value: T) = action(value) + }) +} + +@ExperimentalCoroutinesApi +@FlowPreview +fun Flow.mapParallel( + dispatcher: CoroutineDispatcher = Dispatchers.Default, + transform: suspend (T) -> R +): Flow { + return flatMapMerge{ value -> + flow { emit(transform(value)) } + }.flowOn(dispatcher) +} + + diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/streaming/BufferFlow.kt similarity index 55% rename from kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt rename to kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/streaming/BufferFlow.kt index 914139a3e..bef21a680 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/BufferFlow.kt +++ b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/streaming/BufferFlow.kt @@ -1,40 +1,35 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.streaming +package scientifik.kmath.streaming import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.* -import space.kscience.kmath.chains.BlockingDoubleChain -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.BufferFactory -import space.kscience.kmath.structures.DoubleBuffer +import scientifik.kmath.chains.BlockingRealChain +import scientifik.kmath.structures.Buffer +import scientifik.kmath.structures.BufferFactory +import scientifik.kmath.structures.DoubleBuffer +import scientifik.kmath.structures.asBuffer /** * Create a [Flow] from buffer */ -public fun Buffer.asFlow(): Flow = iterator().asFlow() +fun Buffer.asFlow() = iterator().asFlow() /** * Flat map a [Flow] of [Buffer] into continuous [Flow] of elements */ @FlowPreview -public fun Flow>.spread(): Flow = flatMapConcat { it.asFlow() } +fun Flow>.spread(): Flow = flatMapConcat { it.asFlow() } /** * Collect incoming flow into fixed size chunks */ -public fun Flow.chunked(bufferSize: Int, bufferFactory: BufferFactory): Flow> = flow { +fun Flow.chunked(bufferSize: Int, bufferFactory: BufferFactory): Flow> = flow { require(bufferSize > 0) { "Resulting chunk size must be more than zero" } val list = ArrayList(bufferSize) var counter = 0 this@chunked.collect { element -> - list += element + list.add(element) counter++ - if (counter == bufferSize) { val buffer = bufferFactory(bufferSize) { list[it] } emit(buffer) @@ -42,19 +37,22 @@ public fun Flow.chunked(bufferSize: Int, bufferFactory: BufferFactory) counter = 0 } } - - if (counter > 0) emit(bufferFactory(counter) { list[it] }) + if (counter > 0) { + emit(bufferFactory(counter) { list[it] }) + } } /** * Specialized flow chunker for real buffer */ -public fun Flow.chunked(bufferSize: Int): Flow = flow { +fun Flow.chunked(bufferSize: Int): Flow = flow { require(bufferSize > 0) { "Resulting chunk size must be more than zero" } - if (this@chunked is BlockingDoubleChain) { - // performance optimization for blocking primitive chain - while (true) emit(nextBufferBlocking(bufferSize)) + if (this@chunked is BlockingRealChain) { + //performance optimization for blocking primitive chain + while (true) { + emit(nextBlock(bufferSize).asBuffer()) + } } else { val array = DoubleArray(bufferSize) var counter = 0 @@ -62,28 +60,27 @@ public fun Flow.chunked(bufferSize: Int): Flow = flow { this@chunked.collect { element -> array[counter] = element counter++ - if (counter == bufferSize) { val buffer = DoubleBuffer(array) emit(buffer) counter = 0 } } - - if (counter > 0) emit(DoubleBuffer(counter) { array[it] }) + if (counter > 0) { + emit(DoubleBuffer(counter) { array[it] }) + } } } /** * Map a flow to a moving window buffer. The window step is one. - * To get different steps, one could use skip operation. + * In order to get different steps, one could use skip operation. */ -public fun Flow.windowed(window: Int): Flow> = flow { +fun Flow.windowed(window: Int): Flow> = flow { require(window > 1) { "Window size must be more than one" } val ringBuffer = RingBuffer.boxing(window) - this@windowed.collect { element -> ringBuffer.push(element) emit(ringBuffer.snapshot()) } -} +} \ No newline at end of file diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/streaming/RingBuffer.kt similarity index 57% rename from kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt rename to kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/streaming/RingBuffer.kt index 4b12b031d..6b99e34ff 100644 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/streaming/RingBuffer.kt +++ b/kmath-coroutines/src/commonMain/kotlin/scientifik/kmath/streaming/RingBuffer.kt @@ -1,48 +1,47 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.streaming +package scientifik.kmath.streaming import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.structures.VirtualBuffer +import scientifik.kmath.structures.Buffer +import scientifik.kmath.structures.MutableBuffer +import scientifik.kmath.structures.VirtualBuffer +import kotlin.reflect.KClass /** * Thread-safe ring buffer */ @Suppress("UNCHECKED_CAST") -public class RingBuffer( +internal class RingBuffer( private val buffer: MutableBuffer, private var startIndex: Int = 0, - size: Int = 0, + size: Int = 0 ) : Buffer { - private val mutex: Mutex = Mutex() + + private val mutex = Mutex() override var size: Int = size private set - override operator fun get(index: Int): T { + override 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 } - public fun isFull(): Boolean = size == buffer.size + fun isFull() = size == buffer.size /** * Iterator could provide wrong results if buffer is changed in initialization (iteration is safe) */ - override operator fun iterator(): Iterator = object : AbstractIterator() { + override fun iterator(): Iterator = object : AbstractIterator() { private var count = size private var index = startIndex val copy = buffer.copy() override fun computeNext() { - if (count == 0) done() else { + if (count == 0) { + done() + } else { setNext(copy[index] as T) index = index.forward(1) count-- @@ -53,15 +52,23 @@ public class RingBuffer( /** * A safe snapshot operation */ - public suspend fun snapshot(): Buffer = mutex.withLock { - val copy = buffer.copy() - VirtualBuffer(size) { i -> copy[startIndex.forward(i)] as T } + suspend fun snapshot(): Buffer { + mutex.withLock { + val copy = buffer.copy() + return VirtualBuffer(size) { i -> + copy[startIndex.forward(i)] as T + } + } } - public suspend fun push(element: T) { + suspend fun push(element: T) { mutex.withLock { buffer[startIndex.forward(size)] = element - if (isFull()) startIndex++ else size++ + if (isFull()) { + startIndex++ + } else { + size++ + } } } @@ -69,8 +76,8 @@ public class RingBuffer( @Suppress("NOTHING_TO_INLINE") private inline fun Int.forward(n: Int): Int = (this + n) % (buffer.size) - public companion object { - public inline fun build(size: Int, empty: T): RingBuffer { + companion object { + inline fun build(size: Int, empty: T): RingBuffer { val buffer = MutableBuffer.auto(size) { empty } as MutableBuffer return RingBuffer(buffer) } @@ -78,9 +85,9 @@ public class RingBuffer( /** * Slow yet universal buffer */ - public fun boxing(size: Int): RingBuffer { + fun boxing(size: Int): RingBuffer { val buffer: MutableBuffer = MutableBuffer.boxing(size) { null } return RingBuffer(buffer) } } -} +} \ No newline at end of file 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 deleted file mode 100644 index a41a30f55..000000000 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingChain.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.chains - -import space.kscience.kmath.structures.Buffer - - -public interface BufferChain : Chain { - public suspend fun nextBuffer(size: Int): Buffer - override suspend fun fork(): BufferChain -} - -/** - * A chain with blocking generator that could be used without suspension - */ -public interface BlockingChain : Chain { - /** - * Get the next value without concurrency support. Not guaranteed to be thread safe. - */ - public fun nextBlocking(): T - - override suspend fun next(): T = nextBlocking() - - override suspend fun fork(): BlockingChain -} - - -public interface BlockingBufferChain : BlockingChain, BufferChain { - - public fun nextBufferBlocking(size: Int): Buffer - - override fun nextBlocking(): T = nextBufferBlocking(1)[0] - - override suspend fun nextBuffer(size: Int): Buffer = nextBufferBlocking(size) - - override suspend fun fork(): BlockingBufferChain -} - - -public suspend inline fun Chain.nextBuffer(size: Int): Buffer = if (this is BufferChain) { - nextBuffer(size) -} else { - Buffer.auto(size) { next() } -} - -public inline fun BlockingChain.nextBufferBlocking( - size: Int, -): Buffer = if (this is BlockingBufferChain) { - nextBufferBlocking(size) -} else { - Buffer.auto(size) { nextBlocking() } -} \ No newline at end of file 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 deleted file mode 100644 index 7b4d1f2af..000000000 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingDoubleChain.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.chains - -import space.kscience.kmath.structures.DoubleBuffer - -/** - * Chunked, specialized chain for double values, which supports blocking [nextBlocking] operation - */ -public interface BlockingDoubleChain : BlockingBufferChain { - - /** - * Returns an [DoubleArray] chunk of [size] values of [next]. - */ - override fun nextBufferBlocking(size: Int): DoubleBuffer - - override suspend fun fork(): BlockingDoubleChain - - public companion object -} - -public fun BlockingDoubleChain.map(transform: (Double) -> Double): BlockingDoubleChain = object : BlockingDoubleChain { - override fun nextBufferBlocking(size: Int): DoubleBuffer { - val block = this@map.nextBufferBlocking(size) - return DoubleBuffer(size) { transform(block[it]) } - } - - override suspend fun fork(): BlockingDoubleChain = this@map.fork().map(transform) -} diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt deleted file mode 100644 index f13d9907c..000000000 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/BlockingIntChain.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.chains - -import space.kscience.kmath.structures.IntBuffer - -/** - * Performance optimized chain for integer values - */ -public interface BlockingIntChain : BlockingBufferChain { - override fun nextBufferBlocking(size: Int): IntBuffer - - override suspend fun fork(): BlockingIntChain -} \ 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 deleted file mode 100644 index 403472f28..000000000 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/Chain.kt +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.chains - -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock - -/** - * A not-necessary-Markov chain of some type - * @param T the chain element type - */ -public interface Chain : Flow { - /** - * Generate next value, changing state if needed - */ - public suspend fun next(): T - - /** - * Create a copy of current chain state. Consuming resulting chain does not affect initial chain. - */ - public suspend fun fork(): Chain - - override suspend fun collect(collector: FlowCollector): Unit = - flow { while (true) emit(next()) }.collect(collector) - - public companion object -} - -public fun Iterator.asChain(): Chain = SimpleChain { next() } -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 { - override suspend fun next(): R = gen() - override suspend fun fork(): Chain = this -} - -/** - * A stateless Markov chain - */ -public class MarkovChain(private val seed: suspend () -> R, private val gen: suspend (R) -> R) : Chain { - private val mutex: Mutex = Mutex() - private var value: R? = null - - public fun value(): R? = value - - override suspend fun next(): R = mutex.withLock { - val newValue = gen(value ?: seed()) - value = newValue - newValue - } - - 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. - */ -public class StatefulChain( - private val state: S, - private val seed: S.() -> R, - private val forkState: ((S) -> S), - private val gen: suspend S.(R) -> R, -) : Chain { - private val mutex: Mutex = Mutex() - private var value: R? = null - - public fun value(): R? = value - - override suspend fun next(): R = mutex.withLock { - val newValue = state.gen(value ?: state.seed()) - value = newValue - newValue - } - - 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 { - 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. - */ -public fun Chain.map(func: suspend (T) -> R): Chain = object : Chain { - override suspend fun next(): R = func(this@map.next()) - override suspend fun fork(): Chain = this@map.fork().map(func) -} - -/** - * [block] must be a pure function or at least not use external random variables, otherwise fork could be broken - */ -public fun Chain.filter(block: (T) -> Boolean): Chain = object : Chain { - override suspend fun next(): T { - var next: T - - do next = this@filter.next() - while (!block(next)) - - return next - } - - override suspend fun fork(): Chain = this@filter.fork().filter(block) -} - -/** - * Map the whole chain - */ -public fun Chain.collect(mapper: suspend (Chain) -> R): Chain = object : Chain { - override suspend fun next(): R = mapper(this@collect) - override suspend fun fork(): Chain = this@collect.fork().collect(mapper) -} - -public fun Chain.collectWithState( - state: S, - stateFork: (S) -> S, - mapper: suspend S.(Chain) -> R, -): Chain = object : Chain { - override suspend fun next(): R = state.mapper(this@collectWithState) - - override suspend fun fork(): Chain = - this@collectWithState.fork().collectWithState(stateFork(state), stateFork, mapper) -} - -/** - * Zip two chains together using given transformation - */ -public fun Chain.zip(other: Chain, block: suspend (T, U) -> R): Chain = object : Chain { - override suspend fun next(): R = block(this@zip.next(), other.next()) - override suspend fun fork(): Chain = this@zip.fork().zip(other.fork(), block) -} diff --git a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt b/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt deleted file mode 100644 index 1821daac9..000000000 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/chains/flowExtra.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.chains - -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.runningReduce -import kotlinx.coroutines.flow.scan -import space.kscience.kmath.operations.GroupOperations -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.operations.invoke - -public fun Flow.cumulativeSum(group: GroupOperations): Flow = - group { runningReduce { sum, element -> sum + element } } - -@ExperimentalCoroutinesApi -public fun Flow.mean(space: S): Flow where S : Ring, S : ScaleOperations = space { - data class Accumulator(var sum: T, var num: Int) - - scan(Accumulator(zero, 0)) { sum, element -> - sum.apply { - this.sum += element - this.num += 1 - } - }.map { it.sum / it.num } -} 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 deleted file mode 100644 index 3b90222dd..000000000 --- a/kmath-coroutines/src/commonMain/kotlin/space/kscience/kmath/coroutines/coroutinesExtra.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.coroutines - -import kotlinx.coroutines.* -import kotlinx.coroutines.channels.produce -import kotlinx.coroutines.flow.* - -public val Dispatchers.Math: CoroutineDispatcher - get() = Default - -/** - * An imitator of [Deferred] which holds a suspended function block and dispatcher - */ -@PublishedApi -internal class LazyDeferred(val dispatcher: CoroutineDispatcher, val block: suspend CoroutineScope.() -> T) { - private var deferred: Deferred? = null - - 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 @PublishedApi internal constructor( - @PublishedApi internal val deferredFlow: Flow>, -) : Flow { - override suspend fun collect(collector: FlowCollector): Unit = - deferredFlow.collect { collector.emit((it.await())) } -} - -public inline fun Flow.async( - dispatcher: CoroutineDispatcher = Dispatchers.Default, - crossinline block: suspend CoroutineScope.(T) -> R, -): AsyncFlow { - val flow = map { LazyDeferred(dispatcher) { block(it) } } - return AsyncFlow(flow) -} - -public inline fun AsyncFlow.map(crossinline action: (T) -> R): AsyncFlow = - AsyncFlow(deferredFlow.map { input -> - //TODO add function composition - LazyDeferred(input.dispatcher) { - input.start(this) - action(input.await()) - } - }) - -public suspend fun AsyncFlow.collect(concurrency: Int, collector: FlowCollector) { - require(concurrency >= 1) { "Buffer size should be more than 1, but was $concurrency" } - - coroutineScope { - //Starting up to N deferred coroutines ahead of time - val channel = produce(capacity = concurrency - 1) { - deferredFlow.collect { value -> - value.start(this@coroutineScope) - send(value) - } - } - - (channel as Job).invokeOnCompletion { - if (it is CancellationException && it.cause == null) cancel() - } - - for (element in channel) { - collector.emit(element.await()) - } - - val producer = channel as Job - if (producer.isCancelled) { - producer.join() - //throw producer.getCancellationException() - } - } -} - -public suspend inline fun AsyncFlow.collect( - concurrency: Int, - crossinline action: suspend (value: T) -> Unit, -): Unit = collect(concurrency, object : FlowCollector { - override suspend fun emit(value: T): Unit = action(value) -}) - -public inline fun Flow.mapParallel( - dispatcher: CoroutineDispatcher = Dispatchers.Default, - crossinline transform: suspend (T) -> R, -): Flow = flatMapMerge { value -> flow { emit(transform(value)) } }.flowOn(dispatcher) diff --git a/kmath-coroutines/src/jvmMain/kotlin/scientifik/kmath/chains/ChainExt.kt b/kmath-coroutines/src/jvmMain/kotlin/scientifik/kmath/chains/ChainExt.kt new file mode 100644 index 000000000..013ea2922 --- /dev/null +++ b/kmath-coroutines/src/jvmMain/kotlin/scientifik/kmath/chains/ChainExt.kt @@ -0,0 +1,20 @@ +package scientifik.kmath.chains + +import kotlinx.coroutines.runBlocking +import kotlin.sequences.Sequence + +/** + * Represent a chain as regular iterator (uses blocking calls) + */ +operator fun Chain.iterator() = object : Iterator { + override fun hasNext(): Boolean = true + + override fun next(): R = runBlocking { next() } +} + +/** + * Represent a chain as a sequence + */ +fun Chain.asSequence(): Sequence = object : Sequence { + override fun iterator(): Iterator = this@asSequence.iterator() +} \ No newline at end of file diff --git a/kmath-coroutines/src/jvmMain/kotlin/scientifik/kmath/structures/LazyNDStructure.kt b/kmath-coroutines/src/jvmMain/kotlin/scientifik/kmath/structures/LazyNDStructure.kt new file mode 100644 index 000000000..e65940739 --- /dev/null +++ b/kmath-coroutines/src/jvmMain/kotlin/scientifik/kmath/structures/LazyNDStructure.kt @@ -0,0 +1,62 @@ +package scientifik.kmath.structures + +import kotlinx.coroutines.* +import scientifik.kmath.coroutines.Math + +class LazyNDStructure( + val scope: CoroutineScope, + override val shape: IntArray, + val function: suspend (IntArray) -> T +) : NDStructure { + + private val cache = HashMap>() + + fun deferred(index: IntArray) = cache.getOrPut(index) { + scope.async(context = Dispatchers.Math) { + function(index) + } + } + + suspend fun await(index: IntArray): T = deferred(index).await() + + override fun get(index: IntArray): T = runBlocking { + deferred(index).await() + } + + override fun elements(): Sequence> { + val strides = DefaultStrides(shape) + val res = runBlocking { + strides.indices().toList().map { index -> index to await(index) } + } + return res.asSequence() + } + + override fun equals(other: Any?): Boolean { + return NDStructure.equals(this, other as? NDStructure<*> ?: return false) + } + + override fun hashCode(): Int { + var result = scope.hashCode() + result = 31 * result + shape.contentHashCode() + result = 31 * result + function.hashCode() + result = 31 * result + cache.hashCode() + return result + } + + +} + +fun NDStructure.deferred(index: IntArray) = + if (this is LazyNDStructure) this.deferred(index) else CompletableDeferred(get(index)) + +suspend fun NDStructure.await(index: IntArray) = + if (this is LazyNDStructure) this.await(index) else get(index) + +/** + * PENDING would benifit from KEEP-176 + */ +fun NDStructure.mapAsyncIndexed(scope: CoroutineScope, function: suspend (T, index: IntArray) -> R) = + LazyNDStructure(scope, shape) { index -> function(get(index), index) } + +fun NDStructure.mapAsync(scope: CoroutineScope, function: suspend (T) -> R) = + LazyNDStructure(scope, shape) { index -> function(get(index)) } \ No newline at end of file diff --git a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt b/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt deleted file mode 100644 index 0e36706cf..000000000 --- a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/chains/ChainExt.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.chains - -import kotlinx.coroutines.runBlocking - -/** - * Represent a chain as regular iterator (uses blocking calls) - */ -public operator fun Chain.iterator(): Iterator = object : Iterator { - override fun hasNext(): Boolean = true - override fun next(): R = runBlocking { next() } -} - -/** - * Represent a chain as a sequence - */ -public fun Chain.asSequence(): Sequence = Sequence { this@asSequence.iterator() } 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 deleted file mode 100644 index 3eb6f3aa6..000000000 --- a/kmath-coroutines/src/jvmMain/kotlin/space/kscience/kmath/structures/LazyStructureND.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.structures - -import kotlinx.coroutines.* -import space.kscience.kmath.coroutines.Math -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.DefaultStrides -import space.kscience.kmath.nd.StructureND - -public class LazyStructureND( - public val scope: CoroutineScope, - override val shape: IntArray, - public val function: suspend (IntArray) -> T, -) : StructureND { - private val cache: MutableMap> = HashMap() - - public fun deferred(index: IntArray): Deferred = cache.getOrPut(index) { - scope.async(context = Dispatchers.Math) { function(index) } - } - - public suspend fun await(index: IntArray): T = deferred(index).await() - override operator fun get(index: IntArray): T = runBlocking { deferred(index).await() } - - @OptIn(PerformancePitfall::class) - override fun elements(): Sequence> { - val strides = DefaultStrides(shape) - val res = runBlocking { strides.indices().toList().map { index -> index to await(index) } } - return res.asSequence() - } -} - -public fun StructureND.deferred(index: IntArray): Deferred = - if (this is LazyStructureND) deferred(index) else CompletableDeferred(get(index)) - -public suspend fun StructureND.await(index: IntArray): T = - if (this is LazyStructureND) await(index) else get(index) - -/** - * PENDING would benefit from KEEP-176 - */ -public inline fun StructureND.mapAsyncIndexed( - scope: CoroutineScope, - crossinline function: suspend (T, index: IntArray) -> R, -): LazyStructureND = LazyStructureND(scope, shape) { index -> function(get(index), index) } - -public inline fun StructureND.mapAsync( - scope: CoroutineScope, - crossinline function: suspend (T) -> R, -): LazyStructureND = LazyStructureND(scope, shape) { index -> function(get(index)) } diff --git a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt b/kmath-coroutines/src/jvmTest/kotlin/scientifik/kmath/streaming/BufferFlowTest.kt similarity index 67% rename from kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt rename to kmath-coroutines/src/jvmTest/kotlin/scientifik/kmath/streaming/BufferFlowTest.kt index 057ac5feb..147f687f0 100644 --- a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/BufferFlowTest.kt +++ b/kmath-coroutines/src/jvmTest/kotlin/scientifik/kmath/streaming/BufferFlowTest.kt @@ -1,17 +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 file. - */ - -package space.kscience.kmath.streaming +package scientifik.kmath.streaming import kotlinx.coroutines.* import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.flow.collect import org.junit.jupiter.api.Timeout -import space.kscience.kmath.coroutines.async -import space.kscience.kmath.coroutines.collect -import space.kscience.kmath.coroutines.mapParallel +import scientifik.kmath.coroutines.async +import scientifik.kmath.coroutines.collect +import scientifik.kmath.coroutines.mapParallel import java.util.concurrent.Executors import kotlin.test.Test @@ -19,14 +14,15 @@ import kotlin.test.Test @ExperimentalCoroutinesApi @InternalCoroutinesApi @FlowPreview -internal class BufferFlowTest { - val dispatcher: CoroutineDispatcher = Executors.newFixedThreadPool(4).asCoroutineDispatcher() +class BufferFlowTest { + + val dispatcher = Executors.newFixedThreadPool(4).asCoroutineDispatcher() @Test @Timeout(2000) fun map() { runBlocking { - (1..20).asFlow().mapParallel(dispatcher) { + (1..20).asFlow().mapParallel( dispatcher) { println("Started $it on ${Thread.currentThread().name}") @Suppress("BlockingMethodInNonBlockingContext") Thread.sleep(200) diff --git a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt b/kmath-coroutines/src/jvmTest/kotlin/scientifik/kmath/streaming/RingBufferTest.kt similarity index 54% rename from kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt rename to kmath-coroutines/src/jvmTest/kotlin/scientifik/kmath/streaming/RingBufferTest.kt index 14081b0f5..c14d1a26c 100644 --- a/kmath-coroutines/src/jvmTest/kotlin/space/kscience/kmath/streaming/RingBufferTest.kt +++ b/kmath-coroutines/src/jvmTest/kotlin/scientifik/kmath/streaming/RingBufferTest.kt @@ -1,17 +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 file. - */ - -package space.kscience.kmath.streaming +package scientifik.kmath.streaming import kotlinx.coroutines.flow.* import kotlinx.coroutines.runBlocking -import space.kscience.kmath.structures.asSequence +import scientifik.kmath.structures.asSequence import kotlin.test.Test import kotlin.test.assertEquals -internal class RingBufferTest { +class RingBufferTest { @Test fun push() { val buffer = RingBuffer.build(20, Double.NaN) @@ -24,17 +19,17 @@ internal class RingBufferTest { } @Test - fun windowed() { - val flow = flow { + fun windowed(){ + val flow = flow{ var i = 0 - while (true) emit(i++) + while(true){ + emit(i++) + } } - val windowed = flow.windowed(10) - runBlocking { - @Suppress("UNUSED_VARIABLE") val first = windowed.take(1).single() - val res = windowed.take(15).map { it.asSequence().average() }.toList() + val first = windowed.take(1).single() + val res = windowed.take(15).map { it -> it.asSequence().average() }.toList() assertEquals(0.0, res[0]) assertEquals(4.5, res[9]) assertEquals(9.5, res[14]) diff --git a/kmath-dimensions/build.gradle.kts b/kmath-dimensions/build.gradle.kts index 885f3c227..dda6cd2f0 100644 --- a/kmath-dimensions/build.gradle.kts +++ b/kmath-dimensions/build.gradle.kts @@ -1,10 +1,8 @@ plugins { - kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("scientifik.mpp") } -description = "A proof of concept module for adding type-safe dimensions to structures" +description = "A proof of concept module for adding typ-safe dimensions to structures" kotlin.sourceSets { commonMain { @@ -13,13 +11,9 @@ kotlin.sourceSets { } } - jvmMain { - dependencies { + jvmMain{ + dependencies{ api(kotlin("reflect")) } } -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE -} +} \ No newline at end of file diff --git a/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Dimensions.kt b/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Dimensions.kt new file mode 100644 index 000000000..37e89c111 --- /dev/null +++ b/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Dimensions.kt @@ -0,0 +1,35 @@ +package scientifik.kmath.dimensions + +import kotlin.reflect.KClass + +/** + * An abstract class which is not used in runtime. Designates a size of some structure. + * Could be replaced later by fully inline constructs + */ +interface Dimension { + + val dim: UInt + companion object { + + } +} + +fun KClass.dim(): UInt = Dimension.resolve(this).dim + +expect fun Dimension.Companion.resolve(type: KClass): D + +expect fun Dimension.Companion.of(dim: UInt): Dimension + +inline fun Dimension.Companion.dim(): UInt = D::class.dim() + +object D1 : Dimension { + override val dim: UInt get() = 1U +} + +object D2 : Dimension { + override val dim: UInt get() = 2U +} + +object D3 : Dimension { + override val dim: UInt get() = 31U +} \ No newline at end of file diff --git a/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Wrappers.kt b/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Wrappers.kt new file mode 100644 index 000000000..f447866c0 --- /dev/null +++ b/kmath-dimensions/src/commonMain/kotlin/scientifik/kmath/dimensions/Wrappers.kt @@ -0,0 +1,161 @@ +package scientifik.kmath.dimensions + +import scientifik.kmath.linear.GenericMatrixContext +import scientifik.kmath.linear.MatrixContext +import scientifik.kmath.linear.Point +import scientifik.kmath.linear.transpose +import scientifik.kmath.operations.Ring +import scientifik.kmath.structures.Matrix +import scientifik.kmath.structures.Structure2D + +/** + * A matrix with compile-time controlled dimension + */ +interface DMatrix : Structure2D { + companion object { + /** + * Coerces a regular matrix to a matrix with type-safe dimensions and throws a error if coercion failed + */ + inline fun coerce(structure: Structure2D): DMatrix { + if (structure.rowNum != Dimension.dim().toInt()) { + error("Row number mismatch: expected ${Dimension.dim()} but found ${structure.rowNum}") + } + if (structure.colNum != Dimension.dim().toInt()) { + error("Column number mismatch: expected ${Dimension.dim()} but found ${structure.colNum}") + } + return DMatrixWrapper(structure) + } + + /** + * The same as [coerce] but without dimension checks. Use with caution + */ + fun coerceUnsafe(structure: Structure2D): DMatrix { + return DMatrixWrapper(structure) + } + } +} + +/** + * An inline wrapper for a Matrix + */ +inline class DMatrixWrapper( + val structure: Structure2D +) : DMatrix { + override val shape: IntArray get() = structure.shape + override fun get(i: Int, j: Int): T = structure[i, j] +} + +/** + * Dimension-safe point + */ +interface DPoint : Point { + companion object { + inline fun coerce(point: Point): DPoint { + if (point.size != Dimension.dim().toInt()) { + error("Vector dimension mismatch: expected ${Dimension.dim()}, but found ${point.size}") + } + return DPointWrapper(point) + } + + fun coerceUnsafe(point: Point): DPoint { + return DPointWrapper(point) + } + } +} + +/** + * Dimension-safe point wrapper + */ +inline class DPointWrapper(val point: Point) : + DPoint { + override val size: Int get() = point.size + + override fun get(index: Int): T = point[index] + + override fun iterator(): Iterator = point.iterator() +} + + +/** + * Basic operations on dimension-safe matrices. Operates on [Matrix] + */ +inline class DMatrixContext>(val context: GenericMatrixContext) { + + inline fun Matrix.coerce(): DMatrix { + if (rowNum != Dimension.dim().toInt()) { + error("Row number mismatch: expected ${Dimension.dim()} but found $rowNum") + } + if (colNum != Dimension.dim().toInt()) { + error("Column number mismatch: expected ${Dimension.dim()} but found $colNum") + } + return DMatrix.coerceUnsafe(this) + } + + /** + * Produce a matrix with this context and given dimensions + */ + inline fun produce(noinline initializer: (i: Int, j: Int) -> T): DMatrix { + val rows = Dimension.dim() + val cols = Dimension.dim() + return context.produce(rows.toInt(), cols.toInt(), initializer).coerce() + } + + inline fun point(noinline initializer: (Int) -> T): DPoint { + val size = Dimension.dim() + return DPoint.coerceUnsafe( + context.point( + size.toInt(), + initializer + ) + ) + } + + inline infix fun DMatrix.dot( + other: DMatrix + ): DMatrix { + return context.run { this@dot dot other }.coerce() + } + + inline infix fun DMatrix.dot(vector: DPoint): DPoint { + return DPoint.coerceUnsafe(context.run { this@dot dot vector }) + } + + inline operator fun DMatrix.times(value: T): DMatrix { + return context.run { this@times.times(value) }.coerce() + } + + inline operator fun T.times(m: DMatrix): DMatrix = + m * this + + + inline operator fun DMatrix.plus(other: DMatrix): DMatrix { + return context.run { this@plus + other }.coerce() + } + + inline operator fun DMatrix.minus(other: DMatrix): DMatrix { + return context.run { this@minus + other }.coerce() + } + + inline operator fun DMatrix.unaryMinus(): DMatrix { + return context.run { this@unaryMinus.unaryMinus() }.coerce() + } + + inline fun DMatrix.transpose(): DMatrix { + return context.run { (this@transpose as Matrix).transpose() }.coerce() + } + + /** + * A square unit matrix + */ + inline fun one(): DMatrix = produce { i, j -> + if (i == j) context.elementContext.one else context.elementContext.zero + } + + inline fun zero(): DMatrix = produce { _, _ -> + context.elementContext.zero + } + + companion object { + val real = DMatrixContext(MatrixContext.real) + } +} \ No newline at end of file diff --git a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt deleted file mode 100644 index 53482f020..000000000 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.dimensions - -import kotlin.reflect.KClass - -/** - * 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: Int - - public companion object -} - -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: Int): Dimension - -/** - * Finds [Dimension.dim] of given type [D]. - */ -public inline fun Dimension.Companion.dim(): Int = D::class.dim() - -/** - * Type representing 1 dimension. - */ -public object D1 : Dimension { - override val dim: Int get() = 1 -} - -/** - * Type representing 2 dimensions. - */ -public object D2 : Dimension { - override val dim: Int get() = 2 -} - -/** - * Type representing 3 dimensions. - */ -public object D3 : Dimension { - 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 deleted file mode 100644 index 70dc1001d..000000000 --- a/kmath-dimensions/src/commonMain/kotlin/space/kscience/kmath/dimensions/Wrappers.kt +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.dimensions - -import space.kscience.kmath.linear.LinearSpace -import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.linear.Point -import space.kscience.kmath.linear.transpose -import space.kscience.kmath.nd.Structure2D -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Ring -import kotlin.jvm.JvmInline - -/** - * A matrix with compile-time controlled dimension - */ -public interface DMatrix : Structure2D { - public companion object { - /** - * 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()) { - "Row number mismatch: expected ${Dimension.dim()} but found ${structure.rowNum}" - } - - require(structure.colNum == Dimension.dim()) { - "Column number mismatch: expected ${Dimension.dim()} but found ${structure.colNum}" - } - - return DMatrixWrapper(structure) - } - - /** - * The same as [DMatrix.coerce] but without dimension checks. Use with caution. - */ - public fun coerceUnsafe(structure: Structure2D): DMatrix = - DMatrixWrapper(structure) - } -} - -/** - * An inline wrapper for a Matrix - */ -@JvmInline -public value class DMatrixWrapper( - private val structure: Structure2D, -) : DMatrix { - override val shape: IntArray get() = structure.shape - override val rowNum: Int get() = shape[0] - override val colNum: Int get() = shape[1] - override operator fun get(i: Int, j: Int): T = structure[i, j] -} - -/** - * Dimension-safe point - */ -public interface DPoint : Point { - public companion object { - public inline fun coerce(point: Point): DPoint { - require(point.size == Dimension.dim()) { - "Vector dimension mismatch: expected ${Dimension.dim()}, but found ${point.size}" - } - - return DPointWrapper(point) - } - - public fun coerceUnsafe(point: Point): DPoint = DPointWrapper(point) - } -} - -/** - * Dimension-safe point wrapper - */ -@JvmInline -public value class DPointWrapper(public val point: Point) : - DPoint { - override val size: Int get() = point.size - - override operator fun get(index: Int): T = point[index] - - override operator fun iterator(): Iterator = point.iterator() -} - - -/** - * Basic operations on dimension-safe matrices. Operates on [Matrix] - */ -@JvmInline -public value class DMatrixContext>(public val context: LinearSpace) { - public inline fun Matrix.coerce(): DMatrix { - require(rowNum == Dimension.dim()) { - "Row number mismatch: expected ${Dimension.dim()} but found $rowNum" - } - - require(colNum == Dimension.dim()) { - "Column number mismatch: expected ${Dimension.dim()} but found $colNum" - } - - return DMatrix.coerceUnsafe(this) - } - - /** - * Produce a matrix with this context and given dimensions - */ - public inline fun produce( - noinline initializer: A.(i: Int, j: Int) -> T, - ): DMatrix { - val rows = Dimension.dim() - val cols = Dimension.dim() - return context.buildMatrix(rows, cols, initializer).coerce() - } - - public inline fun point(noinline initializer: A.(Int) -> T): DPoint { - val size = Dimension.dim() - - return DPoint.coerceUnsafe( - context.buildVector( - size, - initializer - ) - ) - } - - public inline infix fun DMatrix.dot( - other: DMatrix, - ): DMatrix = context.run { this@dot dot other }.coerce() - - public inline infix fun DMatrix.dot(vector: DPoint): DPoint = - DPoint.coerceUnsafe(context.run { this@dot dot vector }) - - public inline operator fun DMatrix.times(value: T): DMatrix = - context.run { this@times.times(value) }.coerce() - - public inline operator fun T.times(m: DMatrix): DMatrix = - m * this - - public inline operator fun DMatrix.plus(other: DMatrix): DMatrix = - context.run { this@plus + other }.coerce() - - public inline operator fun DMatrix.minus(other: DMatrix): DMatrix = - context.run { this@minus + other }.coerce() - - public inline operator fun DMatrix.unaryMinus(): DMatrix = - context.run { this@unaryMinus.unaryMinus() }.coerce() - - public inline fun DMatrix.transpose(): DMatrix = - context.run { (this@transpose as Matrix).transpose() }.coerce() - - public companion object { - public val real: DMatrixContext = DMatrixContext(LinearSpace.real) - } -} - - -/** - * A square unit matrix - */ -public inline fun DMatrixContext.one(): DMatrix = - produce { i, j -> - if (i == j) 1.0 else 0.0 - } - -public inline fun DMatrixContext.zero(): DMatrix = - produce { _, _ -> - 0.0 - } diff --git a/kmath-dimensions/src/commonTest/kotlin/scientifik/dimensions/DMatrixContextTest.kt b/kmath-dimensions/src/commonTest/kotlin/scientifik/dimensions/DMatrixContextTest.kt new file mode 100644 index 000000000..74d20205c --- /dev/null +++ b/kmath-dimensions/src/commonTest/kotlin/scientifik/dimensions/DMatrixContextTest.kt @@ -0,0 +1,30 @@ +package scientifik.dimensions + +import scientifik.kmath.dimensions.D2 +import scientifik.kmath.dimensions.D3 +import scientifik.kmath.dimensions.DMatrixContext +import kotlin.test.Test + + +class DMatrixContextTest { + @Test + fun testDimensionSafeMatrix() { + val res = DMatrixContext.real.run { + val m = produce { i, j -> (i + j).toDouble() } + + //The dimension of `one()` is inferred from type + (m + one()) + } + } + + @Test + fun testTypeCheck() { + val res = DMatrixContext.real.run { + val m1 = produce { i, j -> (i + j).toDouble() } + val m2 = produce { i, j -> (i + j).toDouble() } + + //Dimension-safe addition + m1.transpose() + m2 + } + } +} \ No newline at end of file diff --git a/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt b/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt deleted file mode 100644 index efa3170a3..000000000 --- a/kmath-dimensions/src/commonTest/kotlin/space/kscience/dimensions/DMatrixContextTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.dimensions - -import space.kscience.kmath.dimensions.D2 -import space.kscience.kmath.dimensions.D3 -import space.kscience.kmath.dimensions.DMatrixContext -import space.kscience.kmath.dimensions.one -import kotlin.test.Test - -@Suppress("UNUSED_VARIABLE") -internal class DMatrixContextTest { - @Test - fun testDimensionSafeMatrix() { - val res = with(DMatrixContext.real) { - val m = produce { i, j -> (i + j).toDouble() } - - //The dimension of `one()` is inferred from type - (m + one()) - } - } - - @Test - fun testTypeCheck() { - val res = with(DMatrixContext.real) { - val m1 = produce { i, j -> (i + j).toDouble() } - val m2 = produce { i, j -> (i + j).toDouble() } - - //Dimension-safe addition - m1.transpose() + m2 - } - } -} diff --git a/kmath-dimensions/src/jsMain/kotlin/scientifik/kmath/dimensions/dim.kt b/kmath-dimensions/src/jsMain/kotlin/scientifik/kmath/dimensions/dim.kt new file mode 100644 index 000000000..bbd580629 --- /dev/null +++ b/kmath-dimensions/src/jsMain/kotlin/scientifik/kmath/dimensions/dim.kt @@ -0,0 +1,22 @@ +package scientifik.kmath.dimensions + +import kotlin.reflect.KClass + +private val dimensionMap = hashMapOf( + 1u to D1, + 2u to D2, + 3u to D3 +) + +@Suppress("UNCHECKED_CAST") +actual fun Dimension.Companion.resolve(type: KClass): D { + return dimensionMap.entries.find { it.value::class == type }?.value as? D ?: error("Can't resolve dimension $type") +} + +actual fun Dimension.Companion.of(dim: UInt): Dimension { + return dimensionMap.getOrPut(dim) { + object : Dimension { + override val dim: UInt get() = dim + } + } +} \ No newline at end of file diff --git a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt deleted file mode 100644 index 324c78108..000000000 --- a/kmath-dimensions/src/jsMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.dimensions - -import kotlin.reflect.KClass - -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) - .find { it::class == type } as? D - ?: error("Can't resolve dimension $type") - -public actual fun Dimension.Companion.of(dim: Int): Dimension = dimensionMap.getOrPut(dim) { - object : Dimension { - override val dim: Int get() = dim - } -} diff --git a/kmath-dimensions/src/jvmMain/kotlin/scientifik/kmath/dimensions/dim.kt b/kmath-dimensions/src/jvmMain/kotlin/scientifik/kmath/dimensions/dim.kt new file mode 100644 index 000000000..e8fe8f59b --- /dev/null +++ b/kmath-dimensions/src/jvmMain/kotlin/scientifik/kmath/dimensions/dim.kt @@ -0,0 +1,18 @@ +package scientifik.kmath.dimensions + +import kotlin.reflect.KClass + +actual fun Dimension.Companion.resolve(type: KClass): D{ + return type.objectInstance ?: error("No object instance for dimension class") +} + +actual fun Dimension.Companion.of(dim: UInt): Dimension{ + return when(dim){ + 1u -> D1 + 2u -> D2 + 3u -> D3 + else -> object : Dimension { + override val dim: UInt get() = dim + } + } +} \ No newline at end of file diff --git a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt deleted file mode 100644 index 8fc683ed6..000000000 --- a/kmath-dimensions/src/jvmMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -@file:JvmName("DimensionJVM") - -package space.kscience.kmath.dimensions - -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: Int): Dimension = when (dim) { - 1 -> D1 - 2 -> D2 - 3 -> D3 - - else -> object : Dimension { - override val dim: Int get() = dim - } -} diff --git a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt b/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt deleted file mode 100644 index 001d68935..000000000 --- a/kmath-dimensions/src/nativeMain/kotlin/space/kscience/kmath/dimensions/Dimension.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.dimensions - -import kotlin.native.concurrent.ThreadLocal -import kotlin.reflect.KClass - -@ThreadLocal -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) - .find { it::class == type } as? D - ?: error("Can't resolve dimension $type") - -public actual fun Dimension.Companion.of(dim: Int): Dimension = dimensionMap.getOrPut(dim) { - object : Dimension { - override val dim: Int get() = dim - } -} diff --git a/kmath-ejml/README.md b/kmath-ejml/README.md deleted file mode 100644 index f88f53000..000000000 --- a/kmath-ejml/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Module kmath-ejml - -EJML based linear algebra implementation. - - - [ejml-vector](src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt) : Point implementations. - - [ejml-matrix](src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt) : Matrix implementation. - - [ejml-linear-space](src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt) : LinearSpace implementations. - - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-ejml:0.3.0-dev-14`. - -**Gradle:** -```gradle -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-ejml:0.3.0-dev-14' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-ejml:0.3.0-dev-14") -} -``` diff --git a/kmath-ejml/build.gradle.kts b/kmath-ejml/build.gradle.kts deleted file mode 100644 index 727d21e3a..000000000 --- a/kmath-ejml/build.gradle.kts +++ /dev/null @@ -1,42 +0,0 @@ -import space.kscience.kmath.ejml.codegen.ejmlCodegen - -plugins { - kotlin("jvm") - id("ru.mipt.npm.gradle.common") -} - -dependencies { - 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")) -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE - propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) - - feature( - id = "ejml-vector", - ref = "src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt" - ) { "Point implementations." } - - feature( - id = "ejml-matrix", - ref = "src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt" - ) { "Matrix implementation." } - - feature( - id = "ejml-linear-space", - ref = "src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt" - ) { "LinearSpace implementations." } -} - -kotlin.sourceSets.main { - val codegen by tasks.creating { - ejmlCodegen(kotlin.srcDirs.first().absolutePath + "/space/kscience/kmath/ejml/_generated.kt") - } - - kotlin.srcDirs(files().builtBy(codegen)) -} diff --git a/kmath-ejml/docs/README-TEMPLATE.md b/kmath-ejml/docs/README-TEMPLATE.md deleted file mode 100644 index 27fcedd65..000000000 --- a/kmath-ejml/docs/README-TEMPLATE.md +++ /dev/null @@ -1,7 +0,0 @@ -# Module kmath-ejml - -EJML based linear algebra implementation. - -${features} - -${artifact} diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt deleted file mode 100644 index 022a7874e..000000000 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlLinearSpace.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ejml - -import space.kscience.kmath.linear.LinearSpace -import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.linear.Point -import space.kscience.kmath.operations.Ring - -/** - * [LinearSpace] implementation specialized for a certain EJML type. - * - * @param T the type of items in the matrices. - * @param A the element context type. - * @param M the EJML matrix type. - * @author Iaroslav Postovalov - */ -public abstract class EjmlLinearSpace, out M : org.ejml.data.Matrix> : LinearSpace { - /** - * Converts this matrix to EJML one. - */ - public abstract fun Matrix.toEjml(): EjmlMatrix - - /** - * Converts this vector to EJML one. - */ - public abstract fun Point.toEjml(): EjmlVector - - public abstract override fun buildMatrix( - rows: Int, - columns: Int, - initializer: A.(i: Int, j: Int) -> T, - ): EjmlMatrix - - public abstract override fun buildVector(size: Int, initializer: A.(Int) -> T): EjmlVector -} 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 deleted file mode 100644 index 9ad0f9c77..000000000 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlMatrix.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ejml - -import org.ejml.data.Matrix -import space.kscience.kmath.nd.Structure2D - -/** - * [space.kscience.kmath.linear.Matrix] implementation based on EJML [Matrix]. - * - * @param T the type of elements contained in the buffer. - * @param M the type of EJML matrix. - * @property origin The underlying EJML matrix. - * @author Iaroslav Postovalov - */ -public abstract class EjmlMatrix(public open val origin: M) : Structure2D { - 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 deleted file mode 100644 index a6de1b657..000000000 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/EjmlVector.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ejml - -import org.ejml.data.Matrix -import space.kscience.kmath.linear.Point - -/** - * [Point] implementation based on EJML [Matrix]. - * - * @param T the type of elements contained in the buffer. - * @param M the type of EJML matrix. - * @property origin The underlying matrix, must have only one row. - * @author Iaroslav Postovalov - */ -public abstract class EjmlVector(public open val origin: M) : Point { - override val size: Int - get() = origin.numCols - - override operator fun iterator(): Iterator = object : Iterator { - private var cursor: Int = 0 - - override fun next(): T { - cursor += 1 - return this@EjmlVector[cursor - 1] - } - - override fun hasNext(): Boolean = cursor < origin.numCols * origin.numRows - } - - override fun toString(): String = "EjmlVector(origin=$origin)" -} diff --git a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt b/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt deleted file mode 100644 index 492d16510..000000000 --- a/kmath-ejml/src/main/kotlin/space/kscience/kmath/ejml/_generated.kt +++ /dev/null @@ -1,995 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -/* This file is generated with buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt */ - -package space.kscience.kmath.ejml - -import org.ejml.data.* -import org.ejml.dense.row.CommonOps_DDRM -import org.ejml.dense.row.CommonOps_FDRM -import org.ejml.dense.row.factory.DecompositionFactory_DDRM -import org.ejml.dense.row.factory.DecompositionFactory_FDRM -import org.ejml.sparse.FillReducing -import org.ejml.sparse.csc.CommonOps_DSCC -import org.ejml.sparse.csc.CommonOps_FSCC -import org.ejml.sparse.csc.factory.DecompositionFactory_DSCC -import org.ejml.sparse.csc.factory.DecompositionFactory_FSCC -import org.ejml.sparse.csc.factory.LinearSolverFactory_DSCC -import org.ejml.sparse.csc.factory.LinearSolverFactory_FSCC -import space.kscience.kmath.linear.* -import space.kscience.kmath.linear.Matrix -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.StructureFeature -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.FloatField -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.FloatBuffer -import kotlin.reflect.KClass -import kotlin.reflect.cast - -/** - * [EjmlVector] specialization for [Double]. - */ -public class EjmlDoubleVector(override val origin: M) : EjmlVector(origin) { - init { - require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } - } - - override operator fun get(index: Int): Double = origin[0, index] -} - -/** - * [EjmlVector] specialization for [Float]. - */ -public class EjmlFloatVector(override val origin: M) : EjmlVector(origin) { - init { - require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" } - } - - override operator fun get(index: Int): Float = origin[0, index] -} - -/** - * [EjmlMatrix] specialization for [Double]. - */ -public class EjmlDoubleMatrix(override val origin: M) : EjmlMatrix(origin) { - override operator fun get(i: Int, j: Int): Double = origin[i, j] -} - -/** - * [EjmlMatrix] specialization for [Float]. - */ -public class EjmlFloatMatrix(override val origin: M) : EjmlMatrix(origin) { - override operator fun get(i: Int, j: Int): Float = origin[i, j] -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_DDRM], [DecompositionFactory_DDRM] operations and - * [DMatrixRMaj] matrices. - */ -public object EjmlLinearSpaceDDRM : EjmlLinearSpace() { - /** - * The [DoubleField] reference. - */ - override val elementAlgebra: DoubleField get() = DoubleField - - @Suppress("UNCHECKED_CAST") - override fun Matrix.toEjml(): EjmlDoubleMatrix = when { - this is EjmlDoubleMatrix<*> && origin is DMatrixRMaj -> this as EjmlDoubleMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - override fun Point.toEjml(): EjmlDoubleVector = when { - this is EjmlDoubleVector<*> && origin is DMatrixRMaj -> this as EjmlDoubleVector - else -> EjmlDoubleVector(DMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: DoubleField.(i: Int, j: Int) -> Double, - ): EjmlDoubleMatrix = DMatrixRMaj(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - override fun buildVector( - size: Int, - initializer: DoubleField.(Int) -> Double, - ): EjmlDoubleVector = EjmlDoubleVector(DMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlDoubleMatrix(this) - private fun T.wrapVector() = EjmlDoubleVector(this) - - override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixRMaj(1, 1) - CommonOps_DDRM.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - override fun Matrix.dot(vector: Point): EjmlDoubleVector { - val out = DMatrixRMaj(1, 1) - CommonOps_DDRM.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - override operator fun Matrix.times(value: Double): EjmlDoubleMatrix { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - override fun Point.unaryMinus(): EjmlDoubleVector { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - override fun Point.plus(other: Point): EjmlDoubleVector { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - override fun Point.minus(other: Point): EjmlDoubleVector { - val out = DMatrixRMaj(1, 1) - - CommonOps_DDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this - - override fun Point.times(value: Double): EjmlDoubleVector { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - override fun Double.times(v: Point): EjmlDoubleVector = v * this - - @UnstableKMathAPI - override fun getFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - InverseMatrixFeature::class -> object : InverseMatrixFeature { - override val inverse: Matrix by lazy { - val res = origin.copy() - CommonOps_DDRM.invert(res) - res.wrapMatrix() - } - } - - DeterminantFeature::class -> object : DeterminantFeature { - override val determinant: Double by lazy { CommonOps_DDRM.det(origin) } - } - - SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { - private val svd by lazy { - DecompositionFactory_DDRM.svd(origin.numRows, origin.numCols, true, true, false) - .apply { decompose(origin.copy()) } - } - - override val u: Matrix by lazy { svd.getU(null, false).wrapMatrix() } - override val s: Matrix by lazy { svd.getW(null).wrapMatrix() } - override val v: Matrix by lazy { svd.getV(null, false).wrapMatrix() } - override val singularValues: Point by lazy { DoubleBuffer(svd.singularValues) } - } - - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_DDRM.qr().apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix() + OrthogonalFeature - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix() + UFeature } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_DDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) } - - cholesky.getT(null).wrapMatrix() + LFeature - } - } - - LupDecompositionFeature::class -> object : LupDecompositionFeature { - private val lup by lazy { - DecompositionFactory_DDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lup.getLower(null).wrapMatrix() + LFeature - } - - override val u: Matrix by lazy { - lup.getUpper(null).wrapMatrix() + UFeature - } - - override val p: Matrix by lazy { lup.getRowPivot(null).wrapMatrix() } - } - - else -> null - }?.let(type::cast) - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlDoubleMatrix { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.solve(DMatrixRMaj(a.toEjml().origin), DMatrixRMaj(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlDoubleVector { - val res = DMatrixRMaj(1, 1) - CommonOps_DDRM.solve(DMatrixRMaj(a.toEjml().origin), DMatrixRMaj(b.toEjml().origin), res) - return EjmlDoubleVector(res) - } -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_FDRM], [DecompositionFactory_FDRM] operations and - * [FMatrixRMaj] matrices. - */ -public object EjmlLinearSpaceFDRM : EjmlLinearSpace() { - /** - * The [FloatField] reference. - */ - override val elementAlgebra: FloatField get() = FloatField - - @Suppress("UNCHECKED_CAST") - override fun Matrix.toEjml(): EjmlFloatMatrix = when { - this is EjmlFloatMatrix<*> && origin is FMatrixRMaj -> this as EjmlFloatMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - override fun Point.toEjml(): EjmlFloatVector = when { - this is EjmlFloatVector<*> && origin is FMatrixRMaj -> this as EjmlFloatVector - else -> EjmlFloatVector(FMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: FloatField.(i: Int, j: Int) -> Float, - ): EjmlFloatMatrix = FMatrixRMaj(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - override fun buildVector( - size: Int, - initializer: FloatField.(Int) -> Float, - ): EjmlFloatVector = EjmlFloatVector(FMatrixRMaj(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlFloatMatrix(this) - private fun T.wrapVector() = EjmlFloatVector(this) - - override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { - val out = FMatrixRMaj(1, 1) - CommonOps_FDRM.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - override fun Matrix.dot(vector: Point): EjmlFloatVector { - val out = FMatrixRMaj(1, 1) - CommonOps_FDRM.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - override operator fun Matrix.times(value: Float): EjmlFloatMatrix { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - override fun Point.unaryMinus(): EjmlFloatVector { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapMatrix() - } - - override fun Point.plus(other: Point): EjmlFloatVector { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - override fun Point.minus(other: Point): EjmlFloatVector { - val out = FMatrixRMaj(1, 1) - - CommonOps_FDRM.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - ) - - return out.wrapVector() - } - - override fun Float.times(m: Matrix): EjmlFloatMatrix = m * this - - override fun Point.times(value: Float): EjmlFloatVector { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - override fun Float.times(v: Point): EjmlFloatVector = v * this - - @UnstableKMathAPI - override fun getFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - InverseMatrixFeature::class -> object : InverseMatrixFeature { - override val inverse: Matrix by lazy { - val res = origin.copy() - CommonOps_FDRM.invert(res) - res.wrapMatrix() - } - } - - DeterminantFeature::class -> object : DeterminantFeature { - override val determinant: Float by lazy { CommonOps_FDRM.det(origin) } - } - - SingularValueDecompositionFeature::class -> object : SingularValueDecompositionFeature { - private val svd by lazy { - DecompositionFactory_FDRM.svd(origin.numRows, origin.numCols, true, true, false) - .apply { decompose(origin.copy()) } - } - - override val u: Matrix by lazy { svd.getU(null, false).wrapMatrix() } - override val s: Matrix by lazy { svd.getW(null).wrapMatrix() } - override val v: Matrix by lazy { svd.getV(null, false).wrapMatrix() } - override val singularValues: Point by lazy { FloatBuffer(svd.singularValues) } - } - - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_FDRM.qr().apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix() + OrthogonalFeature - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix() + UFeature } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_FDRM.chol(structure.rowNum, true).apply { decompose(origin.copy()) } - - cholesky.getT(null).wrapMatrix() + LFeature - } - } - - LupDecompositionFeature::class -> object : LupDecompositionFeature { - private val lup by lazy { - DecompositionFactory_FDRM.lu(origin.numRows, origin.numCols).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lup.getLower(null).wrapMatrix() + LFeature - } - - override val u: Matrix by lazy { - lup.getUpper(null).wrapMatrix() + UFeature - } - - override val p: Matrix by lazy { lup.getRowPivot(null).wrapMatrix() } - } - - else -> null - }?.let(type::cast) - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlFloatMatrix { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.solve(FMatrixRMaj(a.toEjml().origin), FMatrixRMaj(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlFloatVector { - val res = FMatrixRMaj(1, 1) - CommonOps_FDRM.solve(FMatrixRMaj(a.toEjml().origin), FMatrixRMaj(b.toEjml().origin), res) - return EjmlFloatVector(res) - } -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_DSCC], [DecompositionFactory_DSCC] operations and - * [DMatrixSparseCSC] matrices. - */ -public object EjmlLinearSpaceDSCC : EjmlLinearSpace() { - /** - * The [DoubleField] reference. - */ - override val elementAlgebra: DoubleField get() = DoubleField - - @Suppress("UNCHECKED_CAST") - override fun Matrix.toEjml(): EjmlDoubleMatrix = when { - this is EjmlDoubleMatrix<*> && origin is DMatrixSparseCSC -> this as EjmlDoubleMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - override fun Point.toEjml(): EjmlDoubleVector = when { - this is EjmlDoubleVector<*> && origin is DMatrixSparseCSC -> this as EjmlDoubleVector - else -> EjmlDoubleVector(DMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: DoubleField.(i: Int, j: Int) -> Double, - ): EjmlDoubleMatrix = DMatrixSparseCSC(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - override fun buildVector( - size: Int, - initializer: DoubleField.(Int) -> Double, - ): EjmlDoubleVector = EjmlDoubleVector(DMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlDoubleMatrix(this) - private fun T.wrapVector() = EjmlDoubleVector(this) - - override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - override fun Matrix.dot(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - override fun Matrix.dot(vector: Point): EjmlDoubleVector { - val out = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - override operator fun Matrix.minus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - override operator fun Matrix.times(value: Double): EjmlDoubleMatrix { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - override fun Point.unaryMinus(): EjmlDoubleVector { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - override fun Matrix.plus(other: Matrix): EjmlDoubleMatrix { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - override fun Point.plus(other: Point): EjmlDoubleVector { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - override fun Point.minus(other: Point): EjmlDoubleVector { - val out = DMatrixSparseCSC(1, 1) - - CommonOps_DSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - override fun Double.times(m: Matrix): EjmlDoubleMatrix = m * this - - override fun Point.times(value: Double): EjmlDoubleVector { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - override fun Double.times(v: Point): EjmlDoubleVector = v * this - - @UnstableKMathAPI - override fun getFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_DSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix() + OrthogonalFeature - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix() + UFeature } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_DSCC.cholesky().apply { decompose(origin.copy()) } - - (cholesky.getT(null) as DMatrix).wrapMatrix() + LFeature - } - } - - LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : - LUDecompositionFeature, DeterminantFeature, InverseMatrixFeature { - private val lu by lazy { - DecompositionFactory_DSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lu.getLower(null).wrapMatrix() + LFeature - } - - override val u: Matrix by lazy { - lu.getUpper(null).wrapMatrix() + UFeature - } - - override val inverse: Matrix by lazy { - var a = origin - val inverse = DMatrixRMaj(1, 1) - val solver = LinearSolverFactory_DSCC.lu(FillReducing.NONE) - if (solver.modifiesA()) a = a.copy() - val i = CommonOps_DDRM.identity(a.numRows) - solver.solve(i, inverse) - inverse.wrapMatrix() - } - - override val determinant: Double by lazy { elementAlgebra.number(lu.computeDeterminant().real) } - } - - else -> null - }?.let(type::cast) - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlDoubleMatrix { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.solve(DMatrixSparseCSC(a.toEjml().origin), DMatrixSparseCSC(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlDoubleVector { - val res = DMatrixSparseCSC(1, 1) - CommonOps_DSCC.solve(DMatrixSparseCSC(a.toEjml().origin), DMatrixSparseCSC(b.toEjml().origin), res) - return EjmlDoubleVector(res) - } -} - -/** - * [EjmlLinearSpace] implementation based on [CommonOps_FSCC], [DecompositionFactory_FSCC] operations and - * [FMatrixSparseCSC] matrices. - */ -public object EjmlLinearSpaceFSCC : EjmlLinearSpace() { - /** - * The [FloatField] reference. - */ - override val elementAlgebra: FloatField get() = FloatField - - @Suppress("UNCHECKED_CAST") - override fun Matrix.toEjml(): EjmlFloatMatrix = when { - this is EjmlFloatMatrix<*> && origin is FMatrixSparseCSC -> this as EjmlFloatMatrix - else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) } - } - - @Suppress("UNCHECKED_CAST") - override fun Point.toEjml(): EjmlFloatVector = when { - this is EjmlFloatVector<*> && origin is FMatrixSparseCSC -> this as EjmlFloatVector - else -> EjmlFloatVector(FMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = get(row) } - }) - } - - override fun buildMatrix( - rows: Int, - columns: Int, - initializer: FloatField.(i: Int, j: Int) -> Float, - ): EjmlFloatMatrix = FMatrixSparseCSC(rows, columns).also { - (0 until rows).forEach { row -> - (0 until columns).forEach { col -> it[row, col] = elementAlgebra.initializer(row, col) } - } - }.wrapMatrix() - - override fun buildVector( - size: Int, - initializer: FloatField.(Int) -> Float, - ): EjmlFloatVector = EjmlFloatVector(FMatrixSparseCSC(size, 1).also { - (0 until it.numRows).forEach { row -> it[row, 0] = elementAlgebra.initializer(row) } - }) - - private fun T.wrapMatrix() = EjmlFloatMatrix(this) - private fun T.wrapVector() = EjmlFloatVector(this) - - override fun Matrix.unaryMinus(): Matrix = this * elementAlgebra { -one } - - override fun Matrix.dot(other: Matrix): EjmlFloatMatrix { - val out = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.mult(toEjml().origin, other.toEjml().origin, out) - return out.wrapMatrix() - } - - override fun Matrix.dot(vector: Point): EjmlFloatVector { - val out = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.mult(toEjml().origin, vector.toEjml().origin, out) - return out.wrapVector() - } - - override operator fun Matrix.minus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - override operator fun Matrix.times(value: Float): EjmlFloatMatrix { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.scale(value, toEjml().origin, res) - return res.wrapMatrix() - } - - override fun Point.unaryMinus(): EjmlFloatVector { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.changeSign(toEjml().origin, res) - return res.wrapVector() - } - - override fun Matrix.plus(other: Matrix): EjmlFloatMatrix { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapMatrix() - } - - override fun Point.plus(other: Point): EjmlFloatVector { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra.one, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - override fun Point.minus(other: Point): EjmlFloatVector { - val out = FMatrixSparseCSC(1, 1) - - CommonOps_FSCC.add( - elementAlgebra.one, - toEjml().origin, - elementAlgebra { -one }, - other.toEjml().origin, - out, - null, - null, - ) - - return out.wrapVector() - } - - override fun Float.times(m: Matrix): EjmlFloatMatrix = m * this - - override fun Point.times(value: Float): EjmlFloatVector { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.scale(value, toEjml().origin, res) - return res.wrapVector() - } - - override fun Float.times(v: Point): EjmlFloatVector = v * this - - @UnstableKMathAPI - override fun getFeature(structure: Matrix, type: KClass): F? { - structure.getFeature(type)?.let { return it } - val origin = structure.toEjml().origin - - return when (type) { - QRDecompositionFeature::class -> object : QRDecompositionFeature { - private val qr by lazy { - DecompositionFactory_FSCC.qr(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val q: Matrix by lazy { - qr.getQ(null, false).wrapMatrix() + OrthogonalFeature - } - - override val r: Matrix by lazy { qr.getR(null, false).wrapMatrix() + UFeature } - } - - CholeskyDecompositionFeature::class -> object : CholeskyDecompositionFeature { - override val l: Matrix by lazy { - val cholesky = - DecompositionFactory_FSCC.cholesky().apply { decompose(origin.copy()) } - - (cholesky.getT(null) as FMatrix).wrapMatrix() + LFeature - } - } - - LUDecompositionFeature::class, DeterminantFeature::class, InverseMatrixFeature::class -> object : - LUDecompositionFeature, DeterminantFeature, InverseMatrixFeature { - private val lu by lazy { - DecompositionFactory_FSCC.lu(FillReducing.NONE).apply { decompose(origin.copy()) } - } - - override val l: Matrix by lazy { - lu.getLower(null).wrapMatrix() + LFeature - } - - override val u: Matrix by lazy { - lu.getUpper(null).wrapMatrix() + UFeature - } - - override val inverse: Matrix by lazy { - var a = origin - val inverse = FMatrixRMaj(1, 1) - val solver = LinearSolverFactory_FSCC.lu(FillReducing.NONE) - if (solver.modifiesA()) a = a.copy() - val i = CommonOps_FDRM.identity(a.numRows) - solver.solve(i, inverse) - inverse.wrapMatrix() - } - - override val determinant: Float by lazy { elementAlgebra.number(lu.computeDeterminant().real) } - } - - else -> null - }?.let(type::cast) - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p matrix. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Matrix): EjmlFloatMatrix { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.solve(FMatrixSparseCSC(a.toEjml().origin), FMatrixSparseCSC(b.toEjml().origin), res) - return res.wrapMatrix() - } - - /** - * Solves for *x* in the following equation: *x = [a] -1 · [b]*. - * - * @param a the base matrix. - * @param b n by p vector. - * @return the solution for *x* that is n by p. - */ - public fun solve(a: Matrix, b: Point): EjmlFloatVector { - val res = FMatrixSparseCSC(1, 1) - CommonOps_FSCC.solve(FMatrixSparseCSC(a.toEjml().origin), FMatrixSparseCSC(b.toEjml().origin), res) - return EjmlFloatVector(res) - } -} - diff --git a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt deleted file mode 100644 index 08afa4c68..000000000 --- a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlMatrixTest.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ejml - -import org.ejml.data.DMatrixRMaj -import org.ejml.dense.row.CommonOps_DDRM -import org.ejml.dense.row.RandomMatrices_DDRM -import org.ejml.dense.row.factory.DecompositionFactory_DDRM -import space.kscience.kmath.linear.DeterminantFeature -import space.kscience.kmath.linear.LupDecompositionFeature -import space.kscience.kmath.linear.getFeature -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.StructureND -import kotlin.random.Random -import kotlin.random.asJavaRandom -import kotlin.test.* - -@OptIn(PerformancePitfall::class) -fun assertMatrixEquals(expected: StructureND, actual: StructureND) { - assertTrue { StructureND.contentEquals(expected, actual) } -} - -internal class EjmlMatrixTest { - private val random = Random(0) - - private val randomMatrix: DMatrixRMaj - get() { - val s = random.nextInt(2, 100) - val d = DMatrixRMaj(s, s) - RandomMatrices_DDRM.fillUniform(d, random.asJavaRandom()) - return d - } - - @Test - fun rowNum() { - val m = randomMatrix - assertEquals(m.numRows, EjmlDoubleMatrix(m).rowNum) - } - - @Test - fun colNum() { - val m = randomMatrix - assertEquals(m.numCols, EjmlDoubleMatrix(m).rowNum) - } - - @Test - fun shape() { - val m = randomMatrix - val w = EjmlDoubleMatrix(m) - assertContentEquals(intArrayOf(m.numRows, m.numCols), w.shape) - } - - @OptIn(UnstableKMathAPI::class) - @Test - fun features() { - val m = randomMatrix - val w = EjmlDoubleMatrix(m) - val det: DeterminantFeature = EjmlLinearSpaceDDRM.getFeature(w) ?: fail() - assertEquals(CommonOps_DDRM.det(m), det.determinant) - val lup: LupDecompositionFeature = EjmlLinearSpaceDDRM.getFeature(w) ?: fail() - - val ludecompositionF64 = DecompositionFactory_DDRM.lu(m.numRows, m.numCols) - .also { it.decompose(m.copy()) } - - assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getLower(null)), lup.l) - assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getUpper(null)), lup.u) - assertMatrixEquals(EjmlDoubleMatrix(ludecompositionF64.getRowPivot(null)), lup.p) - } - - @Test - fun get() { - val m = randomMatrix - assertEquals(m[0, 0], EjmlDoubleMatrix(m)[0, 0]) - } - - @Test - fun origin() { - val m = randomMatrix - assertSame(m, EjmlDoubleMatrix(m).origin) - } -} diff --git a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt b/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt deleted file mode 100644 index c87a01436..000000000 --- a/kmath-ejml/src/test/kotlin/space/kscience/kmath/ejml/EjmlVectorTest.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.ejml - -import org.ejml.data.DMatrixRMaj -import org.ejml.dense.row.RandomMatrices_DDRM -import kotlin.random.Random -import kotlin.random.asJavaRandom -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertSame - -internal class EjmlVectorTest { - private val random = Random(0) - - private val randomMatrix: DMatrixRMaj - get() { - val d = DMatrixRMaj(1, random.nextInt(2, 100)) - RandomMatrices_DDRM.fillUniform(d, random.asJavaRandom()) - return d - } - - @Test - fun size() { - val m = randomMatrix - val w = EjmlDoubleVector(m) - assertEquals(m.numCols, w.size) - } - - @Test - fun get() { - val m = randomMatrix - val w = EjmlDoubleVector(m) - assertEquals(m[0, 0], w[0]) - } - - @Test - fun iterator() { - val m = randomMatrix - val w = EjmlDoubleVector(m) - - assertEquals( - m.iterator(true, 0, 0, 0, m.numCols - 1).asSequence().toList(), - w.iterator().asSequence().toList() - ) - } - - @Test - fun origin() { - val m = randomMatrix - val w = EjmlDoubleVector(m) - assertSame(m, w.origin) - } -} diff --git a/kmath-for-real/README.md b/kmath-for-real/README.md deleted file mode 100644 index d449b4540..000000000 --- a/kmath-for-real/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Module kmath-for-real - -Specialization of KMath APIs for Double numbers. - - - [DoubleVector](src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt) : Numpy-like operations for Buffers/Points - - [DoubleMatrix](src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt) : Numpy-like operations for 2d real structures - - [grids](src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt) : Uniform grid generators - - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-for-real:0.3.0-dev-14`. - -**Gradle:** -```gradle -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-for-real:0.3.0-dev-14' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - 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 4cccaef5c..a8a8975bc 100644 --- a/kmath-for-real/build.gradle.kts +++ b/kmath-for-real/build.gradle.kts @@ -1,39 +1,11 @@ plugins { - kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("scientifik.mpp") } -kotlin.sourceSets.commonMain { - dependencies { - api(project(":kmath-core")) +kotlin.sourceSets { + commonMain { + dependencies { + api(project(":kmath-core")) + } } -} - -readme { - description = """ - 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() - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL - propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) - - feature( - id = "DoubleVector", - description = "Numpy-like operations for Buffers/Points", - ref = "src/commonMain/kotlin/space/kscience/kmath/real/DoubleVector.kt" - ) - - feature( - id = "DoubleMatrix", - description = "Numpy-like operations for 2d real structures", - ref = "src/commonMain/kotlin/space/kscience/kmath/real/DoubleMatrix.kt" - ) - - feature( - id = "grids", - description = "Uniform grid generators", - ref = "src/commonMain/kotlin/space/kscience/kmath/structures/grids.kt" - ) -} +} \ No newline at end of file diff --git a/kmath-for-real/docs/README-TEMPLATE.md b/kmath-for-real/docs/README-TEMPLATE.md deleted file mode 100644 index c2ef25aa7..000000000 --- a/kmath-for-real/docs/README-TEMPLATE.md +++ /dev/null @@ -1,7 +0,0 @@ -# Module kmath-for-real - -Specialization of KMath APIs for Double numbers. - -${features} - -${artifact} diff --git a/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/RealVector.kt b/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/RealVector.kt new file mode 100644 index 000000000..ff4c835ed --- /dev/null +++ b/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/RealVector.kt @@ -0,0 +1,59 @@ +package scientifik.kmath.real + +import scientifik.kmath.linear.BufferVectorSpace +import scientifik.kmath.linear.Point +import scientifik.kmath.linear.VectorSpace +import scientifik.kmath.operations.Norm +import scientifik.kmath.operations.RealField +import scientifik.kmath.operations.SpaceElement +import scientifik.kmath.structures.Buffer +import scientifik.kmath.structures.DoubleBuffer +import scientifik.kmath.structures.asBuffer +import scientifik.kmath.structures.asIterable +import kotlin.math.sqrt + +fun DoubleArray.asVector() = RealVector(this.asBuffer()) +fun List.asVector() = RealVector(this.asBuffer()) + + +object VectorL2Norm : Norm, Double> { + override fun norm(arg: Point): Double = sqrt(arg.asIterable().sumByDouble { it.toDouble() }) +} + +inline class RealVector(private val point: Point) : + SpaceElement, RealVector, VectorSpace>, Point { + + override val context: VectorSpace + get() = space( + point.size + ) + + override fun unwrap(): Point = point + + override fun Point.wrap(): RealVector = + RealVector(this) + + override val size: Int get() = point.size + + override fun get(index: Int): Double = point[index] + + override fun iterator(): Iterator = point.iterator() + + companion object { + + private val spaceCache = HashMap>() + + inline operator fun invoke(dim: Int, initializer: (Int) -> Double) = + RealVector(DoubleBuffer(dim, initializer)) + + operator fun invoke(vararg values: Double): RealVector = values.asVector() + + fun space(dim: Int): BufferVectorSpace = + spaceCache.getOrPut(dim) { + BufferVectorSpace( + dim, + RealField + ) { size, init -> Buffer.real(size, init) } + } + } +} \ No newline at end of file diff --git a/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/realBuffer.kt b/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/realBuffer.kt new file mode 100644 index 000000000..d9ee4d90b --- /dev/null +++ b/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/realBuffer.kt @@ -0,0 +1,8 @@ +package scientifik.kmath.real + +import scientifik.kmath.structures.DoubleBuffer + +/** + * Simplified [DoubleBuffer] to array comparison + */ +fun DoubleBuffer.contentEquals(vararg doubles: Double) = array.contentEquals(doubles) \ No newline at end of file diff --git a/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/realMatrix.kt b/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/realMatrix.kt new file mode 100644 index 000000000..813d89577 --- /dev/null +++ b/kmath-for-real/src/commonMain/kotlin/scientifik/kmath/real/realMatrix.kt @@ -0,0 +1,161 @@ +package scientifik.kmath.real + +import scientifik.kmath.linear.MatrixContext +import scientifik.kmath.linear.RealMatrixContext.elementContext +import scientifik.kmath.linear.VirtualMatrix +import scientifik.kmath.operations.sum +import scientifik.kmath.structures.Buffer +import scientifik.kmath.structures.DoubleBuffer +import scientifik.kmath.structures.Matrix +import scientifik.kmath.structures.asIterable +import kotlin.math.pow + +/* + * Functions for convenient "numpy-like" operations with Double matrices. + * + * Initial implementation of these functions is taken from: + * https://github.com/thomasnield/numky/blob/master/src/main/kotlin/org/nield/numky/linear/DoubleOperators.kt + * + */ + +/* + * Functions that help create a real (Double) matrix + */ + +typealias RealMatrix = Matrix + +fun realMatrix(rowNum: Int, colNum: Int, initializer: (i: Int, j: Int) -> Double): RealMatrix = + MatrixContext.real.produce(rowNum, colNum, initializer) + +fun Sequence.toMatrix(): RealMatrix = toList().let { + MatrixContext.real.produce(it.size, it[0].size) { row, col -> it[row][col] } +} + +fun Matrix.repeatStackVertical(n: Int): RealMatrix = + VirtualMatrix(rowNum * n, colNum) { row, col -> + get(if (row == 0) 0 else row % rowNum, col) + } + +/* + * Operations for matrix and real number + */ + +operator fun Matrix.times(double: Double): RealMatrix = + MatrixContext.real.produce(rowNum, colNum) { row, col -> + this[row, col] * double + } + +operator fun Matrix.plus(double: Double): RealMatrix = + MatrixContext.real.produce(rowNum, colNum) { row, col -> + this[row, col] + double + } + +operator fun Matrix.minus(double: Double): RealMatrix = + MatrixContext.real.produce(rowNum, colNum) { row, col -> + this[row, col] - double + } + +operator fun Matrix.div(double: Double): RealMatrix = + MatrixContext.real.produce(rowNum, colNum) { row, col -> + this[row, col] / double + } + +operator fun Double.times(matrix: Matrix): RealMatrix = + MatrixContext.real.produce(matrix.rowNum, matrix.colNum) { row, col -> + this * matrix[row, col] + } + +operator fun Double.plus(matrix: Matrix): RealMatrix = + MatrixContext.real.produce(matrix.rowNum, matrix.colNum) { row, col -> + this + matrix[row, col] + } + +operator fun Double.minus(matrix: Matrix): RealMatrix = + MatrixContext.real.produce(matrix.rowNum, matrix.colNum) { row, col -> + this - matrix[row, col] + } + +// TODO: does this operation make sense? Should it be 'this/matrix[row, col]'? +//operator fun Double.div(matrix: Matrix) = MatrixContext.real.produce(matrix.rowNum, matrix.colNum) { +// row, col -> matrix[row, col] / this +//} + +/* + * Per-element (!) square and power operations + */ + +fun Matrix.square(): RealMatrix = MatrixContext.real.produce(rowNum, colNum) { row, col -> + this[row, col].pow(2) +} + +fun Matrix.pow(n: Int): RealMatrix = MatrixContext.real.produce(rowNum, colNum) { i, j -> + this[i, j].pow(n) +} + +/* + * Operations on two matrices (per-element!) + */ + +operator fun Matrix.times(other: Matrix): RealMatrix = + MatrixContext.real.produce(rowNum, colNum) { row, col -> + this[row, col] * other[row, col] + } + +operator fun Matrix.plus(other: Matrix): RealMatrix = + MatrixContext.real.add(this, other) + +operator fun Matrix.minus(other: Matrix): RealMatrix = + MatrixContext.real.produce(rowNum, colNum) { row, col -> + this[row, col] - other[row, col] + } + +/* + * Operations on columns + */ + +inline fun Matrix.appendColumn(crossinline mapper: (Buffer) -> Double) = + MatrixContext.real.produce(rowNum, colNum + 1) { row, col -> + if (col < colNum) + this[row, col] + else + mapper(rows[row]) + } + +fun Matrix.extractColumns(columnRange: IntRange): RealMatrix = + MatrixContext.real.produce(rowNum, columnRange.count()) { row, col -> + this[row, columnRange.first + col] + } + +fun Matrix.extractColumn(columnIndex: Int): RealMatrix = + extractColumns(columnIndex..columnIndex) + +fun Matrix.sumByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j -> + val column = columns[j] + with(elementContext) { + sum(column.asIterable()) + } +} + +fun Matrix.minByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j -> + columns[j].asIterable().min() ?: throw Exception("Cannot produce min on empty column") +} + +fun Matrix.maxByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j -> + columns[j].asIterable().max() ?: throw Exception("Cannot produce min on empty column") +} + +fun Matrix.averageByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j -> + columns[j].asIterable().average() +} + +/* + * Operations processing all elements + */ + +fun Matrix.sum() = elements().map { (_, value) -> value }.sum() + +fun Matrix.min() = elements().map { (_, value) -> value }.min() + +fun Matrix.max() = elements().map { (_, value) -> value }.max() + +fun Matrix.average() = elements().map { (_, value) -> value }.average() 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 deleted file mode 100644 index 16889aea4..000000000 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealMatrix.kt +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -@file:OptIn(PerformancePitfall::class) -@file:Suppress("unused") - -package space.kscience.kmath.real - -import space.kscience.kmath.linear.* -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.asIterable -import kotlin.math.pow - -/* - * Functions for convenient "numpy-like" operations with Double matrices. - * - * Initial implementation of these functions is taken from: - * https://github.com/thomasnield/numky/blob/master/src/main/kotlin/org/nield/numky/linear/DoubleOperators.kt - * - */ - -/* - * Functions that help create a real (Double) matrix - */ - -public typealias RealMatrix = Matrix - -public fun realMatrix(rowNum: Int, colNum: Int, initializer: DoubleField.(i: Int, j: Int) -> Double): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum, initializer) - -@OptIn(UnstableKMathAPI::class) -public fun realMatrix(rowNum: Int, colNum: Int): MatrixBuilder = - LinearSpace.real.matrix(rowNum, colNum) - -public fun Array.toMatrix(): RealMatrix { - return LinearSpace.real.buildMatrix(size, this[0].size) { row, col -> this@toMatrix[row][col] } -} - -public fun Sequence.toMatrix(): RealMatrix = toList().let { - LinearSpace.real.buildMatrix(it.size, it[0].size) { row, col -> it[row][col] } -} - -public fun RealMatrix.repeatStackVertical(n: Int): RealMatrix = - VirtualMatrix(rowNum * n, colNum) { row, col -> - get(if (row == 0) 0 else row % rowNum, col) - } - -/* - * Operations for matrix and real number - */ - -public operator fun RealMatrix.times(double: Double): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> - get(row, col) * double - } - -public operator fun RealMatrix.plus(double: Double): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> - get(row, col) + double - } - -public operator fun RealMatrix.minus(double: Double): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> - get(row, col) - double - } - -public operator fun RealMatrix.div(double: Double): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> - get(row, col) / double - } - -public operator fun Double.times(matrix: RealMatrix): RealMatrix = - LinearSpace.real.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> - this@times * matrix[row, col] - } - -public operator fun Double.plus(matrix: RealMatrix): RealMatrix = - LinearSpace.real.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> - this@plus + matrix[row, col] - } - -public operator fun Double.minus(matrix: RealMatrix): RealMatrix = - LinearSpace.real.buildMatrix(matrix.rowNum, matrix.colNum) { row, col -> - this@minus - matrix[row, col] - } - -// TODO: does this operation make sense? Should it be 'this/matrix[row, col]'? -//operator fun Double.div(matrix: RealMatrix) = MatrixContext.real.produce(matrix.rowNum, matrix.colNum) { -// row, col -> matrix[row, col] / this -//} - -/* - * Operations on two matrices (per-element!) - */ - -@UnstableKMathAPI -public operator fun RealMatrix.times(other: RealMatrix): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> this@times[row, col] * other[row, col] } - -public operator fun RealMatrix.plus(other: RealMatrix): RealMatrix = - LinearSpace.real.run { this@plus + other } - -public operator fun RealMatrix.minus(other: RealMatrix): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum) { row, col -> this@minus[row, col] - other[row, col] } - -/* - * Operations on columns - */ - -public inline fun RealMatrix.appendColumn(crossinline mapper: (Buffer) -> Double): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum + 1) { row, col -> - if (col < colNum) - get(row, col) - else - mapper(rows[row]) - } - -public fun RealMatrix.extractColumns(columnRange: IntRange): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, columnRange.count()) { row, col -> - this@extractColumns[row, columnRange.first + col] - } - -public fun RealMatrix.extractColumn(columnIndex: Int): RealMatrix = - extractColumns(columnIndex..columnIndex) - -public fun RealMatrix.sumByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j -> - columns[j].asIterable().sum() -} - -public fun RealMatrix.minByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j -> - columns[j].asIterable().minOrNull() ?: error("Cannot produce min on empty column") -} - -public fun RealMatrix.maxByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j -> - columns[j].asIterable().maxOrNull() ?: error("Cannot produce min on empty column") -} - -public fun RealMatrix.averageByColumn(): DoubleBuffer = DoubleBuffer(colNum) { j -> - columns[j].asIterable().average() -} - -/* - * Operations processing all elements - */ - -public fun RealMatrix.sum(): Double = elements().map { (_, value) -> value }.sum() -public fun RealMatrix.min(): Double? = elements().map { (_, value) -> value }.minOrNull() -public fun RealMatrix.max(): Double? = elements().map { (_, value) -> value }.maxOrNull() -public fun RealMatrix.average(): Double = elements().map { (_, value) -> value }.average() - -public inline fun RealMatrix.map(crossinline transform: (Double) -> Double): RealMatrix = - LinearSpace.real.buildMatrix(rowNum, colNum) { i, j -> - transform(get(i, j)) - } - -/** - * Inverse a square real matrix using LUP decomposition - */ -public fun RealMatrix.inverseWithLup(): RealMatrix = LinearSpace.real.inverseWithLup(this) - -//extended operations - -public fun RealMatrix.pow(p: Double): RealMatrix = map { it.pow(p) } - -public fun RealMatrix.pow(p: Int): RealMatrix = map { it.pow(p) } - -public fun exp(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.exp(it) } - -public fun sqrt(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.sqrt(it) } - -public fun RealMatrix.square(): RealMatrix = map { it.pow(2) } - -public fun sin(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.sin(it) } - -public fun cos(arg: RealMatrix): RealMatrix = arg.map { kotlin.math.cos(it) } - -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) } 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 deleted file mode 100644 index d942c31f2..000000000 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/RealVector.kt +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.real - -import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Norm -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.MutableBuffer.Companion.double -import space.kscience.kmath.structures.asBuffer -import space.kscience.kmath.structures.fold -import space.kscience.kmath.structures.indices -import kotlin.math.pow -import kotlin.math.sqrt - -public typealias DoubleVector = Point - -@Suppress("FunctionName") -public fun DoubleVector(vararg doubles: Double): DoubleVector = doubles.asBuffer() - -/** - * Fill the vector with given [size] with given [value] - */ -@UnstableKMathAPI -public fun Buffer.Companion.same(size: Int, value: Number): DoubleVector = double(size) { value.toDouble() } - -// Transformation methods - -public inline fun DoubleVector.map(transform: (Double) -> Double): DoubleVector = - double(size) { transform(get(it)) } - -public inline fun DoubleVector.mapIndexed(transform: (index: Int, value: Double) -> Double): DoubleVector = - double(size) { transform(it, get(it)) } - -public operator fun DoubleVector.plus(other: DoubleVector): DoubleVector { - require(size == other.size) { "Vector size $size expected but ${other.size} found" } - return mapIndexed { index, value -> value + other[index] } -} - -public operator fun DoubleVector.plus(number: Number): DoubleVector = map { it + number.toDouble() } - -public operator fun Number.plus(vector: DoubleVector): DoubleVector = vector + this - -public operator fun DoubleVector.unaryMinus(): Buffer = map { -it } - -public operator fun DoubleVector.minus(other: DoubleVector): DoubleVector { - require(size == other.size) { "Vector size $size expected but ${other.size} found" } - return mapIndexed { index, value -> value - other[index] } -} - -public operator fun DoubleVector.minus(number: Number): DoubleVector = map { it - number.toDouble() } - -public operator fun Number.minus(vector: DoubleVector): DoubleVector = vector.map { toDouble() - it } - -public operator fun DoubleVector.times(other: DoubleVector): DoubleVector { - require(size == other.size) { "Vector size $size expected but ${other.size} found" } - return mapIndexed { index, value -> value * other[index] } -} - -public operator fun DoubleVector.times(number: Number): DoubleVector = map { it * number.toDouble() } - -public operator fun Number.times(vector: DoubleVector): DoubleVector = vector * this - -public operator fun DoubleVector.div(other: DoubleVector): DoubleVector { - require(size == other.size) { "Vector size $size expected but ${other.size} found" } - return mapIndexed { index, value -> value / other[index] } -} - -public operator fun DoubleVector.div(number: Number): DoubleVector = map { it / number.toDouble() } - -public operator fun Number.div(vector: DoubleVector): DoubleVector = vector.map { toDouble() / it } - -//extended operations - -public fun DoubleVector.pow(p: Double): DoubleVector = map { it.pow(p) } - -public fun DoubleVector.pow(p: Int): DoubleVector = map { it.pow(p) } - -public fun exp(vector: DoubleVector): DoubleVector = vector.map { kotlin.math.exp(it) } - -public fun sqrt(vector: DoubleVector): DoubleVector = vector.map { kotlin.math.sqrt(it) } - -public fun DoubleVector.square(): DoubleVector = map { it.pow(2) } - -public fun sin(vector: DoubleVector): DoubleVector = vector.map { kotlin.math.sin(it) } - -public fun cos(vector: DoubleVector): DoubleVector = vector.map { kotlin.math.cos(it) } - -public fun tan(vector: DoubleVector): DoubleVector = vector.map { kotlin.math.tan(it) } - -public fun ln(vector: DoubleVector): DoubleVector = vector.map { kotlin.math.ln(it) } - -public fun log10(vector: DoubleVector): DoubleVector = vector.map { kotlin.math.log10(it) } - -// reductions methods - -public fun DoubleVector.sum(): Double { - var res = 0.0 - for (i in indices) { - res += get(i) - } - return res -} - -public object VectorL2Norm : Norm { - override fun norm(arg: DoubleVector): Double = sqrt(arg.fold(0.0) { acc: Double, d: Double -> acc + d.pow(2) }) -} - -public val DoubleVector.norm: Double get() = VectorL2Norm.norm(this) \ No newline at end of file diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt deleted file mode 100644 index f42a47a27..000000000 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/dot.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.real - -import space.kscience.kmath.linear.LinearSpace -import space.kscience.kmath.linear.Matrix - - -/** - * Optimized dot product for real matrices - */ -public infix fun Matrix.dot(other: Matrix): Matrix = LinearSpace.real.run { - this@dot dot other -} \ No newline at end of file diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt deleted file mode 100644 index fba999e6c..000000000 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/grids.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.real - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer -import kotlin.math.floor - -public val ClosedFloatingPointRange.length: Double get() = endInclusive - start - -/** - * Create a Buffer-based grid with equally distributed [numberOfPoints] points. The range could be increasing or decreasing. - * If range has a zero size, then the buffer consisting of [numberOfPoints] equal values is returned. - */ -public fun Buffer.Companion.fromRange(range: ClosedFloatingPointRange, numberOfPoints: Int): DoubleBuffer { - require(numberOfPoints >= 2) { "Number of points in grid must be more than 1" } - val normalizedRange = when { - range.endInclusive > range.start -> range - range.endInclusive < range.start -> range.endInclusive..range.start - else -> return DoubleBuffer(numberOfPoints) { range.start } - } - val step = normalizedRange.length / (numberOfPoints - 1) - return DoubleBuffer(numberOfPoints) { normalizedRange.start + step * it } -} - -/** - * Create a Buffer-based grid with equally distributed points with a fixed [step]. The range could be increasing or decreasing. - * If the step is larger than the range size, single point is returned. - */ -public fun Buffer.Companion.withFixedStep(range: ClosedFloatingPointRange, step: Double): DoubleBuffer { - require(step > 0) { "The grid step must be positive" } - val normalizedRange = when { - range.endInclusive > range.start -> range - range.endInclusive < range.start -> range.endInclusive..range.start - else -> return DoubleBuffer(range.start) - } - val numberOfPoints = floor(normalizedRange.length / step).toInt() + 1 - return DoubleBuffer(numberOfPoints) { normalizedRange.start + step * it } -} - -/** - * Convert double range to sequence. - * - * If the step is positive, then the sequence starts with the lower boundary and increments by [step] until current value is lower than upper boundary. - * The boundary itself is unnecessarily included. - * - * If step is negative, the same goes from upper boundary downwards - */ -@UnstableKMathAPI -public infix fun ClosedFloatingPointRange.step(step: Double): DoubleBuffer = Buffer.withFixedStep(this, step) \ No newline at end of file diff --git a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt b/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt deleted file mode 100644 index b2c3209c2..000000000 --- a/kmath-for-real/src/commonMain/kotlin/space/kscience/kmath/real/realND.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.real - -import space.kscience.kmath.nd.BufferND -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.structures.DoubleBuffer - -/** - * Map one [BufferND] using function without indices. - */ -public inline fun BufferND.mapInline(crossinline transform: DoubleField.(Double) -> Double): BufferND { - val array = DoubleArray(strides.linearSize) { offset -> DoubleField.transform(buffer[offset]) } - return BufferND(strides, DoubleBuffer(array)) -} - -/** - * Element by element application of any operation on elements to the whole array. Just like in numpy. - */ -public operator fun Function1.invoke(elementND: BufferND): BufferND = - elementND.mapInline { this@invoke(it) } - -/* plus and minus */ - -/** - * Summation operation for [BufferND] and single element - */ -public operator fun BufferND.plus(arg: Double): BufferND = mapInline { it + arg } - -/** - * Subtraction operation between [BufferND] and single element - */ -public operator fun BufferND.minus(arg: Double): BufferND = mapInline { it - arg } \ No newline at end of file diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt b/kmath-for-real/src/commonTest/kotlin/scientific.kmath.real/RealMatrixTest.kt similarity index 62% rename from kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt rename to kmath-for-real/src/commonTest/kotlin/scientific.kmath.real/RealMatrixTest.kt index 1400ed0b7..8918fb300 100644 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleMatrixTest.kt +++ b/kmath-for-real/src/commonTest/kotlin/scientific.kmath.real/RealMatrixTest.kt @@ -1,28 +1,14 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ +package scientific.kmath.real -package space.kscience.kmath.real - -import space.kscience.kmath.linear.LinearSpace -import space.kscience.kmath.linear.matrix -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.real.* -import space.kscience.kmath.structures.contentEquals +import scientifik.kmath.linear.VirtualMatrix +import scientifik.kmath.linear.build +import scientifik.kmath.real.* +import scientifik.kmath.structures.Matrix import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue -@OptIn(PerformancePitfall::class) -fun assertMatrixEquals(expected: StructureND, actual: StructureND) { - assertTrue { StructureND.contentEquals(expected, actual) } -} - -@UnstableKMathAPI -internal class DoubleMatrixTest { +class RealMatrixTest { @Test fun testSum() { val m = realMatrix(10, 10) { i, j -> (i + j).toDouble() } @@ -32,7 +18,7 @@ internal class DoubleMatrixTest { @Test fun testSequenceToMatrix() { - val m = Sequence { + val m = Sequence { listOf( DoubleArray(10) { 10.0 }, DoubleArray(10) { 20.0 }, @@ -43,11 +29,11 @@ internal class DoubleMatrixTest { @Test fun testRepeatStackVertical() { - val matrix1 = realMatrix(2, 3)( + val matrix1 = Matrix.build(2, 3)( 1.0, 0.0, 0.0, 0.0, 1.0, 2.0 ) - val matrix2 = realMatrix(6, 3)( + val matrix2 = Matrix.build(6, 3)( 1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0, 0.0, 0.0, @@ -55,94 +41,93 @@ internal class DoubleMatrixTest { 1.0, 0.0, 0.0, 0.0, 1.0, 2.0 ) - assertMatrixEquals(matrix2, matrix1.repeatStackVertical(3)) + assertEquals(VirtualMatrix.wrap(matrix2), matrix1.repeatStackVertical(3)) } @Test fun testMatrixAndDouble() { - val matrix1 = realMatrix(2, 3)( + val matrix1 = Matrix.build(2, 3)( 1.0, 0.0, 3.0, 4.0, 6.0, 2.0 ) val matrix2 = (matrix1 * 2.5 + 1.0 - 2.0) / 2.0 - val expectedResult = LinearSpace.real.matrix(2, 3)( + val expectedResult = Matrix.build(2, 3)( 0.75, -0.5, 3.25, 4.5, 7.0, 2.0 ) - assertMatrixEquals(matrix2, expectedResult) + assertEquals(matrix2, expectedResult) } @Test fun testDoubleAndMatrix() { - val matrix1 = realMatrix(2, 3)( + val matrix1 = Matrix.build(2, 3)( 1.0, 0.0, 3.0, 4.0, 6.0, 2.0 ) val matrix2 = 20.0 - (10.0 + (5.0 * matrix1)) //val matrix2 = 10.0 + (5.0 * matrix1) - val expectedResult = realMatrix(2, 3)( + val expectedResult = Matrix.build(2, 3)( 5.0, 10.0, -5.0, -10.0, -20.0, 0.0 ) - assertMatrixEquals(matrix2, expectedResult) + assertEquals(matrix2, expectedResult) } @Test fun testSquareAndPower() { - val matrix1 = realMatrix(2, 3)( + val matrix1 = Matrix.build(2, 3)( -1.0, 0.0, 3.0, 4.0, -6.0, -2.0 ) - val matrix2 = realMatrix(2, 3)( + val matrix2 = Matrix.build(2, 3)( 1.0, 0.0, 9.0, 16.0, 36.0, 4.0 ) - val matrix3 = realMatrix(2, 3)( + val matrix3 = Matrix.build(2, 3)( -1.0, 0.0, 27.0, 64.0, -216.0, -8.0 ) - assertMatrixEquals(matrix1.square(), matrix2) - assertMatrixEquals(matrix1.pow(3), matrix3) + assertEquals(matrix1.square(), matrix2) + assertEquals(matrix1.pow(3), matrix3) } - @OptIn(UnstableKMathAPI::class) @Test fun testTwoMatrixOperations() { - val matrix1 = realMatrix(2, 3)( + val matrix1 = Matrix.build(2, 3)( -1.0, 0.0, 3.0, 4.0, -6.0, 7.0 ) - val matrix2 = realMatrix(2, 3)( + val matrix2 = Matrix.build(2, 3)( 1.0, 0.0, 3.0, 4.0, 6.0, -2.0 ) val result = matrix1 * matrix2 + matrix1 - matrix2 - val expectedResult = realMatrix(2, 3)( + val expectedResult = Matrix.build(2, 3)( -3.0, 0.0, 9.0, 16.0, -48.0, -5.0 ) - assertMatrixEquals(result, expectedResult) + assertEquals(result, expectedResult) } @Test fun testColumnOperations() { - val matrix1 = realMatrix(2, 4)( + val matrix1 = Matrix.build(2, 4)( -1.0, 0.0, 3.0, 15.0, 4.0, -6.0, 7.0, -11.0 ) - val matrix2 = realMatrix(2, 5)( + val matrix2 = Matrix.build(2, 5)( -1.0, 0.0, 3.0, 15.0, -1.0, 4.0, -6.0, 7.0, -11.0, 4.0 ) - val col1 = realMatrix(2, 1)(0.0, -6.0) - val cols1to2 = realMatrix(2, 2)( + val col1 = Matrix.build(2, 1)(0.0, -6.0) + val cols1to2 = Matrix.build(2, 2)( 0.0, 3.0, -6.0, 7.0 ) - assertMatrixEquals(matrix1.appendColumn { it[0] }, matrix2) - assertMatrixEquals(matrix1.extractColumn(1), col1) - assertMatrixEquals(matrix1.extractColumns(1..2), cols1to2) + assertEquals(matrix1.appendColumn { it[0] }, matrix2) + assertEquals(matrix1.extractColumn(1), col1) + assertEquals(matrix1.extractColumns(1..2), cols1to2) //equals should never be called on buffers assertTrue { matrix1.sumByColumn().contentEquals(3.0, -6.0, 10.0, 4.0) @@ -160,7 +145,7 @@ internal class DoubleMatrixTest { @Test fun testAllElementOperations() { - val matrix1 = LinearSpace.real.matrix(2, 4)( + val matrix1 = Matrix.build(2, 4)( -1.0, 0.0, 3.0, 15.0, 4.0, -6.0, 7.0, -11.0 ) diff --git a/kmath-for-real/src/commonTest/kotlin/scientifik/kmath/linear/VectorTest.kt b/kmath-for-real/src/commonTest/kotlin/scientifik/kmath/linear/VectorTest.kt new file mode 100644 index 000000000..28e62b066 --- /dev/null +++ b/kmath-for-real/src/commonTest/kotlin/scientifik/kmath/linear/VectorTest.kt @@ -0,0 +1,37 @@ +package scientifik.kmath.linear + +import scientifik.kmath.real.RealVector +import kotlin.test.Test +import kotlin.test.assertEquals + +class VectorTest { + @Test + fun testSum() { + val vector1 = RealVector(5) { it.toDouble() } + val vector2 = RealVector(5) { 5 - it.toDouble() } + val sum = vector1 + vector2 + assertEquals(5.0, sum[2]) + } + + @Test + fun testVectorToMatrix() { + val vector = RealVector(5) { it.toDouble() } + val matrix = vector.asMatrix() + assertEquals(4.0, matrix[4, 0]) + } + + @Test + fun testDot() { + val vector1 = RealVector(5) { it.toDouble() } + val vector2 = RealVector(5) { 5 - it.toDouble() } + + val matrix1 = vector1.asMatrix() + val matrix2 = vector2.asMatrix().transpose() + val product = MatrixContext.real.run { matrix1 dot matrix2 } + + + assertEquals(5.0, product[1, 0]) + assertEquals(6.0, product[2, 2]) + } + +} \ No newline at end of file diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt deleted file mode 100644 index 9a254a0b0..000000000 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/DoubleVectorTest.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.real - -import space.kscience.kmath.linear.LinearSpace -import space.kscience.kmath.linear.asMatrix -import space.kscience.kmath.linear.transpose -import space.kscience.kmath.real.plus -import space.kscience.kmath.structures.DoubleBuffer -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class DoubleVectorTest { - @Test - fun testSum() { - val vector1 = DoubleBuffer(5) { it.toDouble() } - val vector2 = DoubleBuffer(5) { 5 - it.toDouble() } - val sum = vector1 + vector2 - assertEquals(5.0, sum[2]) - } - - @Test - fun testVectorToMatrix() { - val vector = DoubleBuffer(5) { it.toDouble() } - val matrix = vector.asMatrix() - assertEquals(4.0, matrix[4, 0]) - } - - @Test - fun testDot() { - val vector1 = DoubleBuffer(5) { it.toDouble() } - val vector2 = DoubleBuffer(5) { 5 - it.toDouble() } - val matrix1 = vector1.asMatrix() - val matrix2 = vector2.asMatrix().transpose() - val product = LinearSpace.real.run { matrix1 dot matrix2 } - assertEquals(5.0, product[1, 0]) - assertEquals(6.0, product[2, 2]) - } -} diff --git a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt b/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt deleted file mode 100644 index ec1ed8f50..000000000 --- a/kmath-for-real/src/commonTest/kotlin/space/kscience/kmath/real/GridTest.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.real - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.real.DoubleVector -import space.kscience.kmath.real.minus -import space.kscience.kmath.real.norm -import space.kscience.kmath.real.step -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -@UnstableKMathAPI -class GridTest { - @Test - fun testStepGrid() { - val grid = 0.0..1.0 step 0.2 - assertEquals(6, grid.size) - assertTrue { (grid - DoubleVector(0.0, 0.2, 0.4, 0.6, 0.8, 1.0)).norm < 1e-4 } - } - - @Test - fun testIterateGrid(){ - var res = 0.0 - for(d in 0.0..1.0 step 0.2){ - res = d - } - assertEquals(1.0, res) - } -} \ No newline at end of file diff --git a/kmath-functions/README.md b/kmath-functions/README.md deleted file mode 100644 index d0beae2c8..000000000 --- a/kmath-functions/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# Module kmath-functions - -Functions and interpolations. - - - [piecewise](src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt) : Piecewise functions. - - [polynomials](src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt) : Polynomial functions. - - [linear interpolation](src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt) : Linear XY interpolator. - - [spline interpolation](src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt) : Cubic spline XY interpolator. - - [integration](#) : Univariate and multivariate quadratures - - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-functions:0.3.0-dev-14`. - -**Gradle:** -```gradle -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-functions:0.3.0-dev-14' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - 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 fadbac091..4c158a32e 100644 --- a/kmath-functions/build.gradle.kts +++ b/kmath-functions/build.gradle.kts @@ -1,34 +1,11 @@ plugins { - kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("scientifik.mpp") } -description = "Functions, integration and interpolation" - -kotlin.sourceSets.commonMain { - dependencies { - api(project(":kmath-core")) - } -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL - propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) - - feature("piecewise", "src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt") { - "Piecewise functions." - } - feature("polynomials", "src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt") { - "Polynomial functions." - } - feature("linear interpolation", "src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt") { - "Linear XY interpolator." - } - feature("spline interpolation", "src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt") { - "Cubic spline XY interpolator." - } - feature("integration") { - "Univariate and multivariate quadratures" +kotlin.sourceSets { + commonMain { + dependencies { + api(project(":kmath-core")) + } } } diff --git a/kmath-functions/docs/README-TEMPLATE.md b/kmath-functions/docs/README-TEMPLATE.md deleted file mode 100644 index 2e163eee5..000000000 --- a/kmath-functions/docs/README-TEMPLATE.md +++ /dev/null @@ -1,7 +0,0 @@ -# Module kmath-functions - -Functions and interpolations. - -${features} - -${artifact} diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Piecewise.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Piecewise.kt new file mode 100644 index 000000000..16f8aa12b --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Piecewise.kt @@ -0,0 +1,57 @@ +package scientifik.kmath.functions + +import scientifik.kmath.operations.Ring + +interface Piecewise { + fun findPiece(arg: T): R? +} + +interface PiecewisePolynomial : + Piecewise> + +/** + * Ordered list of pieces in piecewise function + */ +class OrderedPiecewisePolynomial>(delimeter: T) : + PiecewisePolynomial { + + private val delimiters: ArrayList = arrayListOf(delimeter) + private val pieces: ArrayList> = ArrayList() + + /** + * Dynamically add 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, a error is thrown. + */ + fun putRight(right: T, piece: Polynomial) { + require(right > delimiters.last()) { "New delimiter should be to the right of old one" } + delimiters.add(right) + pieces.add(piece) + } + + fun putLeft(left: T, piece: Polynomial) { + require(left < delimiters.first()) { "New delimiter should be to the left of old one" } + delimiters.add(0, left) + pieces.add(0, piece) + } + + override fun findPiece(arg: T): Polynomial? { + if (arg < delimiters.first() || arg >= delimiters.last()) { + return null + } else { + for (index in 1 until delimiters.size) { + if (arg < delimiters[index]) { + return pieces[index - 1] + } + } + error("Piece not found") + } + } +} + +/** + * Return a value of polynomial function with given [ring] an given [arg] or null if argument is outside of piecewise definition. + */ +fun , C : Ring> PiecewisePolynomial.value(ring: C, arg: T): T? = + findPiece(arg)?.value(ring, arg) + +fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { value(ring, it) } \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Polynomial.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Polynomial.kt new file mode 100644 index 000000000..b747b521d --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/Polynomial.kt @@ -0,0 +1,73 @@ +package scientifik.kmath.functions + +import scientifik.kmath.operations.Ring +import scientifik.kmath.operations.Space +import kotlin.math.max +import kotlin.math.pow + +/** + * Polynomial coefficients without fixation on specific context they are applied to + * @param coefficients constant is the leftmost coefficient + */ +inline class Polynomial(val coefficients: List) { + constructor(vararg coefficients: T) : this(coefficients.toList()) +} + +fun Polynomial.value() = + coefficients.reduceIndexed { index: Int, acc: Double, d: Double -> acc + d.pow(index) } + + +fun > Polynomial.value(ring: C, arg: T): T = ring.run { + if (coefficients.isEmpty()) return@run zero + var res = coefficients.first() + var powerArg = arg + for (index in 1 until coefficients.size) { + res += coefficients[index] * powerArg + //recalculating power on each step to avoid power costs on long polynomials + powerArg *= arg + } + return@run res +} + +/** + * Represent a polynomial as a context-dependent function + */ +fun > Polynomial.asMathFunction(): MathFunction = object : + MathFunction { + override fun C.invoke(arg: T): T = value(this, arg) +} + +/** + * Represent the polynomial as a regular context-less function + */ +fun > Polynomial.asFunction(ring: C): (T) -> T = { value(ring, it) } + +/** + * An algebra for polynomials + */ +class PolynomialSpace>(val ring: C) : Space> { + + override fun add(a: Polynomial, b: Polynomial): Polynomial { + val dim = max(a.coefficients.size, b.coefficients.size) + ring.run { + return Polynomial(List(dim) { index -> + a.coefficients.getOrElse(index) { zero } + b.coefficients.getOrElse(index) { zero } + }) + } + } + + override fun multiply(a: Polynomial, k: Number): Polynomial { + ring.run { + return Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * k }) + } + } + + override val zero: Polynomial = + Polynomial(emptyList()) + + operator fun Polynomial.invoke(arg: T): T = value(ring, arg) +} + +fun , R> C.polynomial(block: PolynomialSpace.() -> R): R { + return PolynomialSpace(this).run(block) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/functions.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/functions.kt new file mode 100644 index 000000000..2b822b3ba --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/functions/functions.kt @@ -0,0 +1,33 @@ +package scientifik.kmath.functions + +import scientifik.kmath.operations.Algebra +import scientifik.kmath.operations.RealField + +/** + * A regular function that could be called only inside specific algebra context + * @param T source type + * @param C source algebra constraint + * @param R result type + */ +interface MathFunction, R> { + operator fun C.invoke(arg: T): R +} + +fun MathFunction.invoke(arg: Double): R = RealField.invoke(arg) + +/** + * A suspendable function defined in algebraic context + */ +interface SuspendableMathFunction, R> { + suspend operator fun C.invoke(arg: T): R +} + +suspend fun SuspendableMathFunction.invoke(arg: Double) = RealField.invoke(arg) + + +/** + * A parametric function with parameter + */ +interface ParametricFunction> { + operator fun C.invoke(arg: T, parameter: P): T +} diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/Interpolator.kt new file mode 100644 index 000000000..8d83e4198 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/Interpolator.kt @@ -0,0 +1,45 @@ +package scientifik.kmath.interpolation + +import scientifik.kmath.functions.PiecewisePolynomial +import scientifik.kmath.functions.value +import scientifik.kmath.operations.Ring +import scientifik.kmath.structures.Buffer +import scientifik.kmath.structures.asBuffer + +interface Interpolator { + fun interpolate(points: XYPointSet): (X) -> Y +} + +interface PolynomialInterpolator> : Interpolator { + val algebra: Ring + + fun getDefaultValue(): T = error("Out of bounds") + + fun interpolatePolynomials(points: XYPointSet): PiecewisePolynomial + + override fun interpolate(points: XYPointSet): (T) -> T = { x -> + interpolatePolynomials(points).value(algebra, x) ?: getDefaultValue() + } +} + +fun > PolynomialInterpolator.interpolatePolynomials( + x: Buffer, + y: Buffer +): PiecewisePolynomial { + val pointSet = BufferXYPointSet(x, y) + return interpolatePolynomials(pointSet) +} + +fun > PolynomialInterpolator.interpolatePolynomials( + data: Map +): PiecewisePolynomial { + val pointSet = BufferXYPointSet(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) + return interpolatePolynomials(pointSet) +} + +fun > PolynomialInterpolator.interpolatePolynomials( + data: List> +): PiecewisePolynomial { + val pointSet = BufferXYPointSet(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) + return interpolatePolynomials(pointSet) +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LinearInterpolator.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LinearInterpolator.kt new file mode 100644 index 000000000..98beb4391 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LinearInterpolator.kt @@ -0,0 +1,26 @@ +package scientifik.kmath.interpolation + +import scientifik.kmath.functions.OrderedPiecewisePolynomial +import scientifik.kmath.functions.PiecewisePolynomial +import scientifik.kmath.functions.Polynomial +import scientifik.kmath.operations.Field + +/** + * Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java + */ +class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { + + override fun interpolatePolynomials(points: XYPointSet): PiecewisePolynomial = algebra.run { + require(points.size > 0) { "Point array should not be empty" } + insureSorted(points) + + OrderedPiecewisePolynomial(points.x[0]).apply { + for (i in 0 until points.size - 1) { + val slope = (points.y[i + 1] - points.y[i]) / (points.x[i + 1] - points.x[i]) + val const = points.y[i] - slope * points.x[i] + val polynomial = Polynomial(const, slope) + putRight(points.x[i + 1], polynomial) + } + } + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LoessInterpolator.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LoessInterpolator.kt new file mode 100644 index 000000000..6707bd8bc --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/LoessInterpolator.kt @@ -0,0 +1,296 @@ +package scientifik.kmath.interpolation +// +//import scientifik.kmath.functions.PiecewisePolynomial +//import scientifik.kmath.operations.Ring +//import scientifik.kmath.structures.Buffer +//import kotlin.math.abs +//import kotlin.math.sqrt +// +// +///** +// * Original code: https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/LoessInterpolator.java +// */ +//class LoessInterpolator>(override val algebra: Ring) : PolynomialInterpolator { +// /** +// * The bandwidth parameter: when computing the loess fit at +// * a particular point, this fraction of source points closest +// * to the current point is taken into account for computing +// * a least-squares regression. +// * +// * +// * A sensible value is usually 0.25 to 0.5. +// */ +// private var bandwidth = 0.0 +// +// /** +// * The number of robustness iterations parameter: this many +// * robustness iterations are done. +// * +// * +// * A sensible value is usually 0 (just the initial fit without any +// * robustness iterations) to 4. +// */ +// private var robustnessIters = 0 +// +// /** +// * If the median residual at a certain robustness iteration +// * is less than this amount, no more iterations are done. +// */ +// private var accuracy = 0.0 +// +// /** +// * Constructs a new [LoessInterpolator] +// * with a bandwidth of [.DEFAULT_BANDWIDTH], +// * [.DEFAULT_ROBUSTNESS_ITERS] robustness iterations +// * and an accuracy of {#link #DEFAULT_ACCURACY}. +// * See [.LoessInterpolator] for an explanation of +// * the parameters. +// */ +// fun LoessInterpolator() { +// bandwidth = DEFAULT_BANDWIDTH +// robustnessIters = DEFAULT_ROBUSTNESS_ITERS +// accuracy = DEFAULT_ACCURACY +// } +// +// fun LoessInterpolator(bandwidth: Double, robustnessIters: Int) { +// this(bandwidth, robustnessIters, DEFAULT_ACCURACY) +// } +// +// fun LoessInterpolator(bandwidth: Double, robustnessIters: Int, accuracy: Double) { +// if (bandwidth < 0 || +// bandwidth > 1 +// ) { +// throw OutOfRangeException(LocalizedFormats.BANDWIDTH, bandwidth, 0, 1) +// } +// this.bandwidth = bandwidth +// if (robustnessIters < 0) { +// throw NotPositiveException(LocalizedFormats.ROBUSTNESS_ITERATIONS, robustnessIters) +// } +// this.robustnessIters = robustnessIters +// this.accuracy = accuracy +// } +// +// fun interpolate( +// xval: DoubleArray, +// yval: DoubleArray +// ): PolynomialSplineFunction { +// return SplineInterpolator().interpolate(xval, smooth(xval, yval)) +// } +// +// fun XYZPointSet.smooth(): XYPointSet { +// checkAllFiniteReal(x) +// checkAllFiniteReal(y) +// checkAllFiniteReal(z) +// MathArrays.checkOrder(xval) +// if (size == 1) { +// return doubleArrayOf(y[0]) +// } +// if (size == 2) { +// return doubleArrayOf(y[0], y[1]) +// } +// val bandwidthInPoints = (bandwidth * size).toInt() +// if (bandwidthInPoints < 2) { +// throw NumberIsTooSmallException( +// LocalizedFormats.BANDWIDTH, +// bandwidthInPoints, 2, true +// ) +// } +// val res = DoubleArray(size) +// val residuals = DoubleArray(size) +// val sortedResiduals = DoubleArray(size) +// val robustnessWeights = DoubleArray(size) +// // Do an initial fit and 'robustnessIters' robustness iterations. +// // This is equivalent to doing 'robustnessIters+1' robustness iterations +// // starting with all robustness weights set to 1. +// Arrays.fill(robustnessWeights, 1.0) +// for (iter in 0..robustnessIters) { +// val bandwidthInterval = intArrayOf(0, bandwidthInPoints - 1) +// // At each x, compute a local weighted linear regression +// for (i in 0 until size) { +//// val x = x[i] +// // Find out the interval of source points on which +// // a regression is to be made. +// if (i > 0) { +// updateBandwidthInterval(x, z, i, bandwidthInterval) +// } +// val ileft = bandwidthInterval[0] +// val iright = bandwidthInterval[1] +// // Compute the point of the bandwidth interval that is +// // farthest from x +// val edge: Int +// edge = if (x[i] - x[ileft] > x[iright] - x[i]) { +// ileft +// } else { +// iright +// } +// // Compute a least-squares linear fit weighted by +// // the product of robustness weights and the tricube +// // weight function. +// // See http://en.wikipedia.org/wiki/Linear_regression +// // (section "Univariate linear case") +// // and http://en.wikipedia.org/wiki/Weighted_least_squares +// // (section "Weighted least squares") +// var sumWeights = 0.0 +// var sumX = 0.0 +// var sumXSquared = 0.0 +// var sumY = 0.0 +// var sumXY = 0.0 +// val denom: Double = abs(1.0 / (x[edge] - x[i])) +// for (k in ileft..iright) { +// val xk = x[k] +// val yk = y[k] +// val dist = if (k < i) x - xk else xk - x[i] +// val w = tricube(dist * denom) * robustnessWeights[k] * z[k] +// val xkw = xk * w +// sumWeights += w +// sumX += xkw +// sumXSquared += xk * xkw +// sumY += yk * w +// sumXY += yk * xkw +// } +// val meanX = sumX / sumWeights +// val meanY = sumY / sumWeights +// val meanXY = sumXY / sumWeights +// val meanXSquared = sumXSquared / sumWeights +// val beta: Double +// beta = if (sqrt(abs(meanXSquared - meanX * meanX)) < accuracy) { +// 0.0 +// } else { +// (meanXY - meanX * meanY) / (meanXSquared - meanX * meanX) +// } +// val alpha = meanY - beta * meanX +// res[i] = beta * x[i] + alpha +// residuals[i] = abs(y[i] - res[i]) +// } +// // No need to recompute the robustness weights at the last +// // iteration, they won't be needed anymore +// if (iter == robustnessIters) { +// break +// } +// // Recompute the robustness weights. +// // Find the median residual. +// // An arraycopy and a sort are completely tractable here, +// // because the preceding loop is a lot more expensive +// java.lang.System.arraycopy(residuals, 0, sortedResiduals, 0, size) +// Arrays.sort(sortedResiduals) +// val medianResidual = sortedResiduals[size / 2] +// if (abs(medianResidual) < accuracy) { +// break +// } +// for (i in 0 until size) { +// val arg = residuals[i] / (6 * medianResidual) +// if (arg >= 1) { +// robustnessWeights[i] = 0.0 +// } else { +// val w = 1 - arg * arg +// robustnessWeights[i] = w * w +// } +// } +// } +// return res +// } +// +// fun smooth(xval: DoubleArray, yval: DoubleArray): DoubleArray { +// if (xval.size != yval.size) { +// throw DimensionMismatchException(xval.size, yval.size) +// } +// val unitWeights = DoubleArray(xval.size) +// Arrays.fill(unitWeights, 1.0) +// return smooth(xval, yval, unitWeights) +// } +// +// /** +// * Given an index interval into xval that embraces a certain number of +// * points closest to `xval[i-1]`, update the interval so that it +// * embraces the same number of points closest to `xval[i]`, +// * ignoring zero weights. +// * +// * @param xval Arguments array. +// * @param weights Weights array. +// * @param i Index around which the new interval should be computed. +// * @param bandwidthInterval a two-element array {left, right} such that: +// * `(left==0 or xval[i] - xval[left-1] > xval[right] - xval[i])` +// * and +// * `(right==xval.length-1 or xval[right+1] - xval[i] > xval[i] - xval[left])`. +// * The array will be updated. +// */ +// private fun updateBandwidthInterval( +// xval: Buffer, weights: Buffer, +// i: Int, +// bandwidthInterval: IntArray +// ) { +// val left = bandwidthInterval[0] +// val right = bandwidthInterval[1] +// // The right edge should be adjusted if the next point to the right +// // is closer to xval[i] than the leftmost point of the current interval +// val nextRight = nextNonzero(weights, right) +// if (nextRight < xval.size && xval[nextRight] - xval[i] < xval[i] - xval[left]) { +// val nextLeft = nextNonzero(weights, bandwidthInterval[0]) +// bandwidthInterval[0] = nextLeft +// bandwidthInterval[1] = nextRight +// } +// } +// +// /** +// * Return the smallest index `j` such that +// * `j > i && (j == weights.length || weights[j] != 0)`. +// * +// * @param weights Weights array. +// * @param i Index from which to start search. +// * @return the smallest compliant index. +// */ +// private fun nextNonzero(weights: Buffer, i: Int): Int { +// var j = i + 1 +// while (j < weights.size && weights[j] == 0.0) { +// ++j +// } +// return j +// } +// +// /** +// * Compute the +// * [tricube](http://en.wikipedia.org/wiki/Local_regression#Weight_function) +// * weight function +// * +// * @param x Argument. +// * @return `(1 - |x|3)3` for |x| < 1, 0 otherwise. +// */ +// private fun tricube(x: Double): Double { +// val absX: Double = FastMath.abs(x) +// if (absX >= 1.0) { +// return 0.0 +// } +// val tmp = 1 - absX * absX * absX +// return tmp * tmp * tmp +// } +// +// /** +// * Check that all elements of an array are finite real numbers. +// * +// * @param values Values array. +// * @throws org.apache.commons.math4.exception.NotFiniteNumberException +// * if one of the values is not a finite real number. +// */ +// private fun checkAllFiniteReal(values: DoubleArray) { +// for (i in values.indices) { +// MathUtils.checkFinite(values[i]) +// } +// } +// +// override fun interpolatePolynomials(points: Collection>): PiecewisePolynomial { +// TODO("not implemented") //To change body of created functions use File | Settings | File Templates. +// } +// +// companion object { +// /** Default value of the bandwidth parameter. */ +// const val DEFAULT_BANDWIDTH = 0.3 +// +// /** Default value of the number of robustness iterations. */ +// const val DEFAULT_ROBUSTNESS_ITERS = 2 +// +// /** +// * Default value for accuracy. +// */ +// const val DEFAULT_ACCURACY = 1e-12 +// } +//} \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/SplineInterpolator.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/SplineInterpolator.kt new file mode 100644 index 000000000..e1af0c1a2 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/SplineInterpolator.kt @@ -0,0 +1,58 @@ +package scientifik.kmath.interpolation + +import scientifik.kmath.functions.OrderedPiecewisePolynomial +import scientifik.kmath.functions.PiecewisePolynomial +import scientifik.kmath.functions.Polynomial +import scientifik.kmath.operations.Field +import scientifik.kmath.structures.MutableBufferFactory + +/** + * Generic spline interpolator. Not recommended for performance critical places, use platform-specific and type specific ones. + * Based on https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java + */ +class SplineInterpolator>( + override val algebra: Field, + val bufferFactory: MutableBufferFactory +) : PolynomialInterpolator { + + //TODO possibly optimize zeroed buffers + + override fun interpolatePolynomials(points: XYPointSet): PiecewisePolynomial = algebra.run { + if (points.size < 3) { + error("Can't use spline interpolator with less than 3 points") + } + insureSorted(points) + + // Number of intervals. The number of data points is n + 1. + val n = points.size - 1 + // Differences between knot points + val h = bufferFactory(points.size) { i -> points.x[i + 1] - points.x[i] } + val mu = bufferFactory(points.size - 1) { zero } + val z = bufferFactory(points.size) { zero } + + for (i in 1 until n) { + val g = 2.0 * (points.x[i + 1] - points.x[i - 1]) - h[i - 1] * mu[i - 1] + mu[i] = h[i] / g + z[i] = + (3.0 * (points.y[i + 1] * h[i - 1] - points.x[i] * (points.x[i + 1] - points.x[i - 1]) + points.y[i - 1] * h[i]) / (h[i - 1] * h[i]) + - h[i - 1] * z[i - 1]) / g + } + + // cubic spline coefficients -- b is linear, c quadratic, d is cubic (original y's are constants) + + OrderedPiecewisePolynomial(points.x[points.size - 1]).apply { + var cOld = zero + for (j in n - 1 downTo 0) { + val c = z[j] - mu[j] * cOld + val a = points.y[j] + val b = (points.y[j + 1] - points.y[j]) / h[j] - h[j] * (cOld + 2.0 * c) / 3.0 + val d = (cOld - c) / (3.0 * h[j]) + val polynomial = Polynomial(a, b, c, d) + cOld = c + putLeft(points.x[j], polynomial) + } + } + + } + +} diff --git a/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/XYPointSet.kt b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/XYPointSet.kt new file mode 100644 index 000000000..d8e10b880 --- /dev/null +++ b/kmath-functions/src/commonMain/kotlin/scientifik/kmath/interpolation/XYPointSet.kt @@ -0,0 +1,54 @@ +package scientifik.kmath.interpolation + +import scientifik.kmath.structures.Buffer +import scientifik.kmath.structures.Structure2D + +interface XYPointSet { + val size: Int + val x: Buffer + val y: Buffer +} + +interface XYZPointSet : XYPointSet { + val z: Buffer +} + +internal fun > insureSorted(points: XYPointSet) { + for (i in 0 until points.size - 1) { + if (points.x[i + 1] <= points.x[i]) error("Input data is not sorted at index $i") + } +} + +class NDStructureColumn(val structure: Structure2D, val column: Int) : Buffer { + init { + require(column < structure.colNum) { "Column index is outside of structure column range" } + } + + override val size: Int get() = structure.rowNum + + override fun get(index: Int): T = structure[index, column] + + override fun iterator(): Iterator = sequence { + repeat(size) { + yield(get(it)) + } + }.iterator() +} + +class BufferXYPointSet(override val x: Buffer, override val y: Buffer) : XYPointSet { + init { + require(x.size == y.size) { "Sizes of x and y buffers should be the same" } + } + + override val size: Int + get() = x.size +} + +fun Structure2D.asXYPointSet(): XYPointSet { + require(shape[1] == 2) { "Structure second dimension should be of size 2" } + return object : XYPointSet { + override val size: Int get() = this@asXYPointSet.shape[0] + override val x: Buffer get() = NDStructureColumn(this@asXYPointSet, 0) + override val y: Buffer get() = NDStructureColumn(this@asXYPointSet, 1) + } +} \ 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 deleted file mode 100644 index 4225a7572..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Piecewise.kt +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.operations.Ring - -/** - * Represents piecewise-defined function. - * - * @param T the piece key type. - * @param R the sub-function type. - */ -public fun interface Piecewise { - /** - * Returns the appropriate sub-function for given piece key. - */ - public fun findPiece(arg: T): R? -} - -/** - * Represents piecewise-defined function where all the sub-functions are polynomials. - * - * @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>> - - override fun findPiece(arg: T): Polynomial? -} - -/** - * A generic piecewise without constraints on how pieces are placed - */ -@PerformancePitfall("findPiece method of resulting piecewise is slow") -public fun > PiecewisePolynomial( - pieces: Collection, Polynomial>>, -): PiecewisePolynomial = object : PiecewisePolynomial { - override val pieces: Collection, Polynomial>> = pieces - - override fun findPiece(arg: T): Polynomial? = pieces.firstOrNull { arg in it.first }?.second -} - -/** - * 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>>, -) : PiecewisePolynomial { - - override fun findPiece(arg: T): Polynomial? { - val index = pieces.binarySearch { (range, _) -> - when { - arg >= range.endInclusive -> -1 - arg < range.start -> +1 - else -> 0 - } - } - return if (index < 0) null else pieces[index].second - } - -} - -/** - * A [Piecewise] builder where all the pieces are ordered by the [Comparable] type instances. - * - * @param T the comparable piece key type. - * @param delimiter the initial piecewise separator - */ -public class PiecewiseBuilder>(delimiter: T) { - private val delimiters: MutableList = arrayListOf(delimiter) - private val pieces: MutableList> = arrayListOf() - - /** - * Dynamically adds a piece to the right side (beyond maximum argument value of previous piece) - * - * @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) { - require(right > delimiters.last()) { "New delimiter should be to the right of old one" } - delimiters += right - pieces += piece - } - - /** - * Dynamically adds a piece to the left side (beyond maximum argument value of previous piece) - * - * @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) { - require(left < delimiters.first()) { "New delimiter should be to the left of old one" } - delimiters.add(0, left) - pieces.add(0, piece) - } - - public fun build(): PiecewisePolynomial = OrderedPiecewisePolynomial(delimiters.zipWithNext { l, r -> - l..r - }.zip(pieces)) -} - -/** - * A builder for [PiecewisePolynomial] - */ -public fun > PiecewisePolynomial( - startingPoint: T, - builder: PiecewiseBuilder.() -> Unit, -): PiecewisePolynomial = PiecewiseBuilder(startingPoint).apply(builder).build() - -/** - * 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? = - findPiece(arg)?.value(ring, arg) - -/** - * Convert this polynomial to a function returning nullable value (null if argument is outside piecewise range). - */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C): (T) -> T? = { value(ring, it) } - -/** - * Convert this polynomial to a function using [defaultValue] for arguments outside the piecewise range. - */ -public fun , C : Ring> PiecewisePolynomial.asFunction(ring: C, defaultValue: T): (T) -> T = - { value(ring, it) ?: defaultValue } 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 deleted file mode 100644 index 54b285a70..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/Polynomial.kt +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.math.max -import kotlin.math.pow - -/** - * Polynomial coefficients model without fixation on specific context they are applied to. - * - * @param coefficients constant is the leftmost coefficient. - */ -public class Polynomial(public val coefficients: List) { - override fun toString(): String = "Polynomial$coefficients" -} - -/** - * Returns a [Polynomial] instance with given [coefficients]. - */ -@Suppress("FunctionName") -public fun Polynomial(vararg coefficients: T): Polynomial = Polynomial(coefficients.toList()) - -/** - * Evaluates the value of the given double polynomial for given double argument. - */ -public fun Polynomial.value(arg: Double): Double = coefficients.reduceIndexed { index, acc, c -> - acc + c * arg.pow(index) -} - -/** - * Evaluates the value of the given polynomial for given argument. - * https://en.wikipedia.org/wiki/Horner%27s_method - */ -public fun > Polynomial.value(ring: C, arg: T): T = ring { - if (coefficients.isEmpty()) return@ring zero - var result: T = coefficients.last() - for (j in coefficients.size - 2 downTo 0) { - result = (arg * result) + coefficients[j] - } - return result -} - -/** - * Represent the polynomial as a regular context-less function. - */ -public fun > Polynomial.asFunction(ring: C): (T) -> T = { value(ring, it) } - -/** - * Create a polynomial witch represents differentiated version of this polynomial - */ -@UnstableKMathAPI -public fun Polynomial.differentiate( - algebra: A, -): Polynomial where A : Ring, A : NumericAlgebra = algebra { - Polynomial(coefficients.drop(1).mapIndexed { index, t -> number(index) * t }) -} - -/** - * Create a polynomial witch represents indefinite integral version of this polynomial - */ -@UnstableKMathAPI -public fun Polynomial.integrate( - algebra: A, -): Polynomial where A : Field, A : NumericAlgebra = algebra { - val integratedCoefficients = buildList(coefficients.size + 1) { - add(zero) - coefficients.forEachIndexed{ index, t -> add(t / (number(index) + one)) } - } - Polynomial(integratedCoefficients) -} - -/** - * Compute a definite integral of a given polynomial in a [range] - */ -@UnstableKMathAPI -public fun > Polynomial.integrate( - algebra: Field, - range: ClosedRange, -): T = algebra { - val integral = integrate(algebra) - integral.value(algebra, range.endInclusive) - integral.value(algebra, range.start) -} - -/** - * Space of polynomials. - * - * @param T the type of operated polynomials. - * @param C the intersection of [Ring] of [T] and [ScaleOperations] of [T]. - * @param ring the [C] instance. - */ -public class PolynomialSpace( - private val ring: C, -) : Group>, ScaleOperations> where C : Ring, C : ScaleOperations { - override val zero: Polynomial = Polynomial(emptyList()) - - override fun Polynomial.unaryMinus(): Polynomial = ring { - Polynomial(coefficients.map { -it }) - } - - override fun add(a: Polynomial, b: Polynomial): Polynomial { - val dim = max(a.coefficients.size, b.coefficients.size) - - return ring { - Polynomial(List(dim) { index -> - a.coefficients.getOrElse(index) { zero } + b.coefficients.getOrElse(index) { zero } - }) - } - } - - override fun scale(a: Polynomial, value: Double): Polynomial = - ring { Polynomial(List(a.coefficients.size) { index -> a.coefficients[index] * value }) } - - /** - * Evaluates the polynomial for the given value [arg]. - */ - public operator fun Polynomial.invoke(arg: T): T = value(ring, arg) - - public fun Polynomial.asFunction(): (T) -> T = asFunction(ring) - -} - -public inline fun C.polynomial(block: PolynomialSpace.() -> R): R where C : Ring, C : ScaleOperations { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - return PolynomialSpace(this).block() -} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt deleted file mode 100644 index 52b7e50db..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/functions/functionTypes.kt +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.functions - -import space.kscience.kmath.structures.Buffer - -public typealias UnivariateFunction = (T) -> T - -public typealias MultivariateFunction = (Buffer) -> T \ No newline at end of file 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 deleted file mode 100644 index dc3f41861..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegrator.kt +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ -package space.kscience.kmath.integration - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -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]. - */ -public class GaussIntegrator( - public val algebra: Field, -) : UnivariateIntegrator { - - private fun buildRule(integrand: UnivariateIntegrand): Pair, Buffer> { - val factory = integrand.getFeature() ?: GaussLegendreRuleFactory - val predefinedRanges = integrand.getFeature() - if (predefinedRanges == null || predefinedRanges.ranges.isEmpty()) { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - val range = integrand.getFeature()?.range ?: 0.0..1.0 - return factory.build(numPoints, range) - } else { - val ranges = predefinedRanges.ranges - var counter = 0 - val length = ranges.sumOf { it.second } - val pointsArray = DoubleArray(length) - val weightsArray = DoubleArray(length) - - for (range in ranges) { - val rule = factory.build(range.second, range.first) - repeat(rule.first.size) { i -> - pointsArray[counter] = rule.first[i] - weightsArray[counter] = rule.second[i] - counter++ - } - - } - return pointsArray.asBuffer() to weightsArray.asBuffer() - } - } - - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand = with(algebra) { - val f = integrand.function - val (points, weights) = buildRule(integrand) - var res = zero - var c = zero - for (i in points.indices) { - val x = points[i] - val weight = weights[i] - val y: T = weight * f(x) - c - val t = res + y - c = t - res - y - res = t - } - return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + points.size) - } - - public companion object -} - -/** - * Create a Gauss-Legendre integrator for this field. - * @see [GaussIntegrator] - */ -public val Field.gaussIntegrator: GaussIntegrator get() = GaussIntegrator(this) - - -/** - * Integrate using [intervals] segments with Gauss-Legendre rule of [order] order. - */ -@UnstableKMathAPI -public fun GaussIntegrator.integrate( - range: ClosedRange, - order: Int = 10, - intervals: Int = 10, - vararg features: IntegrandFeature, - function: (Double) -> T, -): UnivariateIntegrand { - require(range.endInclusive > range.start) { "The range upper bound should be higher than lower bound" } - require(order > 1) { "The order of polynomial must be more than 1" } - require(intervals > 0) { "Number of intervals must be positive" } - val rangeSize = (range.endInclusive - range.start) / intervals - val ranges = UnivariateIntegrandRanges( - (0 until intervals).map { i -> (range.start + rangeSize * i)..(range.start + rangeSize * (i + 1)) to order } - ) - return integrate( - UnivariateIntegrand( - function, - IntegrationRange(range), - GaussLegendreRuleFactory, - ranges, - *features - ) - ) -} \ No newline at end of file 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 deleted file mode 100644 index b09129626..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/GaussIntegratorRuleFactory.kt +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.integration - -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.asBuffer -import space.kscience.kmath.structures.map -import kotlin.jvm.Synchronized -import kotlin.math.ulp -import kotlin.native.concurrent.ThreadLocal - -public interface GaussIntegratorRuleFactory : IntegrandFeature { - public fun build(numPoints: Int): Pair, Buffer> - - public companion object { - public fun double(numPoints: Int, range: ClosedRange): Pair, Buffer> = - GaussLegendreRuleFactory.build(numPoints, range) - } -} - -/** - * Create an integration rule by scaling existing normalized rule - * - */ -public fun GaussIntegratorRuleFactory.build( - numPoints: Int, - range: ClosedRange, -): Pair, Buffer> { - val normalized = build(numPoints) - val length = range.endInclusive - range.start - - val points = normalized.first.map(::DoubleBuffer) { - range.start + length / 2 + length / 2 * it - } - - val weights = normalized.second.map(::DoubleBuffer) { - it * length / 2 - } - - return points to weights - -} - - -/** - * Gauss integrator rule based ont Legendre polynomials. All rules are normalized to - * - * The code is based on [Apache Commons Math source code version 3.6.1](https://commons.apache.org/proper/commons-math/javadocs/api-3.6.1/org/apache/commons/math3/analysis/integration/gauss/LegendreRuleFactory.html) - * - */ -@ThreadLocal -public object GaussLegendreRuleFactory : GaussIntegratorRuleFactory { - - private val cache = HashMap, Buffer>>() - - @Synchronized - private fun getOrBuildRule(numPoints: Int): Pair, Buffer> = - cache.getOrPut(numPoints) { buildRule(numPoints) } - - - private fun buildRule(numPoints: Int): Pair, Buffer> { - if (numPoints == 1) { - // Break recursion. - return Pair( - DoubleBuffer(0.0), - DoubleBuffer(0.0) - ) - } - - // Get previous rule. - // If it has not been computed, yet it will trigger a recursive call - // to this method. - val previousPoints: Buffer = getOrBuildRule(numPoints - 1).first - - // Compute next rule. - val points = DoubleArray(numPoints) - val weights = DoubleArray(numPoints) - - // Find i-th root of P[n+1] by bracketing. - val iMax = numPoints / 2 - for (i in 0 until iMax) { - // Lower-bound of the interval. - var a: Double = if (i == 0) -1.0 else previousPoints[i - 1] - // Upper-bound of the interval. - var b: Double = if (iMax == 1) 1.0 else previousPoints[i] - // P[j-1](a) - var pma = 1.0 - // P[j](a) - var pa = a - // P[j-1](b) - var pmb = 1.0 - // P[j](b) - var pb = b - for (j in 1 until numPoints) { - val twoJP1 = 2 * j + 1 - val jP1 = j + 1 - // P[j+1](a) - val ppa = (twoJP1 * a * pa - j * pma) / jP1 - // P[j+1](b) - val ppb = (twoJP1 * b * pb - j * pmb) / jP1 - pma = pa - pa = ppa - pmb = pb - pb = ppb - } - // Now pa = P[n+1](a), and pma = P[n](a) (same holds for b). - // Middle of the interval. - var c = 0.5 * (a + b) - // P[j-1](c) - var pmc = 1.0 - // P[j](c) - var pc = c - var done = false - while (!done) { - done = b - a <= c.ulp - pmc = 1.0 - pc = c - for (j in 1 until numPoints) { - // P[j+1](c) - val ppc = ((2 * j + 1) * c * pc - j * pmc) / (j + 1) - pmc = pc - pc = ppc - } - // Now pc = P[n+1](c) and pmc = P[n](c). - if (!done) { - if (pa * pc <= 0) { - b = c - } else { - a = c - pa = pc - } - c = 0.5 * (a + b) - } - } - val d = numPoints * (pmc - c * pc) - val w = 2 * (1 - c * c) / (d * d) - points[i] = c - weights[i] = w - val idx = numPoints - i - 1 - points[idx] = -c - weights[idx] = w - } - // If "numPoints" is odd, 0 is a root. - // Note: as written, the test for oddness will work for negative - // integers too (although it is unnecessary here), preventing - // a FindBugs warning. - if (numPoints % 2 != 0) { - var pmc = 1.0 - var j = 1 - while (j < numPoints) { - pmc = -j * pmc / (j + 1) - j += 2 - } - val d = numPoints * pmc - val w = 2 / (d * d) - points[iMax] = 0.0 - weights[iMax] = w - } - return Pair(points.asBuffer(), weights.asBuffer()) - } - - override fun build(numPoints: Int): Pair, Buffer> = getOrBuildRule(numPoints) - - override fun toString(): String = "GaussLegendreRule" -} \ No newline at end of file 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 deleted file mode 100644 index 0fdfee6c6..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrand.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.integration - -import kotlin.reflect.KClass - -public interface IntegrandFeature { - override fun toString(): String -} - -public interface Integrand { - public val features: Set - public fun getFeature(type: KClass): T? -} - -public inline fun Integrand.getFeature(): T? = getFeature(T::class) - -public class IntegrandValue(public val value: T) : IntegrandFeature { - override fun toString(): String = "Value($value)" -} - -public class IntegrandRelativeAccuracy(public val accuracy: Double) : IntegrandFeature { - override fun toString(): String = "TargetRelativeAccuracy($accuracy)" -} - -public class IntegrandAbsoluteAccuracy(public val accuracy: Double) : IntegrandFeature { - override fun toString(): String = "TargetAbsoluteAccuracy($accuracy)" -} - -public class IntegrandCallsPerformed(public val calls: Int) : IntegrandFeature { - override fun toString(): String = "Calls($calls)" -} - -public val Integrand.calls: Int get() = getFeature()?.calls ?: 0 - -public class IntegrandMaxCalls(public val maxCalls: Int) : IntegrandFeature { - override fun toString(): String = "MaxCalls($maxCalls)" -} - -public class IntegrandIterationsRange(public val range: IntRange) : IntegrandFeature { - override fun toString(): String = "Iterations(${range.first}..${range.last})" -} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt deleted file mode 100644 index 18c428667..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/Integrator.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.integration - -/** - * A general interface for all integrators. - */ -public interface Integrator { - /** - * Runs one integration pass and return a new [Integrand] with a new set of features. - */ - public fun integrate(integrand: I): I -} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt deleted file mode 100644 index fcc0a8d62..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/MultivariateIntegrand.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.integration - -import space.kscience.kmath.linear.Point -import kotlin.reflect.KClass - -public class MultivariateIntegrand internal constructor( - private val featureMap: Map, IntegrandFeature>, - public val function: (Point) -> T, -) : Integrand { - - override val features: Set get() = featureMap.values.toSet() - - @Suppress("UNCHECKED_CAST") - override fun getFeature(type: KClass): T? = featureMap[type] as? T - - public operator fun plus(pair: Pair, F>): MultivariateIntegrand = - MultivariateIntegrand(featureMap + pair, function) - - public operator fun plus(feature: F): MultivariateIntegrand = - plus(feature::class to feature) -} - -@Suppress("FunctionName") -public fun MultivariateIntegrand( - vararg features: IntegrandFeature, - function: (Point) -> T, -): MultivariateIntegrand = MultivariateIntegrand(features.associateBy { it::class }, function) - -public val MultivariateIntegrand.value: T? get() = getFeature>()?.value diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt deleted file mode 100644 index 9bcc8e4d9..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SimpsonIntegrator.kt +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.integration - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke -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. - */ -@UnstableKMathAPI -public class SimpsonIntegrator( - public val algebra: Field, -) : UnivariateIntegrator { - - private fun integrateRange( - integrand: UnivariateIntegrand, range: ClosedRange, numPoints: Int, - ): T = algebra { - val h: Double = (range.endInclusive - range.start) / (numPoints - 1) - val values: List = List(numPoints) { i -> - integrand.function(range.start + i * h) - }// equally distributed point - - //TODO don't use list, reassign values instead - fun simpson(index: Int) = h / 3 * (values[index - 1] + 4 * values[index] + values[index + 1]) - - var res = zero - res += simpson(1) / 1.5 //border points with 1.5 factor - for (i in 2 until (values.size - 2)) { - //each half-interval is computed twice, therefore /2 - res += simpson(i) / 2 - } - res += simpson(values.size - 2) / 1.5 //border points with 1.5 factor - return res - } - - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { - val ranges = integrand.getFeature() - return if (ranges != null) { - val res = algebra.sum(ranges.ranges.map { integrateRange(integrand, it.first, it.second) }) - integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + ranges.ranges.sumOf { it.second }) - } else { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - require(numPoints >= 4) { "Simpson integrator requires at least 4 nodes" } - val range = integrand.getFeature()?.range ?: 0.0..1.0 - val res = integrateRange(integrand, range, numPoints) - integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + numPoints) - } - } -} - -@UnstableKMathAPI -public val Field.simpsonIntegrator: SimpsonIntegrator get() = SimpsonIntegrator(this) - -/** - * 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.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 { - val h: Double = (range.endInclusive - range.start) / (numPoints - 1) - val values = DoubleArray(numPoints) { i -> - integrand.function(range.start + i * h) - }// equally distributed point - - fun simpson(index: Int) = h / 3 * (values[index - 1] + 4 * values[index] + values[index + 1]) - - var res = 0.0 - res += simpson(1) / 1.5 //border points with 1.5 factor - for (i in 2 until (values.size - 2)) { - //each half-interval is computed twice, therefore /2 - res += simpson(i) / 2 - } - res += simpson(values.size - 2) / 1.5 //border points with 1.5 factor - return res - } - - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand { - val ranges = integrand.getFeature() - return if (ranges != null) { - val res = ranges.ranges.sumOf { integrateRange(integrand, it.first, it.second) } - integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + ranges.ranges.sumOf { it.second }) - } else { - val numPoints = integrand.getFeature()?.maxCalls ?: 100 - require(numPoints >= 4) { "Simpson integrator requires at least 4 nodes" } - val range = integrand.getFeature()?.range ?: 0.0..1.0 - val res = integrateRange(integrand, range, numPoints) - integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + numPoints) - } - } -} - -public val DoubleField.simpsonIntegrator: DoubleSimpsonIntegrator get() = DoubleSimpsonIntegrator \ No newline at end of file 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 deleted file mode 100644 index 65a3d5e82..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/SplineIntegrator.kt +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.integration - -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.integrate -import space.kscience.kmath.interpolation.PolynomialInterpolator -import space.kscience.kmath.interpolation.SplineInterpolator -import space.kscience.kmath.interpolation.interpolatePolynomials -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.operations.sum -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.MutableBufferFactory -import space.kscience.kmath.structures.map - -/** - * Compute analytical indefinite integral of this [PiecewisePolynomial], keeping all intervals intact - */ -@UnstableKMathAPI -public fun > PiecewisePolynomial.integrate(algebra: Field): PiecewisePolynomial = - PiecewisePolynomial(pieces.map { it.first to it.second.integrate(algebra) }) - -/** - * Compute definite integral of given [PiecewisePolynomial] piece by piece in a given [range] - * Requires [UnivariateIntegrationNodes] or [IntegrationRange] and [IntegrandMaxCalls] - */ -@UnstableKMathAPI -public fun > PiecewisePolynomial.integrate( - algebra: Field, range: ClosedRange, -): T = algebra.sum( - pieces.map { (region, poly) -> - val intersectedRange = maxOf(range.start, region.start)..minOf(range.endInclusive, region.endInclusive) - //Check if polynomial range is not used - if (intersectedRange.start == intersectedRange.endInclusive) algebra.zero - else poly.integrate(algebra, intersectedRange) - } -) - -/** - * 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. - */ -@UnstableKMathAPI -public class SplineIntegrator>( - public val algebra: Field, - public val bufferFactory: MutableBufferFactory, -) : UnivariateIntegrator { - override fun integrate(integrand: UnivariateIntegrand): UnivariateIntegrand = algebra { - 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) - DoubleBuffer(numPoints) { i -> range.start + i * step } - } - - val values = nodes.map(bufferFactory) { integrand.function(it) } - val polynomials = interpolator.interpolatePolynomials( - nodes.map(bufferFactory) { number(it) }, - values - ) - val res = polynomials.integrate(algebra, number(range.start)..number(range.endInclusive)) - integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) - } -} - -/** - * A simplified double-based spline-interpolation-based analytic integration - * * [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 integrate(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) - DoubleBuffer(numPoints) { i -> range.start + i * step } - } - - val values = nodes.map { integrand.function(it) } - val polynomials = interpolator.interpolatePolynomials(nodes, values) - val res = polynomials.integrate(DoubleField, range) - return integrand + IntegrandValue(res) + IntegrandCallsPerformed(integrand.calls + nodes.size) - } -} - -@UnstableKMathAPI -public inline val DoubleField.splineIntegrator: UnivariateIntegrator - get() = DoubleSplineIntegrator \ No newline at end of file diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt deleted file mode 100644 index f994ba9f9..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/integration/UnivariateIntegrand.kt +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.integration - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.DoubleBuffer -import kotlin.reflect.KClass - -public class UnivariateIntegrand internal constructor( - private val featureMap: Map, IntegrandFeature>, - public val function: (Double) -> T, -) : Integrand { - - override val features: Set get() = featureMap.values.toSet() - - @Suppress("UNCHECKED_CAST") - override fun getFeature(type: KClass): T? = featureMap[type] as? T - - public operator fun plus(pair: Pair, F>): UnivariateIntegrand = - UnivariateIntegrand(featureMap + pair, function) - - public operator fun plus(feature: F): UnivariateIntegrand = - plus(feature::class to feature) -} - -@Suppress("FunctionName") -public fun UnivariateIntegrand( - function: (Double) -> T, - vararg features: IntegrandFeature, -): UnivariateIntegrand = UnivariateIntegrand(features.associateBy { it::class }, function) - -public typealias UnivariateIntegrator = Integrator> - -public class IntegrationRange(public val range: ClosedRange) : IntegrandFeature { - override fun toString(): String = "Range(${range.start}..${range.endInclusive})" -} - -/** - * 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()) - - override fun toString(): String { - val rangesString = ranges.joinToString(separator = ",") { (range, points) -> - "${range.start}..${range.endInclusive} : $points" - } - return "UnivariateRanges($rangesString)" - } -} - -public class UnivariateIntegrationNodes(public val nodes: Buffer) : IntegrandFeature { - public constructor(vararg nodes: Double) : this(DoubleBuffer(nodes)) - - override fun toString(): String = "UnivariateNodes($nodes)" -} - - -/** - * Value of the integrand if it is present or null - */ -public val UnivariateIntegrand.valueOrNull: T? get() = getFeature>()?.value - -/** - * Value of the integrand or error - */ -public val UnivariateIntegrand.value: T get() = valueOrNull ?: error("No value in the integrand") - -/** - * A shortcut method to integrate a [function] with additional [features]. Range must be provided in features. - * The [function] is placed in the end position to allow passing a lambda. - */ -@UnstableKMathAPI -public fun UnivariateIntegrator.integrate( - vararg features: IntegrandFeature, - function: (Double) -> T, -): UnivariateIntegrand = integrate(UnivariateIntegrand(function, *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 -public fun UnivariateIntegrator.integrate( - range: ClosedRange, - vararg features: IntegrandFeature, - function: (Double) -> T, -): UnivariateIntegrand = integrate(UnivariateIntegrand(function, IntegrationRange(range), *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 -public fun UnivariateIntegrator.integrate( - range: ClosedRange, - featureBuilder: MutableList.() -> Unit = {}, - function: (Double) -> T, -): UnivariateIntegrand { - //TODO use dedicated feature builder class instead or add extensions to MutableList - val features = buildList { - featureBuilder() - add(IntegrationRange(range)) - } - return integrate(UnivariateIntegrand(function, *features.toTypedArray())) -} diff --git a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt b/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt deleted file mode 100644 index 7a096f902..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/Interpolator.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -@file:OptIn(UnstableKMathAPI::class) - -package space.kscience.kmath.interpolation - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.value -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Ring -import space.kscience.kmath.structures.Buffer -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 interpolate(points: XYColumnarData): (X) -> Y -} - -/** - * And interpolator returning [PiecewisePolynomial] function - */ -public interface PolynomialInterpolator> : Interpolator { - public val algebra: Ring - - public fun getDefaultValue(): T = error("Out of bounds") - - public fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial - - override fun interpolate(points: XYColumnarData): (T) -> T = { x -> - interpolatePolynomials(points).value(algebra, x) ?: getDefaultValue() - } -} - - -public fun > PolynomialInterpolator.interpolatePolynomials( - x: Buffer, - y: Buffer, -): PiecewisePolynomial { - val pointSet = XYColumnarData(x, y) - return interpolatePolynomials(pointSet) -} - -public fun > PolynomialInterpolator.interpolatePolynomials( - data: Map, -): PiecewisePolynomial { - val pointSet = XYColumnarData(data.keys.toList().asBuffer(), data.values.toList().asBuffer()) - return interpolatePolynomials(pointSet) -} - -public fun > PolynomialInterpolator.interpolatePolynomials( - data: List>, -): PiecewisePolynomial { - val pointSet = XYColumnarData(data.map { it.first }.asBuffer(), data.map { it.second }.asBuffer()) - return interpolatePolynomials(pointSet) -} 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 deleted file mode 100644 index eff9cd97d..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/LinearInterpolator.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.interpolation - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.Polynomial -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke - -@OptIn(UnstableKMathAPI::class) -internal fun > insureSorted(points: XYColumnarData<*, T, *>) { - for (i in 0 until points.size - 1) - require(points.x[i + 1] > points.x[i]) { "Input data is not sorted at index $i" } -} - -/** - * Reference JVM implementation: https://github.com/apache/commons-math/blob/master/src/main/java/org/apache/commons/math4/analysis/interpolation/LinearInterpolator.java - */ -public class LinearInterpolator>(override val algebra: Field) : PolynomialInterpolator { - @OptIn(UnstableKMathAPI::class) - override fun interpolatePolynomials(points: XYColumnarData): PiecewisePolynomial = algebra { - require(points.size > 0) { "Point array should not be empty" } - insureSorted(points) - - PiecewisePolynomial(points.x[0]) { - for (i in 0 until points.size - 1) { - val slope = (points.y[i + 1] - points.y[i]) / (points.x[i + 1] - points.x[i]) - val const = points.y[i] - slope * points.x[i] - val polynomial = Polynomial(const, slope) - putRight(points.x[i + 1], polynomial) - } - } - } -} 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 deleted file mode 100644 index ac9708d01..000000000 --- a/kmath-functions/src/commonMain/kotlin/space/kscience/kmath/interpolation/SplineInterpolator.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.interpolation - -import space.kscience.kmath.data.XYColumnarData -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.Polynomial -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Field -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.MutableBufferFactory - -/** - * Generic spline interpolator. Not recommended for performance critical places, use platform-specific and type - * specific ones. - * - * Based on - * https://github.com/apache/commons-math/blob/eb57d6d457002a0bb5336d789a3381a24599affe/src/main/java/org/apache/commons/math4/analysis/interpolation/SplineInterpolator.java - */ -public class SplineInterpolator>( - override val algebra: Field, - public val bufferFactory: MutableBufferFactory, -) : PolynomialInterpolator { - //TODO possibly optimize zeroed buffers - - @OptIn(UnstableKMathAPI::class) - 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. - val n = points.size - 1 - // Differences between knot points - val h = bufferFactory(n) { i -> points.x[i + 1] - points.x[i] } - val mu = bufferFactory(n) { zero } - val z = bufferFactory(n + 1) { zero } - - for (i in 1 until n) { - val g = 2.0 * (points.x[i + 1] - points.x[i - 1]) - h[i - 1] * mu[i - 1] - mu[i] = h[i] / g - z[i] = - ((points.y[i + 1] * h[i - 1] - points.y[i] * (points.x[i + 1] - points.x[i - 1]) + points.y[i - 1] * h[i]) * 3.0 / - (h[i - 1] * h[i]) - h[i - 1] * z[i - 1]) / g - } - - // cubic spline coefficients -- b is linear, c quadratic, d is cubic (original y's are constants) - - PiecewisePolynomial(points.x[points.size - 1]) { - var cOld = zero - - for (j in n - 1 downTo 0) { - val c = z[j] - mu[j] * cOld - val a = points.y[j] - val b = (points.y[j + 1] - points.y[j]) / h[j] - h[j] * (cOld + 2.0 * c) / 3.0 - val d = (cOld - c) / (3.0 * h[j]) - val x0 = points.x[j] - val x02 = x0 * x0 - val x03 = x02 * x0 - //Shift coefficients to represent absolute polynomial instead of one with an offset - val polynomial = Polynomial( - a - b * x0 + c * x02 - d * x03, - b - 2*c*x0 + 3*d*x02, - c - 3*d*x0, - d - ) - cOld = c - putLeft(x0, polynomial) - } - } - } - - public companion object { - public val double: SplineInterpolator = SplineInterpolator(DoubleField, ::DoubleBuffer) - } -} diff --git a/kmath-functions/src/commonTest/kotlin/scientifik/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/scientifik/kmath/interpolation/LinearInterpolatorTest.kt new file mode 100644 index 000000000..23acd835c --- /dev/null +++ b/kmath-functions/src/commonTest/kotlin/scientifik/kmath/interpolation/LinearInterpolatorTest.kt @@ -0,0 +1,27 @@ +package scientifik.kmath.interpolation + +import scientifik.kmath.functions.PiecewisePolynomial +import scientifik.kmath.functions.asFunction +import scientifik.kmath.operations.RealField +import kotlin.test.Test +import kotlin.test.assertEquals + + +class LinearInterpolatorTest { + @Test + fun testInterpolation() { + val data = listOf( + 0.0 to 0.0, + 1.0 to 1.0, + 2.0 to 3.0, + 3.0 to 4.0 + ) + val polynomial: PiecewisePolynomial = LinearInterpolator(RealField).interpolatePolynomials(data) + val function = polynomial.asFunction(RealField) + + assertEquals(null, function(-1.0)) + assertEquals(0.5, function(0.5)) + assertEquals(2.0, function(1.5)) + assertEquals(3.0, function(2.0)) + } +} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt deleted file mode 100644 index 21e5473a0..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/functions/PolynomialTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.functions - -import kotlin.test.Test -import kotlin.test.assertEquals - -class PolynomialTest { - @Test - fun testIntegration() { - val polynomial = Polynomial(1.0, -2.0, 1.0) - assertEquals(0.0, polynomial.value(1.0), 0.001) - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt deleted file mode 100644 index 533389a6e..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/GaussIntegralTest.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.integration - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import kotlin.math.PI -import kotlin.math.sin -import kotlin.test.Test -import kotlin.test.assertEquals - -@OptIn(UnstableKMathAPI::class) -class GaussIntegralTest { - @Test - fun gaussSin() { - val res = DoubleField.gaussIntegrator.integrate(0.0..2 * PI) { x -> - sin(x) - } - assertEquals(0.0, res.value, 1e-2) - } - - @Test - fun gaussUniform() { - val res = DoubleField.gaussIntegrator.integrate(35.0..100.0) { x -> - if(x in 30.0..50.0){ - 1.0 - } else { - 0.0 - } - } - assertEquals(15.0, res.value, 0.5) - } - - -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt deleted file mode 100644 index eaf7abbfd..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SimpsonIntegralTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.integration - -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import kotlin.math.PI -import kotlin.math.sin -import kotlin.test.Test -import kotlin.test.assertEquals - -@OptIn(UnstableKMathAPI::class) -class SimpsonIntegralTest { - @Test - fun gaussSin() { - val res = DoubleField.simpsonIntegrator.integrate(0.0..2 * PI, IntegrandMaxCalls(5)) { x -> - sin(x) - } - assertEquals(0.0, res.value, 1e-2) - } - - @Test - fun gaussUniform() { - val res = DoubleField.simpsonIntegrator.integrate(35.0..100.0, IntegrandMaxCalls(20)) { x -> - if (x in 30.0..50.0) { - 1.0 - } else { - 0.0 - } - } - assertEquals(15.0, res.value, 0.5) - } -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt deleted file mode 100644 index 4dffb276f..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/integration/SplineIntegralTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.integration - -import space.kscience.kmath.functions.Polynomial -import space.kscience.kmath.functions.integrate -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.DoubleField -import kotlin.math.PI -import kotlin.math.sin -import kotlin.test.Test -import kotlin.test.assertEquals - -@OptIn(UnstableKMathAPI::class) -class SplineIntegralTest { - - @Test - fun integratePolynomial(){ - val polynomial = Polynomial(1.0, 2.0, 3.0) - val integral = polynomial.integrate(DoubleField,1.0..2.0) - assertEquals(11.0, integral, 0.001) - } - - @Test - fun gaussSin() { - val res = DoubleField.splineIntegrator.integrate(0.0..2 * PI, IntegrandMaxCalls(5)) { x -> - sin(x) - } - assertEquals(0.0, res.value, 1e-2) - } - - @Test - fun gaussUniform() { - val res = DoubleField.splineIntegrator.integrate(35.0..100.0, IntegrandMaxCalls(20)) { x -> - if(x in 30.0..50.0){ - 1.0 - } else { - 0.0 - } - } - assertEquals(15.0, res.value, 0.5) - } - - -} \ No newline at end of file diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt deleted file mode 100644 index c3388c265..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/LinearInterpolatorTest.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.interpolation - -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.asFunction -import space.kscience.kmath.operations.DoubleField -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class LinearInterpolatorTest { - @Test - fun testInterpolation() { - val data = listOf( - 0.0 to 0.0, - 1.0 to 1.0, - 2.0 to 3.0, - 3.0 to 4.0 - ) - - val polynomial: PiecewisePolynomial = LinearInterpolator(DoubleField).interpolatePolynomials(data) - val function = polynomial.asFunction(DoubleField) - assertEquals(null, function(-1.0)) - assertEquals(0.5, function(0.5)) - assertEquals(2.0, function(1.5)) - assertEquals(3.0, function(2.0)) - } -} diff --git a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt b/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt deleted file mode 100644 index 42f41ab80..000000000 --- a/kmath-functions/src/commonTest/kotlin/space/kscience/kmath/interpolation/SplineInterpolatorTest.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.interpolation - -import space.kscience.kmath.functions.PiecewisePolynomial -import space.kscience.kmath.functions.asFunction -import space.kscience.kmath.operations.DoubleField -import kotlin.math.PI -import kotlin.math.sin -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class SplineInterpolatorTest { - @Test - fun testInterpolation() { - val data = (0..10).map { - val x = it.toDouble() / 5 * PI - x to sin(x) - } - - val polynomial: PiecewisePolynomial = SplineInterpolator.double.interpolatePolynomials(data) - - val function = polynomial.asFunction(DoubleField, Double.NaN) - assertEquals(Double.NaN, function(-1.0)) - assertEquals(sin(0.5), function(0.5), 0.1) - assertEquals(sin(1.5), function(1.5), 0.1) - assertEquals(sin(2.0), function(2.0), 0.1) - } -} diff --git a/kmath-geometry/build.gradle.kts b/kmath-geometry/build.gradle.kts index 7eb814683..39aa833ad 100644 --- a/kmath-geometry/build.gradle.kts +++ b/kmath-geometry/build.gradle.kts @@ -1,15 +1,9 @@ plugins { - kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("scientifik.mpp") } kotlin.sourceSets.commonMain { dependencies { api(project(":kmath-core")) } -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE -} +} \ No newline at end of file diff --git a/kmath-geometry/src/commonMain/kotlin/scientifik/kmath/geometry/Euclidean2DSpace.kt b/kmath-geometry/src/commonMain/kotlin/scientifik/kmath/geometry/Euclidean2DSpace.kt new file mode 100644 index 000000000..2313b2170 --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/scientifik/kmath/geometry/Euclidean2DSpace.kt @@ -0,0 +1,58 @@ +package scientifik.kmath.geometry + +import scientifik.kmath.linear.Point +import scientifik.kmath.operations.SpaceElement +import scientifik.kmath.operations.invoke +import kotlin.math.sqrt + + +interface Vector2D : Point, Vector, SpaceElement { + val x: Double + val y: Double + + override val size: Int get() = 2 + + override fun get(index: Int): Double = when (index) { + 1 -> x + 2 -> y + else -> error("Accessing outside of point bounds") + } + + override fun iterator(): Iterator = listOf(x, y).iterator() + + override val context: Euclidean2DSpace get() = Euclidean2DSpace + + override fun unwrap(): Vector2D = this + + override fun Vector2D.wrap(): Vector2D = this +} + +val Vector2D.r: Double get() = Euclidean2DSpace.run { sqrt(norm()) } + +@Suppress("FunctionName") +fun Vector2D(x: Double, y: Double): Vector2D = Vector2DImpl(x, y) + +private data class Vector2DImpl( + override val x: Double, + override val y: Double +) : Vector2D + +/** + * 2D Euclidean space + */ +object Euclidean2DSpace : GeometrySpace { + fun Vector2D.norm(): Double = sqrt(x * x + y * 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 multiply(a: Vector2D, k: Number): Vector2D = + Vector2D(a.x * k.toDouble(), a.y * k.toDouble()) + + override val zero: Vector2D = Vector2D(0.0, 0.0) + + override fun Vector2D.dot(other: Vector2D): Double = + x * other.x + y * other.y +} \ No newline at end of file diff --git a/kmath-geometry/src/commonMain/kotlin/scientifik/kmath/geometry/Euclidean3DSpace.kt b/kmath-geometry/src/commonMain/kotlin/scientifik/kmath/geometry/Euclidean3DSpace.kt new file mode 100644 index 000000000..dd1776342 --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/scientifik/kmath/geometry/Euclidean3DSpace.kt @@ -0,0 +1,57 @@ +package scientifik.kmath.geometry + +import scientifik.kmath.linear.Point +import scientifik.kmath.operations.SpaceElement +import kotlin.math.sqrt + + +interface Vector3D : Point, Vector, SpaceElement { + val x: Double + val y: Double + val z: Double + + override val size: Int get() = 3 + + override fun get(index: Int): Double = when (index) { + 1 -> x + 2 -> y + 3 -> z + else -> error("Accessing outside of point bounds") + } + + override fun iterator(): Iterator = listOf(x, y, z).iterator() + + override val context: Euclidean3DSpace get() = Euclidean3DSpace + + override fun unwrap(): Vector3D = this + + override fun Vector3D.wrap(): Vector3D = this +} + +@Suppress("FunctionName") +fun Vector3D(x: Double, y: Double, z: Double): Vector3D = Vector3DImpl(x, y, z) + +val Vector3D.r: Double get() = Euclidean3DSpace.run { sqrt(norm()) } + +private data class Vector3DImpl( + override val x: Double, + override val y: Double, + override val z: Double +) : Vector3D + +object Euclidean3DSpace : GeometrySpace { + override val zero: Vector3D = Vector3D(0.0, 0.0, 0.0) + + fun Vector3D.norm(): Double = sqrt(x * x + y * y + z * z) + + override fun Vector3D.distanceTo(other: Vector3D): Double = (this - other).norm() + + override fun add(a: Vector3D, b: Vector3D): Vector3D = + Vector3D(a.x + b.x, a.y + b.y, a.z + b.z) + + override fun multiply(a: Vector3D, k: Number): Vector3D = + Vector3D(a.x * k.toDouble(), a.y * k.toDouble(), a.z * k.toDouble()) + + override fun Vector3D.dot(other: Vector3D): Double = + x * other.x + y * other.y + z * other.z +} \ No newline at end of file diff --git a/kmath-geometry/src/commonMain/kotlin/scientifik/kmath/geometry/GeometrySpace.kt b/kmath-geometry/src/commonMain/kotlin/scientifik/kmath/geometry/GeometrySpace.kt new file mode 100644 index 000000000..b65a8dd3a --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/scientifik/kmath/geometry/GeometrySpace.kt @@ -0,0 +1,17 @@ +package scientifik.kmath.geometry + +import scientifik.kmath.operations.Space + +interface Vector + +interface GeometrySpace: Space { + /** + * L2 distance + */ + fun V.distanceTo(other: V): Double + + /** + * Scalar product + */ + infix fun V.dot(other: V): Double +} \ No newline at end of file diff --git a/kmath-geometry/src/commonMain/kotlin/scientifik/kmath/geometry/Line.kt b/kmath-geometry/src/commonMain/kotlin/scientifik/kmath/geometry/Line.kt new file mode 100644 index 000000000..d802a103f --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/scientifik/kmath/geometry/Line.kt @@ -0,0 +1,6 @@ +package scientifik.kmath.geometry + +data class Line(val base: V, val direction: V) + +typealias Line2D = Line +typealias Line3D = Line diff --git a/kmath-geometry/src/commonMain/kotlin/scientifik/kmath/geometry/ReferenceFrame.kt b/kmath-geometry/src/commonMain/kotlin/scientifik/kmath/geometry/ReferenceFrame.kt new file mode 100644 index 000000000..420e38ce2 --- /dev/null +++ b/kmath-geometry/src/commonMain/kotlin/scientifik/kmath/geometry/ReferenceFrame.kt @@ -0,0 +1,4 @@ +package scientifik.kmath.geometry + +interface ReferenceFrame { +} \ No newline at end of file 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 deleted file mode 100644 index e8b1ce95b..000000000 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean2DSpace.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.geometry - -import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.operations.invoke -import kotlin.math.sqrt - -@OptIn(UnstableKMathAPI::class) -public interface Vector2D : Point, Vector { - public val x: Double - public val y: Double - override val size: Int get() = 2 - - override operator fun get(index: Int): Double = when (index) { - 0 -> x - 1 -> y - else -> error("Accessing outside of point bounds") - } - - override operator fun iterator(): Iterator = listOf(x, y).iterator() -} - -public val Vector2D.r: Double - get() = Euclidean2DSpace { norm() } - -@Suppress("FunctionName") -public fun Vector2D(x: Double, y: Double): Vector2D = Vector2DImpl(x, y) - -private data class Vector2DImpl( - override val x: Double, - override val y: Double, -) : Vector2D - -/** - * 2D Euclidean space - */ -public object Euclidean2DSpace : GeometrySpace, ScaleOperations { - 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) - - 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 deleted file mode 100644 index d567bee9a..000000000 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Euclidean3DSpace.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.geometry - -import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.operations.invoke -import kotlin.math.sqrt - -@OptIn(UnstableKMathAPI::class) -public interface Vector3D : Point, Vector { - public val x: Double - public val y: Double - public val z: Double - override val size: Int get() = 3 - - override operator fun get(index: Int): Double = when (index) { - 0 -> x - 1 -> y - 2 -> z - else -> error("Accessing outside of point bounds") - } - - override operator fun iterator(): Iterator = listOf(x, y, z).iterator() -} - -@Suppress("FunctionName") -public fun Vector3D(x: Double, y: Double, z: Double): Vector3D = Vector3DImpl(x, y, z) - -public val Vector3D.r: Double get() = Euclidean3DSpace { norm() } - -private data class Vector3DImpl( - override val x: Double, - override val y: Double, - override val z: Double, -) : Vector3D - -public object Euclidean3DSpace : GeometrySpace, ScaleOperations { - 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) - - override fun Vector3D.distanceTo(other: Vector3D): Double = (this - other).norm() - - override fun add(a: Vector3D, b: Vector3D): Vector3D = - Vector3D(a.x + b.x, a.y + b.y, a.z + b.z) - - override fun scale(a: Vector3D, value: Double): Vector3D = - Vector3D(a.x * value, a.y * value, a.z * value) - - 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/GeometrySpace.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt deleted file mode 100644 index 3d3f8b653..000000000 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/GeometrySpace.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.geometry - -import space.kscience.kmath.operations.Group -import space.kscience.kmath.operations.ScaleOperations - -public interface Vector - -public interface GeometrySpace : Group, ScaleOperations { - /** - * L2 distance - */ - public fun V.distanceTo(other: V): Double - - /** - * Scalar product - */ - public infix fun V.dot(other: V): Double -} \ No newline at end of file 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 deleted file mode 100644 index d9dc57ec2..000000000 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Line.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.geometry - -public data class Line(val base: V, val direction: V) - -public typealias Line2D = Line -public typealias Line3D = Line diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Projections.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Projections.kt deleted file mode 100644 index 205bc17e7..000000000 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/Projections.kt +++ /dev/null @@ -1,20 +0,0 @@ -package space.kscience.kmath.geometry - -/** - * Project vector onto a line. - * @param vector to project - * @param line line to which vector should be projected - */ -public fun GeometrySpace.projectToLine(vector: V, line: Line): V = with(line) { - base + (direction dot (vector - base)) / (direction dot direction) * direction -} - -/** - * Project vector onto a hyperplane, which is defined by a normal and base. - * In 2D case it is the projection to a line, in 3d case it is the one to a plane. - * @param vector to project - * @param normal normal (perpendicular) vector to a hyper-plane to which vector should be projected - * @param base point belonging to a hyper-plane to which vector should be projected - */ -public fun GeometrySpace.projectAlong(vector: V, normal: V, base: V): V = - vector + normal * ((base - vector) dot normal) / (normal dot normal) diff --git a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt b/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt deleted file mode 100644 index 7bb95c009..000000000 --- a/kmath-geometry/src/commonMain/kotlin/space/kscience/kmath/geometry/ReferenceFrame.kt +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.geometry - -public interface ReferenceFrame diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt deleted file mode 100644 index 5913b2fa9..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean2DSpaceTest.kt +++ /dev/null @@ -1,62 +0,0 @@ -package space.kscience.kmath.geometry - -import kotlin.math.sqrt -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class Euclidean2DSpaceTest { - @Test - fun zero() { - assertVectorEquals(Vector2D(0.0, 0.0), Euclidean2DSpace.zero) - } - - @Test - fun norm() { - with(Euclidean2DSpace) { - assertEquals(0.0, zero.norm()) - assertEquals(1.0, Vector2D(1.0, 0.0).norm()) - assertEquals(sqrt(2.0), Vector2D(1.0, 1.0).norm()) - assertEquals(sqrt(5.002001), Vector2D(-2.0, 1.001).norm()) - } - } - - @Test - fun dotProduct() { - with(Euclidean2DSpace) { - assertEquals(0.0, zero dot zero) - assertEquals(0.0, zero dot Vector2D(1.0, 0.0)) - assertEquals(0.0, Vector2D(-2.0, 0.001) dot zero) - assertEquals(0.0, Vector2D(1.0, 0.0) dot Vector2D(0.0, 1.0)) - - assertEquals(1.0, Vector2D(1.0, 0.0) dot Vector2D(1.0, 0.0)) - assertEquals(-2.0, Vector2D(0.0, 1.0) dot Vector2D(1.0, -2.0)) - assertEquals(2.0, Vector2D(1.0, 1.0) dot Vector2D(1.0, 1.0)) - assertEquals(4.001001, Vector2D(-2.0, 1.001) dot Vector2D(-2.0, 0.001)) - - assertEquals(-4.998, Vector2D(1.0, 2.0) dot Vector2D(-5.0, 0.001)) - } - } - - @Test - fun add() { - with(Euclidean2DSpace) { - assertVectorEquals( - Vector2D(-2.0, 0.001), - Vector2D(-2.0, 0.001) + zero - ) - assertVectorEquals( - Vector2D(-3.0, 3.001), - Vector2D(2.0, 3.0) + Vector2D(-5.0, 0.001) - ) - } - } - - @Test - fun multiply() { - with(Euclidean2DSpace) { - assertVectorEquals(Vector2D(-4.0, 0.0), Vector2D(-2.0, 0.0) * 2) - assertVectorEquals(Vector2D(4.0, 0.0), Vector2D(-2.0, 0.0) * -2) - assertVectorEquals(Vector2D(300.0, 0.0003), Vector2D(100.0, 0.0001) * 3) - } - } -} diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt deleted file mode 100644 index 2c74cbd27..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Euclidean3DSpaceTest.kt +++ /dev/null @@ -1,74 +0,0 @@ -package space.kscience.kmath.geometry - -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class Euclidean3DSpaceTest { - @Test - fun zero() { - assertVectorEquals(Vector3D(0.0, 0.0, 0.0), Euclidean3DSpace.zero) - } - - @Test - fun distance() { - with(Euclidean3DSpace) { - assertEquals(0.0, zero.distanceTo(zero)) - assertEquals(1.0, zero.distanceTo(Vector3D(1.0, 0.0, 0.0))) - assertEquals(kotlin.math.sqrt(5.000001), Vector3D(1.0, -2.0, 0.001).distanceTo(zero)) - assertEquals(0.0, Vector3D(1.0, -2.0, 0.001).distanceTo(Vector3D(1.0, -2.0, 0.001))) - assertEquals(0.0, Vector3D(1.0, 0.0, 0.0).distanceTo(Vector3D(1.0, 0.0, 0.0))) - assertEquals(kotlin.math.sqrt(2.0), Vector3D(1.0, 0.0, 0.0).distanceTo(Vector3D(1.0, 1.0, 1.0))) - assertEquals(3.1622778182822584, Vector3D(0.0, 1.0, 0.0).distanceTo(Vector3D(1.0, -2.0, 0.001))) - assertEquals(0.0, Vector3D(1.0, -2.0, 0.001).distanceTo(Vector3D(1.0, -2.0, 0.001))) - assertEquals(9.695050335093676, Vector3D(1.0, 2.0, 3.0).distanceTo(Vector3D(7.0, -5.0, 0.001))) - } - } - - @Test - fun norm() { - with(Euclidean3DSpace) { - assertEquals(0.0, zero.norm()) - assertEquals(1.0, Vector3D(1.0, 0.0, 0.0).norm()) - assertEquals(kotlin.math.sqrt(3.0), Vector3D(1.0, 1.0, 1.0).norm()) - assertEquals(kotlin.math.sqrt(5.000001), Vector3D(1.0, -2.0, 0.001).norm()) - } - } - - @Test - fun dotProduct() { - with(Euclidean3DSpace) { - assertEquals(0.0, zero dot zero) - assertEquals(0.0, zero dot Vector3D(1.0, 0.0, 0.0)) - assertEquals(0.0, Vector3D(1.0, -2.0, 0.001) dot zero) - - assertEquals(1.0, Vector3D(1.0, 0.0, 0.0) dot Vector3D(1.0, 0.0, 0.0)) - assertEquals(1.0, Vector3D(1.0, 0.0, 0.0) dot Vector3D(1.0, 1.0, 1.0)) - assertEquals(-2.0, Vector3D(0.0, 1.0, 0.0) dot Vector3D(1.0, -2.0, 0.001)) - assertEquals(3.0, Vector3D(1.0, 1.0, 1.0) dot Vector3D(1.0, 1.0, 1.0)) - assertEquals(5.000001, Vector3D(1.0, -2.0, 0.001) dot Vector3D(1.0, -2.0, 0.001)) - - assertEquals(-2.997, Vector3D(1.0, 2.0, 3.0) dot Vector3D(7.0, -5.0, 0.001)) - } - } - - @Test - fun add() { - with(Euclidean3DSpace) { - assertVectorEquals( - Vector3D(1.0, -2.0, 0.001), - Vector3D(1.0, -2.0, 0.001) + zero - ) - assertVectorEquals( - Vector3D(8.0, -3.0, 3.001), - Vector3D(1.0, 2.0, 3.0) + Vector3D(7.0, -5.0, 0.001) - ) - } - } - - @Test - fun multiply() { - with(Euclidean3DSpace) { - assertVectorEquals(Vector3D(2.0, -4.0, 0.0), Vector3D(1.0, -2.0, 0.0) * 2) - } - } -} diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt deleted file mode 100644 index 55fc39aad..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionAlongTest.kt +++ /dev/null @@ -1,61 +0,0 @@ -package space.kscience.kmath.geometry - -import kotlin.test.Test -import kotlin.test.assertTrue - -internal class ProjectionAlongTest { - @Test - fun projectionIntoYEqualsX() { - with(Euclidean2DSpace) { - val normal = Vector2D(-2.0, 2.0) - val base = Vector2D(2.3, 2.3) - - assertVectorEquals(zero, projectAlong(zero, normal, base)) - - grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> - val d = (y - x) / 2.0 - assertVectorEquals(Vector2D(x + d, y - d), projectAlong(Vector2D(x, y), normal, base)) - } - } - } - - @Test - fun projectionOntoLine() { - with(Euclidean2DSpace) { - val a = 5.0 - val b = -3.0 - val c = -15.0 - val normal = Vector2D(-5.0, 3.0) - val base = Vector2D(3.0, 0.0) - - grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> - val xProj = (b * (b * x - a * y) - a * c) / (a * a + b * b) - val yProj = (a * (-b * x + a * y) - b * c) / (a * a + b * b) - assertVectorEquals(Vector2D(xProj, yProj), projectAlong(Vector2D(x, y), normal, base)) - } - } - } - - @Test - fun projectOntoPlane() { - val normal = Vector3D(1.0, 3.5, 0.07) - val base = Vector3D(2.0, -0.0037, 11.1111) - - with(Euclidean3DSpace) { - val testDomain = (-10.0..10.0).generateList(0.43) - for (x in testDomain) { - for (y in testDomain) { - for (z in testDomain) { - val v = Vector3D(x, y, z) - val result = projectAlong(v, normal, base) - - // assert that result is on plane - assertTrue(isOrthogonal(result - base, normal)) - // assert that PV vector is collinear to normal vector - assertTrue(isCollinear(v - result, normal)) - } - } - } - } - } -} diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt deleted file mode 100644 index ab6ef3628..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/ProjectionOntoLineTest.kt +++ /dev/null @@ -1,83 +0,0 @@ -package space.kscience.kmath.geometry - -import kotlin.test.Test -import kotlin.test.assertTrue - -internal class ProjectionOntoLineTest { - @Test - fun projectionIntoOx() { - with(Euclidean2DSpace) { - val ox = Line(zero, Vector2D(1.0, 0.0)) - - grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> - assertVectorEquals(Vector2D(x, 0.0), projectToLine(Vector2D(x, y), ox)) - } - } - } - - @Test - fun projectionIntoOy() { - with(Euclidean2DSpace) { - val line = Line(zero, Vector2D(0.0, 1.0)) - - grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> - assertVectorEquals(Vector2D(0.0, y), projectToLine(Vector2D(x, y), line)) - } - } - } - - @Test - fun projectionIntoYEqualsX() { - with(Euclidean2DSpace) { - val line = Line(zero, Vector2D(1.0, 1.0)) - - assertVectorEquals(zero, projectToLine(zero, line)) - - grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> - val d = (y - x) / 2.0 - assertVectorEquals(Vector2D(x + d, y - d), projectToLine(Vector2D(x, y), line)) - } - } - } - - @Test - fun projectionOntoLine2d() { - with(Euclidean2DSpace) { - val a = 5.0 - val b = -3.0 - val c = -15.0 - val line = Line(Vector2D(3.0, 0.0), Vector2D(3.0, 5.0)) - - grid(-10.0..10.0, -10.0..10.0, 0.15).forEach { (x, y) -> - val xProj = (b * (b * x - a * y) - a * c) / (a * a + b * b) - val yProj = (a * (-b * x + a * y) - b * c) / (a * a + b * b) - assertVectorEquals(Vector2D(xProj, yProj), projectToLine(Vector2D(x, y), line)) - } - } - } - - @Test - fun projectionOntoLine3d() { - val line = Line3D( - base = Vector3D(1.0, 3.5, 0.07), - direction = Vector3D(2.0, -0.0037, 11.1111) - ) - - with(Euclidean3DSpace) { - val testDomain = (-10.0..10.0).generateList(0.43) - for (x in testDomain) { - for (y in testDomain) { - for (z in testDomain) { - val v = Vector3D(x, y, z) - val result = projectToLine(v, line) - - // assert that result is on line - assertTrue(isCollinear(result - line.base, line.direction)) - // assert that PV vector is orthogonal to direction vector - assertTrue(isOrthogonal(v - result, line.direction)) - } - } - } - } - } -} diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt deleted file mode 100644 index 84b1f4fd6..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector2DTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -package space.kscience.kmath.geometry - -import space.kscience.kmath.structures.asSequence -import space.kscience.kmath.structures.toList -import kotlin.test.assertEquals -import kotlin.test.Test - -internal class Vector2DTest { - private val vector = Vector2D(1.0, -7.999) - - @Test - fun size() { - assertEquals(2, vector.size) - } - - @Test - fun get() { - assertEquals(1.0, vector[0]) - assertEquals(-7.999, vector[1]) - } - - @Test - fun iterator() { - assertEquals(listOf(1.0, -7.999), vector.toList()) - } - - @Test - fun x() { - assertEquals(1.0, vector.x) - } - - @Test - fun y() { - assertEquals(-7.999, vector.y) - } -} diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt deleted file mode 100644 index 717e78871..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/Vector3DTest.kt +++ /dev/null @@ -1,41 +0,0 @@ -package space.kscience.kmath.geometry - -import space.kscience.kmath.structures.toList -import kotlin.test.Test -import kotlin.test.assertEquals - -internal class Vector3DTest { - private val vector = Vector3D(1.0, -7.999, 0.001) - - @Test - fun size() { - assertEquals(3, vector.size) - } - - @Test - fun get() { - assertEquals(1.0, vector[0]) - assertEquals(-7.999, vector[1]) - assertEquals(0.001, vector[2]) - } - - @Test - fun iterator() { - assertEquals(listOf(1.0, -7.999, 0.001), vector.toList()) - } - - @Test - fun x() { - assertEquals(1.0, vector.x) - } - - @Test - fun y() { - assertEquals(-7.999, vector.y) - } - - @Test - fun z() { - assertEquals(0.001, vector.z) - } -} diff --git a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt b/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt deleted file mode 100644 index 1277c0130..000000000 --- a/kmath-geometry/src/commonTest/kotlin/space/kscience/kmath/geometry/testUtils.kt +++ /dev/null @@ -1,41 +0,0 @@ -package space.kscience.kmath.geometry - -import kotlin.math.abs -import kotlin.test.assertEquals - -fun ClosedRange.generateList(step: Double): List = generateSequence(start) { previous -> - if (previous == Double.POSITIVE_INFINITY) return@generateSequence null - val next = previous + step - if (next > endInclusive) null else next -}.toList() - -fun grid( - xRange: ClosedRange, - yRange: ClosedRange, - step: Double -): List> { - val xs = xRange.generateList(step) - val ys = yRange.generateList(step) - - return xs.flatMap { x -> ys.map { y -> x to y } } -} - -fun assertVectorEquals(expected: Vector2D, actual: Vector2D, absoluteTolerance: Double = 1e-6) { - assertEquals(expected.x, actual.x, absoluteTolerance) - assertEquals(expected.y, actual.y, absoluteTolerance) -} - -fun assertVectorEquals(expected: Vector3D, actual: Vector3D, absoluteTolerance: Double = 1e-6) { - assertEquals(expected.x, actual.x, absoluteTolerance) - assertEquals(expected.y, actual.y, absoluteTolerance) - assertEquals(expected.z, actual.z, absoluteTolerance) -} - -fun GeometrySpace.isCollinear(a: V, b: V, absoluteTolerance: Double = 1e-6): Boolean { - val aDist = a.distanceTo(zero) - val bDist = b.distanceTo(zero) - return abs(aDist) < absoluteTolerance || abs(bDist) < absoluteTolerance || abs(abs((a dot b) / (aDist * bDist)) - 1) < absoluteTolerance -} - -fun GeometrySpace.isOrthogonal(a: V, b: V, absoluteTolerance: Double = 1e-6): Boolean = - abs(a dot b) < absoluteTolerance diff --git a/kmath-histograms/build.gradle.kts b/kmath-histograms/build.gradle.kts index 7e511faa0..993bfed8e 100644 --- a/kmath-histograms/build.gradle.kts +++ b/kmath-histograms/build.gradle.kts @@ -1,26 +1,10 @@ plugins { - kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") + id("scientifik.mpp") } -kscience { - useAtomic() -} - -kotlin.sourceSets { - commonMain { - dependencies { - api(project(":kmath-core")) - } +kotlin.sourceSets.commonMain { + dependencies { + api(project(":kmath-core")) + api(project(":kmath-for-real")) } - commonTest { - dependencies { - implementation(project(":kmath-for-real")) - } - } -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE -} +} \ No newline at end of file diff --git a/kmath-histograms/src/commonMain/kotlin/scientifik/kmath/histogram/Counters.kt b/kmath-histograms/src/commonMain/kotlin/scientifik/kmath/histogram/Counters.kt new file mode 100644 index 000000000..9c7de3303 --- /dev/null +++ b/kmath-histograms/src/commonMain/kotlin/scientifik/kmath/histogram/Counters.kt @@ -0,0 +1,20 @@ +package scientifik.kmath.histogram + +/* + * Common representation for atomic counters + * TODO replace with atomics + */ + +expect class LongCounter() { + fun decrement() + fun increment() + fun reset() + fun sum(): Long + fun add(l: Long) +} + +expect class DoubleCounter() { + fun reset() + fun sum(): Double + fun add(d: Double) +} \ No newline at end of file diff --git a/kmath-histograms/src/commonMain/kotlin/scientifik/kmath/histogram/Histogram.kt b/kmath-histograms/src/commonMain/kotlin/scientifik/kmath/histogram/Histogram.kt new file mode 100644 index 000000000..329af72a1 --- /dev/null +++ b/kmath-histograms/src/commonMain/kotlin/scientifik/kmath/histogram/Histogram.kt @@ -0,0 +1,64 @@ +package scientifik.kmath.histogram + +import scientifik.kmath.linear.Point +import scientifik.kmath.structures.ArrayBuffer +import scientifik.kmath.structures.DoubleBuffer + +/** + * A simple geometric domain + * TODO move to geometry module + */ +interface Domain { + operator fun contains(vector: Point): Boolean + val dimension: Int +} + +/** + * The bin in the histogram. The histogram is by definition always done in the real space + */ +interface Bin : Domain { + /** + * The value of this bin + */ + val value: Number + val center: Point +} + +interface Histogram> : Iterable { + + /** + * Find existing bin, corresponding to given coordinates + */ + operator fun get(point: Point): B? + + /** + * Dimension of the histogram + */ + val dimension: Int + +} + +interface MutableHistogram> : Histogram { + + /** + * Increment appropriate bin + */ + fun putWithWeight(point: Point, weight: Double) + + fun put(point: Point) = putWithWeight(point, 1.0) +} + +fun MutableHistogram.put(vararg point: T) = put(ArrayBuffer(point)) + +fun MutableHistogram.put(vararg point: Number) = + put(DoubleBuffer(point.map { it.toDouble() }.toDoubleArray())) + +fun MutableHistogram.put(vararg point: Double) = put(DoubleBuffer(point)) + +fun MutableHistogram.fill(sequence: Iterable>) = sequence.forEach { put(it) } + +/** + * Pass a sequence builder into histogram + */ +fun MutableHistogram.fill(buider: suspend SequenceScope>.() -> Unit) = + fill(sequence(buider).asIterable()) \ No newline at end of file diff --git a/kmath-histograms/src/commonMain/kotlin/scientifik/kmath/histogram/RealHistogram.kt b/kmath-histograms/src/commonMain/kotlin/scientifik/kmath/histogram/RealHistogram.kt new file mode 100644 index 000000000..4438f5d60 --- /dev/null +++ b/kmath-histograms/src/commonMain/kotlin/scientifik/kmath/histogram/RealHistogram.kt @@ -0,0 +1,169 @@ +package scientifik.kmath.histogram + +import scientifik.kmath.linear.Point +import scientifik.kmath.real.asVector +import scientifik.kmath.operations.SpaceOperations +import scientifik.kmath.structures.* +import kotlin.math.floor + + +data class BinDef>(val space: SpaceOperations>, val center: Point, val sizes: Point) { + fun contains(vector: Point): Boolean { + if (vector.size != center.size) error("Dimension mismatch for input vector. Expected ${center.size}, but found ${vector.size}") + val upper = space.run { center + sizes / 2.0 } + val lower = space.run { center - sizes / 2.0 } + return vector.asSequence().mapIndexed { i, value -> + value in lower[i]..upper[i] + }.all { it } + } +} + + +class MultivariateBin>(val def: BinDef, override val value: Number) : Bin { + + override fun contains(vector: Point): Boolean = def.contains(vector) + + override val dimension: Int + get() = def.center.size + + override val center: Point + get() = def.center + +} + +/** + * Uniform multivariate histogram with fixed borders. Based on NDStructure implementation with complexity of m for bin search, where m is the number of dimensions. + */ +class RealHistogram( + private val lower: Buffer, + private val upper: Buffer, + private val binNums: IntArray = IntArray(lower.size) { 20 } +) : MutableHistogram> { + + + private val strides = DefaultStrides(IntArray(binNums.size) { binNums[it] + 2 }) + + private val values: NDStructure = NDStructure.auto(strides) { LongCounter() } + + private val weights: NDStructure = NDStructure.auto(strides) { DoubleCounter() } + + override val dimension: Int get() = lower.size + + + private val binSize = DoubleBuffer(dimension) { (upper[it] - lower[it]) / binNums[it] } + + init { + // argument checks + if (lower.size != upper.size) error("Dimension mismatch in histogram lower and upper limits.") + if (lower.size != binNums.size) error("Dimension mismatch in bin count.") + if ((0 until dimension).any { upper[it] - lower[it] < 0 }) error("Range for one of axis is not strictly positive") + } + + + /** + * Get internal [NDStructure] bin index for given axis + */ + private fun getIndex(axis: Int, value: Double): Int { + return when { + value >= upper[axis] -> binNums[axis] + 1 // overflow + value < lower[axis] -> 0 // underflow + else -> floor((value - lower[axis]) / binSize[axis]).toInt() + 1 + } + } + + private fun getIndex(point: Buffer): IntArray = IntArray(dimension) { getIndex(it, point[it]) } + + private fun getValue(index: IntArray): Long { + return values[index].sum() + } + + fun getValue(point: Buffer): Long { + return getValue(getIndex(point)) + } + + private fun getDef(index: IntArray): BinDef { + val center = index.mapIndexed { axis, i -> + when (i) { + 0 -> Double.NEGATIVE_INFINITY + strides.shape[axis] - 1 -> Double.POSITIVE_INFINITY + else -> lower[axis] + (i.toDouble() - 0.5) * binSize[axis] + } + }.asBuffer() + return BinDef(RealBufferFieldOperations, center, binSize) + } + + fun getDef(point: Buffer): BinDef { + return getDef(getIndex(point)) + } + + override fun get(point: Buffer): MultivariateBin? { + val index = getIndex(point) + return MultivariateBin(getDef(index), getValue(index)) + } + +// fun put(point: Point){ +// val index = getIndex(point) +// values[index].increment() +// } + + override fun putWithWeight(point: Buffer, weight: Double) { + val index = getIndex(point) + values[index].increment() + weights[index].add(weight) + } + + override fun iterator(): Iterator> = weights.elements().map { (index, value) -> + MultivariateBin(getDef(index), value.sum()) + }.iterator() + + /** + * Convert this histogram into NDStructure containing bin values but not bin descriptions + */ + fun values(): NDStructure { + return NDStructure.auto(values.shape) { values[it].sum() } + } + + /** + * Sum of weights + */ + fun weights():NDStructure{ + return NDStructure.auto(weights.shape) { weights[it].sum() } + } + + companion object { + + /** + * Use it like + * ``` + *FastHistogram.fromRanges( + * (-1.0..1.0), + * (-1.0..1.0) + *) + *``` + */ + fun fromRanges(vararg ranges: ClosedFloatingPointRange): RealHistogram { + return RealHistogram( + ranges.map { it.start }.asVector(), + ranges.map { it.endInclusive }.asVector() + ) + } + + /** + * Use it like + * ``` + *FastHistogram.fromRanges( + * (-1.0..1.0) to 50, + * (-1.0..1.0) to 32 + *) + *``` + */ + fun fromRanges(vararg ranges: Pair, Int>): RealHistogram { + return RealHistogram( + ListBuffer(ranges.map { it.first.start }), + ListBuffer(ranges.map { it.first.endInclusive }), + ranges.map { it.second }.toIntArray() + ) + } + } + +} \ No newline at end of file diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt deleted file mode 100644 index 4f5a1ceba..000000000 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Counter.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.histogram - -import kotlinx.atomicfu.atomic -import kotlinx.atomicfu.getAndUpdate -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.Ring - -/** - * Common representation for atomic counters - */ -public interface Counter { - public fun add(delta: T) - public val value: T - - public companion object { - public fun real(): ObjectCounter = ObjectCounter(DoubleField) - } -} - -public class IntCounter : Counter { - private val innerValue = atomic(0) - - override fun add(delta: Int) { - innerValue += delta - } - - override val value: Int get() = innerValue.value -} - -public class LongCounter : Counter { - private val innerValue = atomic(0L) - - override fun add(delta: Long) { - innerValue += delta - } - - override val value: Long get() = innerValue.value -} - -public class ObjectCounter(public val group: Ring) : Counter { - private val innerValue = atomic(group.zero) - - override fun add(delta: T) { - innerValue.getAndUpdate { group.run { it + delta } } - } - - override val value: T get() = innerValue.value -} - - diff --git a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt b/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt deleted file mode 100644 index 27b14b65e..000000000 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/DoubleHistogramSpace.kt +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.histogram - -import space.kscience.kmath.domains.Domain -import space.kscience.kmath.domains.HyperSquareDomain -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.* -import space.kscience.kmath.structures.* -import kotlin.math.floor - -public class DoubleHistogramSpace( - private val lower: Buffer, - private val upper: Buffer, - private val binNums: IntArray = IntArray(lower.size) { 20 }, -) : IndexedHistogramSpace { - - init { - // argument checks - require(lower.size == upper.size) { "Dimension mismatch in histogram lower and upper limits." } - require(lower.size == binNums.size) { "Dimension mismatch in bin count." } - require(!lower.indices.any { upper[it] - lower[it] < 0 }) { "Range for one of axis is not strictly positive" } - } - - public val dimension: Int get() = lower.size - - private val shape = IntArray(binNums.size) { binNums[it] + 2 } - override val histogramValueSpace: DoubleFieldND = AlgebraND.real(*shape) - - override val strides: Strides get() = histogramValueSpace.strides - private val binSize = DoubleBuffer(dimension) { (upper[it] - lower[it]) / binNums[it] } - - /** - * Get internal [StructureND] bin index for given axis - */ - private fun getIndex(axis: Int, value: Double): Int = when { - value >= upper[axis] -> binNums[axis] + 1 // overflow - value < lower[axis] -> 0 // underflow - else -> floor((value - lower[axis]) / binSize[axis]).toInt() - } - - override fun getIndex(point: Buffer): IntArray = IntArray(dimension) { - getIndex(it, point[it]) - } - - @OptIn(UnstableKMathAPI::class) - override fun getDomain(index: IntArray): Domain { - val lowerBoundary = index.mapIndexed { axis, i -> - when (i) { - 0 -> Double.NEGATIVE_INFINITY - strides.shape[axis] - 1 -> upper[axis] - else -> lower[axis] + (i.toDouble()) * binSize[axis] - } - }.asBuffer() - - val upperBoundary = index.mapIndexed { axis, i -> - when (i) { - 0 -> lower[axis] - strides.shape[axis] - 1 -> Double.POSITIVE_INFINITY - else -> lower[axis] + (i.toDouble() + 1) * binSize[axis] - } - }.asBuffer() - - return HyperSquareDomain(lowerBoundary, upperBoundary) - } - - - override fun produceBin(index: IntArray, value: Double): Bin { - val domain = getDomain(index) - return DomainBin(domain, value) - } - - override fun produce(builder: HistogramBuilder.() -> Unit): IndexedHistogram { - val ndCounter = StructureND.auto(strides) { Counter.real() } - val hBuilder = HistogramBuilder { point, value -> - val index = getIndex(point) - ndCounter[index].add(value.toDouble()) - } - hBuilder.apply(builder) - val values: BufferND = ndCounter.mapToBuffer { it.value } - return IndexedHistogram(this, values) - } - - override fun IndexedHistogram.unaryMinus(): IndexedHistogram = this * (-1) - - public companion object { - /** - * Use it like - * ``` - *FastHistogram.fromRanges( - * (-1.0..1.0), - * (-1.0..1.0) - *) - *``` - */ - public fun fromRanges(vararg ranges: ClosedFloatingPointRange): DoubleHistogramSpace = DoubleHistogramSpace( - ranges.map(ClosedFloatingPointRange::start).asBuffer(), - ranges.map(ClosedFloatingPointRange::endInclusive).asBuffer() - ) - - /** - * Use it like - * ``` - *FastHistogram.fromRanges( - * (-1.0..1.0) to 50, - * (-1.0..1.0) to 32 - *) - *``` - */ - public fun fromRanges(vararg ranges: Pair, Int>): DoubleHistogramSpace = - DoubleHistogramSpace( - ListBuffer( - ranges - .map(Pair, Int>::first) - .map(ClosedFloatingPointRange::start) - ), - - ListBuffer( - ranges - .map(Pair, Int>::first) - .map(ClosedFloatingPointRange::endInclusive) - ), - - ranges.map(Pair, Int>::second).toIntArray() - ) - } -} \ No newline at end of file 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 deleted file mode 100644 index 946aa814b..000000000 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/Histogram.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.histogram - -import space.kscience.kmath.domains.Domain -import space.kscience.kmath.linear.Point -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. - */ -public interface Bin : Domain { - /** - * The value of this bin. - */ - public val value: Number -} - -public interface Histogram> { - /** - * Find existing bin, corresponding to given coordinates - */ - public operator fun get(point: Point): B? - - /** - * Dimension of the histogram - */ - public val dimension: Int - - public val bins: Iterable -} - -public fun interface HistogramBuilder { - - /** - * Increment appropriate bin - */ - public fun putValue(point: Point, value: Number) - -} - -public fun > HistogramBuilder.put(point: Point): Unit = putValue(point, 1.0) - -public fun HistogramBuilder.put(vararg point: T): Unit = put(point.asBuffer()) - -public fun HistogramBuilder.put(vararg point: Number): Unit = - put(DoubleBuffer(point.map { it.toDouble() }.toDoubleArray())) - -public fun HistogramBuilder.put(vararg point: Double): Unit = put(DoubleBuffer(point)) -public fun HistogramBuilder.fill(sequence: Iterable>): Unit = sequence.forEach { put(it) } - -/** - * Pass a sequence builder into histogram - */ -public fun HistogramBuilder.fill(block: suspend SequenceScope>.() -> Unit): Unit = - fill(sequence(block).asIterable()) 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 deleted file mode 100644 index 44f3072d2..000000000 --- a/kmath-histograms/src/commonMain/kotlin/space/kscience/kmath/histogram/IndexedHistogramSpace.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.histogram - -import space.kscience.kmath.domains.Domain -import space.kscience.kmath.linear.Point -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.FieldND -import space.kscience.kmath.nd.Strides -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.Group -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.operations.invoke - -/** - * A simple histogram bin based on domain - */ -public data class DomainBin>( - public val domain: Domain, - override val value: Number, -) : Bin, Domain by domain - -@OptIn(UnstableKMathAPI::class) -public class IndexedHistogram, V : Any>( - public val context: IndexedHistogramSpace, - public val values: StructureND, -) : Histogram> { - - override fun get(point: Point): Bin? { - val index = context.getIndex(point) ?: return null - return context.produceBin(index, values[index]) - } - - override val dimension: Int get() = context.strides.shape.size - - override val bins: Iterable> - get() = context.strides.indices().map { - context.produceBin(it, values[it]) - }.asIterable() - -} - -/** - * A space for producing histograms with values in a NDStructure - */ -public interface IndexedHistogramSpace, V : Any> - : Group>, ScaleOperations> { - //public val valueSpace: Space - public val strides: Strides - public val histogramValueSpace: FieldND //= NDAlgebra.space(valueSpace, Buffer.Companion::boxing, *shape), - - /** - * Resolve index of the bin including given [point] - */ - public fun getIndex(point: Point): IntArray? - - /** - * Get a bin domain represented by given index - */ - public fun getDomain(index: IntArray): Domain? - - public fun produceBin(index: IntArray, value: V): Bin - - public fun produce(builder: HistogramBuilder.() -> Unit): IndexedHistogram - - override fun add(a: IndexedHistogram, b: IndexedHistogram): IndexedHistogram { - require(a.context == this) { "Can't operate on a histogram produced by external space" } - require(b.context == this) { "Can't operate on a histogram produced by external space" } - return IndexedHistogram(this, histogramValueSpace { a.values + b.values }) - } - - override fun scale(a: IndexedHistogram, value: Double): IndexedHistogram { - require(a.context == this) { "Can't operate on a histogram produced by external space" } - return IndexedHistogram(this, histogramValueSpace { a.values * value }) - } - - override val zero: IndexedHistogram get() = produce { } -} - diff --git a/kmath-histograms/src/commonTest/kotlin/scietifik/kmath/histogram/MultivariateHistogramTest.kt b/kmath-histograms/src/commonTest/kotlin/scietifik/kmath/histogram/MultivariateHistogramTest.kt new file mode 100644 index 000000000..5edecb5a5 --- /dev/null +++ b/kmath-histograms/src/commonTest/kotlin/scietifik/kmath/histogram/MultivariateHistogramTest.kt @@ -0,0 +1,47 @@ +package scietifik.kmath.histogram + +import scientifik.kmath.histogram.RealHistogram +import scientifik.kmath.histogram.fill +import scientifik.kmath.histogram.put +import scientifik.kmath.real.RealVector +import kotlin.random.Random +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class MultivariateHistogramTest { + @Test + fun testSinglePutHistogram() { + val histogram = RealHistogram.fromRanges( + (-1.0..1.0), + (-1.0..1.0) + ) + histogram.put(0.55, 0.55) + val bin = histogram.find { it.value.toInt() > 0 }!! + assertTrue { bin.contains(RealVector(0.55, 0.55)) } + assertTrue { bin.contains(RealVector(0.6, 0.5)) } + assertFalse { bin.contains(RealVector(-0.55, 0.55)) } + } + + @Test + fun testSequentialPut() { + val histogram = RealHistogram.fromRanges( + (-1.0..1.0), + (-1.0..1.0), + (-1.0..1.0) + ) + val random = Random(1234) + + fun nextDouble() = random.nextDouble(-1.0, 1.0) + + val n = 10000 + + histogram.fill { + repeat(n) { + yield(RealVector(nextDouble(), nextDouble(), nextDouble())) + } + } + assertEquals(n, histogram.sumBy { it.value.toInt() }) + } +} \ No newline at end of file diff --git a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt b/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt deleted file mode 100644 index c797eb65a..000000000 --- a/kmath-histograms/src/commonTest/kotlin/space/kscience/kmath/histogram/MultivariateHistogramTest.kt +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.histogram - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.real.DoubleVector -import kotlin.random.Random -import kotlin.test.* - -internal class MultivariateHistogramTest { - @Test - fun testSinglePutHistogram() { - val hSpace = DoubleHistogramSpace.fromRanges( - (-1.0..1.0), - (-1.0..1.0) - ) - val histogram = hSpace.produce { - put(0.55, 0.55) - } - val bin = histogram.bins.find { it.value.toInt() > 0 } ?: fail() - assertTrue { bin.contains(DoubleVector(0.55, 0.55)) } - assertTrue { bin.contains(DoubleVector(0.6, 0.5)) } - assertFalse { bin.contains(DoubleVector(-0.55, 0.55)) } - } - - @Test - fun testSequentialPut() { - val hSpace = DoubleHistogramSpace.fromRanges( - (-1.0..1.0), - (-1.0..1.0), - (-1.0..1.0) - ) - val random = Random(1234) - - fun nextDouble() = random.nextDouble(-1.0, 1.0) - - val n = 10000 - val histogram = hSpace.produce { - repeat(n) { - put(nextDouble(), nextDouble(), nextDouble()) - } - } - assertEquals(n, histogram.bins.sumOf { it.value.toInt() }) - } - - @Test - fun testHistogramAlgebra() { - DoubleHistogramSpace.fromRanges( - (-1.0..1.0), - (-1.0..1.0), - (-1.0..1.0) - ).invoke { - val random = Random(1234) - - fun nextDouble() = random.nextDouble(-1.0, 1.0) - val n = 10000 - val histogram1 = produce { - repeat(n) { - put(nextDouble(), nextDouble(), nextDouble()) - } - } - val histogram2 = produce { - repeat(n) { - put(nextDouble(), nextDouble(), nextDouble()) - } - } - val res = histogram1 - histogram2 - assertTrue { - strides.indices().all { index -> - res.values[index] <= histogram1.values[index] - } - } - assertTrue { - res.bins.count() >= histogram1.bins.count() - } - assertEquals(0.0, res.bins.sumOf { it.value.toDouble() }) - } - } -} \ No newline at end of file diff --git a/kmath-histograms/src/jsMain/kotlin/scientifik/kmath/histogram/Counters.kt b/kmath-histograms/src/jsMain/kotlin/scientifik/kmath/histogram/Counters.kt new file mode 100644 index 000000000..3765220b9 --- /dev/null +++ b/kmath-histograms/src/jsMain/kotlin/scientifik/kmath/histogram/Counters.kt @@ -0,0 +1,33 @@ +package scientifik.kmath.histogram + +actual class LongCounter { + private var sum: Long = 0 + actual fun decrement() { + sum-- + } + + actual fun increment() { + sum++ + } + + actual fun reset() { + sum = 0 + } + + actual fun sum(): Long = sum + actual fun add(l: Long) { + sum += l + } +} + +actual class DoubleCounter { + private var sum: Double = 0.0 + actual fun reset() { + sum = 0.0 + } + + actual fun sum(): Double = sum + actual fun add(d: Double) { + sum += d + } +} \ No newline at end of file diff --git a/kmath-histograms/src/jvmMain/kotlin/scientifik/kmath/histogram/Counters.kt b/kmath-histograms/src/jvmMain/kotlin/scientifik/kmath/histogram/Counters.kt new file mode 100644 index 000000000..bb3667f7d --- /dev/null +++ b/kmath-histograms/src/jvmMain/kotlin/scientifik/kmath/histogram/Counters.kt @@ -0,0 +1,7 @@ +package scientifik.kmath.histogram + +import java.util.concurrent.atomic.DoubleAdder +import java.util.concurrent.atomic.LongAdder + +actual typealias LongCounter = LongAdder +actual typealias DoubleCounter = DoubleAdder \ No newline at end of file diff --git a/kmath-histograms/src/jvmMain/kotlin/scientifik/kmath/histogram/UnivariateHistogram.kt b/kmath-histograms/src/jvmMain/kotlin/scientifik/kmath/histogram/UnivariateHistogram.kt new file mode 100644 index 000000000..dcc5ac0eb --- /dev/null +++ b/kmath-histograms/src/jvmMain/kotlin/scientifik/kmath/histogram/UnivariateHistogram.kt @@ -0,0 +1,99 @@ +package scientifik.kmath.histogram + +import scientifik.kmath.real.RealVector +import scientifik.kmath.real.asVector +import scientifik.kmath.structures.Buffer +import java.util.* +import kotlin.math.floor + +//TODO move to common + +class UnivariateBin(val position: Double, val size: Double, val counter: LongCounter = LongCounter()) : Bin { + //TODO add weighting + override val value: Number get() = counter.sum() + + override val center: RealVector get() = doubleArrayOf(position).asVector() + + operator fun contains(value: Double): Boolean = value in (position - size / 2)..(position + size / 2) + + override fun contains(vector: Buffer): Boolean = contains(vector[0]) + + internal operator fun inc() = this.also { counter.increment() } + + override val dimension: Int get() = 1 +} + +/** + * Univariate histogram with log(n) bin search speed + */ +class UnivariateHistogram private constructor(private val factory: (Double) -> UnivariateBin) : + MutableHistogram { + + private val bins: TreeMap = TreeMap() + + private operator fun get(value: Double): UnivariateBin? { + // check ceiling entry and return it if it is what needed + val ceil = bins.ceilingEntry(value)?.value + if (ceil != null && value in ceil) return ceil + //check floor entry + val floor = bins.floorEntry(value)?.value + if (floor != null && value in floor) return floor + //neither is valid, not found + return null + } + + private fun createBin(value: Double): UnivariateBin = factory(value).also { + synchronized(this) { bins.put(it.position, it) } + } + + override fun get(point: Buffer): UnivariateBin? = get(point[0]) + + override val dimension: Int get() = 1 + + override fun iterator(): Iterator = bins.values.iterator() + + /** + * Thread safe put operation + */ + fun put(value: Double) { + (get(value) ?: createBin(value)).inc() + } + + override fun putWithWeight(point: Buffer, weight: Double) { + if (weight != 1.0) TODO("Implement weighting") + put(point[0]) + } + + companion object { + fun uniform(binSize: Double, start: Double = 0.0): UnivariateHistogram { + return UnivariateHistogram { value -> + val center = start + binSize * floor((value - start) / binSize + 0.5) + UnivariateBin(center, binSize) + } + } + + fun custom(borders: DoubleArray): UnivariateHistogram { + val sorted = borders.sortedArray() + return UnivariateHistogram { value -> + when { + value < sorted.first() -> UnivariateBin( + Double.NEGATIVE_INFINITY, + Double.MAX_VALUE + ) + value > sorted.last() -> UnivariateBin( + Double.POSITIVE_INFINITY, + Double.MAX_VALUE + ) + else -> { + val index = (0 until sorted.size).first { value > sorted[it] } + val left = sorted[index] + val right = sorted[index + 1] + UnivariateBin((left + right) / 2, (right - left)) + } + } + } + } + } +} + +fun UnivariateHistogram.fill(sequence: Iterable) = sequence.forEach { put(it) } 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 deleted file mode 100644 index 96f945f6a..000000000 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/TreeHistogramSpace.kt +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.histogram - -import space.kscience.kmath.domains.UnivariateDomain -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.Group -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.structures.Buffer -import java.util.* -import kotlin.math.abs -import kotlin.math.floor -import kotlin.math.sqrt - -private fun > TreeMap.getBin(value: Double): B? { - // check ceiling entry and return it if it is what needed - val ceil = ceilingEntry(value)?.value - if (ceil != null && value in ceil) return ceil - //check floor entry - val floor = floorEntry(value)?.value - if (floor != null && value in floor) return floor - //neither is valid, not found - return null -} - -@UnstableKMathAPI -public class TreeHistogram( - private val binMap: TreeMap, -) : UnivariateHistogram { - override fun get(value: Double): UnivariateBin? = binMap.getBin(value) - override val dimension: Int get() = 1 - 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( - @PublishedApi internal val binFactory: (Double) -> UnivariateDomain, -) : Group, ScaleOperations { - - public inline fun fill(block: UnivariateHistogramBuilder.() -> Unit): UnivariateHistogram = - TreeHistogramBuilder(binFactory).apply(block).build() - - override fun add( - a: UnivariateHistogram, - b: UnivariateHistogram, - ): UnivariateHistogram { -// require(a.context == this) { "Histogram $a does not belong to this context" } -// require(b.context == this) { "Histogram $b does not belong to this context" } - val bins = TreeMap().apply { - (a.bins.map { it.domain } union b.bins.map { it.domain }).forEach { def -> - put( - def.center, - UnivariateBin( - def, - value = (a[def.center]?.value ?: 0.0) + (b[def.center]?.value ?: 0.0), - standardDeviation = (a[def.center]?.standardDeviation - ?: 0.0) + (b[def.center]?.standardDeviation ?: 0.0) - ) - ) - } - } - return TreeHistogram(bins) - } - - override fun scale(a: UnivariateHistogram, value: Double): UnivariateHistogram { - val bins = TreeMap().apply { - a.bins.forEach { bin -> - put( - bin.domain.center, - UnivariateBin( - bin.domain, - value = bin.value * value, - standardDeviation = abs(bin.standardDeviation * value) - ) - ) - } - } - - return TreeHistogram(bins) - } - - override fun UnivariateHistogram.unaryMinus(): UnivariateHistogram = this * (-1) - - override val zero: UnivariateHistogram by lazy { fill { } } - - public companion object { - /** - * Build and fill a [UnivariateHistogram]. Returns a read-only histogram. - */ - public fun uniform( - binSize: Double, - start: Double = 0.0, - ): TreeHistogramSpace = TreeHistogramSpace { value -> - val center = start + binSize * floor((value - start) / binSize + 0.5) - UnivariateDomain((center - binSize / 2)..(center + binSize / 2)) - } - - /** - * Create a histogram with custom cell borders - */ - public fun custom(borders: DoubleArray): TreeHistogramSpace { - val sorted = borders.sortedArray() - - return TreeHistogramSpace { value -> - when { - value < sorted.first() -> UnivariateDomain( - Double.NEGATIVE_INFINITY..sorted.first() - ) - - value > sorted.last() -> UnivariateDomain( - sorted.last()..Double.POSITIVE_INFINITY - ) - - else -> { - val index = sorted.indices.first { value > sorted[it] } - val left = sorted[index] - val right = sorted[index + 1] - UnivariateDomain(left..right) - } - } - } - } - } -} \ No newline at end of file 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 deleted file mode 100644 index 0841fcb4c..000000000 --- a/kmath-histograms/src/jvmMain/kotlin/space/kscience/kmath/histogram/UnivariateHistogram.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.histogram - -import space.kscience.kmath.domains.UnivariateDomain -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asSequence - - -@UnstableKMathAPI -public val UnivariateDomain.center: Double - get() = (range.endInclusive + range.start) / 2 - -/** - * 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( - public val domain: UnivariateDomain, - override val value: Double, - public val standardDeviation: Double, -) : Bin, ClosedFloatingPointRange by domain.range { - - override val dimension: Int get() = 1 - - 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? - override operator fun get(point: Buffer): UnivariateBin? = get(point[0]) - - public companion object { - /** - * Build and fill a [UnivariateHistogram]. Returns a read-only histogram. - */ - public fun uniform( - binSize: Double, - start: Double = 0.0, - builder: UnivariateHistogramBuilder.() -> Unit, - ): UnivariateHistogram = TreeHistogramSpace.uniform(binSize, start).fill(builder) - - /** - * Build and fill a histogram with custom borders. Returns a read-only histogram. - */ - public fun custom( - borders: DoubleArray, - builder: UnivariateHistogramBuilder.() -> Unit, - ): UnivariateHistogram = TreeHistogramSpace.custom(borders).fill(builder) - - } -} - -@UnstableKMathAPI -public interface UnivariateHistogramBuilder : HistogramBuilder { - /** - * Thread safe put operation - */ - public fun putValue(at: Double, value: Double = 1.0) - - override fun putValue(point: Buffer, value: Number) -} - -@UnstableKMathAPI -public fun UnivariateHistogramBuilder.fill(items: Iterable): Unit = items.forEach(this::putValue) - -@UnstableKMathAPI -public fun UnivariateHistogramBuilder.fill(array: DoubleArray): Unit = array.forEach(this::putValue) - -@UnstableKMathAPI -public fun UnivariateHistogramBuilder.fill(buffer: Buffer): Unit = buffer.asSequence().forEach(this::putValue) \ No newline at end of file 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 deleted file mode 100644 index e71602c7b..000000000 --- a/kmath-histograms/src/jvmTest/kotlin/space/kscience/kmath/histogram/TreeHistogramTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.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 deleted file mode 100644 index 3c5d4e19d..000000000 --- a/kmath-jafama/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# 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 deleted file mode 100644 index 9cf328d0b..000000000 --- a/kmath-jafama/build.gradle.kts +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index 54348467b..000000000 --- a/kmath-jafama/docs/README-TEMPLATE.md +++ /dev/null @@ -1,29 +0,0 @@ -# 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 deleted file mode 100644 index 1a6e3325b..000000000 --- a/kmath-jafama/src/main/kotlin/space/kscience/kmath/jafama/KMathJafama.kt +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.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 deleted file mode 100644 index 5bd08c485..000000000 --- a/kmath-jupyter/build.gradle.kts +++ /dev/null @@ -1,26 +0,0 @@ -plugins { - id("ru.mipt.npm.gradle.jvm") - kotlin("jupyter.api") -} - -dependencies { - api(project(":kmath-ast")) - api(project(":kmath-complex")) - api(project(":kmath-for-real")) -} - -kscience{ - useHtml() -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE -} - -kotlin.sourceSets.all { - languageSettings.useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI") -} - -tasks.processJupyterApiResources { - libraryProducers = listOf("space.kscience.kmath.jupyter.KMathJupyter") -} diff --git a/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt b/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt deleted file mode 100644 index d7438bf0f..000000000 --- a/kmath-jupyter/src/main/kotlin/space/kscience/kmath/jupyter/KMathJupyter.kt +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.jupyter - -import kotlinx.html.Unsafe -import kotlinx.html.div -import kotlinx.html.stream.createHTML -import kotlinx.html.unsafe -import org.jetbrains.kotlinx.jupyter.api.DisplayResult -import org.jetbrains.kotlinx.jupyter.api.HTML -import org.jetbrains.kotlinx.jupyter.api.annotations.JupyterLibrary -import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration -import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess -import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer -import space.kscience.kmath.ast.rendering.renderWithStringBuilder -import space.kscience.kmath.complex.Complex -import space.kscience.kmath.complex.Quaternion -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.MstRing -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.Structure2D -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asSequence - -/** - * A function for conversion of number to MST for pretty print - */ -public fun Number.toMst(): MST.Numeric = MST.Numeric(this) - -internal class KMathJupyter : JupyterIntegration() { - private val mathRender = FeaturedMathRendererWithPostProcess.Default - private val syntaxRender = MathMLSyntaxRenderer - - private fun MST.toDisplayResult(): DisplayResult = HTML(createHTML().div { - unsafe { - +syntaxRender.renderWithStringBuilder(mathRender.render(this@toDisplayResult)) - } - }) - - private fun Unsafe.appendCellValue(it: Any?) { - when (it) { - is Number -> { - val s = StringBuilder() - syntaxRender.renderPart(mathRender.render(MST.Numeric(it)), s) - +s.toString() - } - is MST -> { - val s = StringBuilder() - syntaxRender.renderPart(mathRender.render(it), s) - +s.toString() - } - else -> { - +"" - +it.toString() - +"" - } - } - } - - @OptIn(PerformancePitfall::class) - override fun Builder.onLoaded() { - import( - "space.kscience.kmath.ast.*", - "space.kscience.kmath.ast.rendering.*", - "space.kscience.kmath.structures.*", - "space.kscience.kmath.operations.*", - "space.kscience.kmath.expressions.*", - "space.kscience.kmath.nd.*", - "space.kscience.kmath.misc.*", - "space.kscience.kmath.real.*", - ) - - import("space.kscience.kmath.jupyter.toMst") - - render { it.toDisplayResult() } - //render { MST.Numeric(it).toDisplayResult() } - - render> { structure -> - HTML(createHTML().div { - unsafe { - +"" - +"" - +"" - +"" - structure.rows.forEach { row -> - +"" - row.asSequence().forEach { - +"" - appendCellValue(it) - +"" - } - +"" - } - +"" - +"" - +"" - +"" - } - }) - } - - render> { buffer -> - HTML(createHTML().div { - unsafe { - +"" - +"" - +"" - +"" - buffer.asSequence().forEach { - +"" - +"" - appendCellValue(it) - +"" - +"" - } - +"" - +"" - +"" - +"" - } - }) - } - - render { - MstRing { - number(it.re) + number(it.im) * bindSymbol("i") - }.toDisplayResult() - } - - render { - MstRing { - number(it.w) + - number(it.x) * bindSymbol("i") + - number(it.x) * bindSymbol("j") + - number(it.x) * bindSymbol("k") - }.toDisplayResult() - } - } -} diff --git a/kmath-koma/build.gradle.kts b/kmath-koma/build.gradle.kts new file mode 100644 index 000000000..26955bca7 --- /dev/null +++ b/kmath-koma/build.gradle.kts @@ -0,0 +1,31 @@ +plugins { + id("scientifik.mpp") +} + +repositories { + maven("http://dl.bintray.com/kyonifer/maven") +} + +kotlin.sourceSets { + commonMain { + dependencies { + api(project(":kmath-core")) + api("com.kyonifer:koma-core-api-common:0.12") + } + } + jvmMain { + dependencies { + api("com.kyonifer:koma-core-api-jvm:0.12") + } + } + jvmTest { + dependencies { + implementation("com.kyonifer:koma-core-ejml:0.12") + } + } + jsMain { + dependencies { + api("com.kyonifer:koma-core-api-js:0.12") + } + } +} diff --git a/kmath-koma/src/commonMain/kotlin/scientifik.kmath.linear/KomaMatrix.kt b/kmath-koma/src/commonMain/kotlin/scientifik.kmath.linear/KomaMatrix.kt new file mode 100644 index 000000000..10deabd73 --- /dev/null +++ b/kmath-koma/src/commonMain/kotlin/scientifik.kmath.linear/KomaMatrix.kt @@ -0,0 +1,114 @@ +package scientifik.kmath.linear + +import koma.extensions.fill +import koma.matrix.MatrixFactory +import scientifik.kmath.operations.Space +import scientifik.kmath.structures.Matrix +import scientifik.kmath.structures.NDStructure + +class KomaMatrixContext( + private val factory: MatrixFactory>, + private val space: Space +) : + MatrixContext { + + override fun produce(rows: Int, columns: Int, initializer: (i: Int, j: Int) -> T) = + KomaMatrix(factory.zeros(rows, columns).fill(initializer)) + + fun Matrix.toKoma(): KomaMatrix = if (this is KomaMatrix) { + this + } else { + produce(rowNum, colNum) { i, j -> get(i, j) } + } + + fun Point.toKoma(): KomaVector = if (this is KomaVector) { + this + } else { + KomaVector(factory.zeros(size, 1).fill { i, _ -> get(i) }) + } + + + override fun Matrix.dot(other: Matrix) = + KomaMatrix(this.toKoma().origin * other.toKoma().origin) + + override fun Matrix.dot(vector: Point) = + KomaVector(this.toKoma().origin * vector.toKoma().origin) + + override fun Matrix.unaryMinus() = + KomaMatrix(this.toKoma().origin.unaryMinus()) + + override fun add(a: Matrix, b: Matrix) = + KomaMatrix(a.toKoma().origin + b.toKoma().origin) + + override fun Matrix.minus(b: Matrix) = + KomaMatrix(this.toKoma().origin - b.toKoma().origin) + + override fun multiply(a: Matrix, k: Number): Matrix = + produce(a.rowNum, a.colNum) { i, j -> space.run { a[i, j] * k } } + + override fun Matrix.times(value: T) = + KomaMatrix(this.toKoma().origin * value) + + companion object { + + } + +} + +fun KomaMatrixContext.solve(a: Matrix, b: Matrix) = + KomaMatrix(a.toKoma().origin.solve(b.toKoma().origin)) + +fun KomaMatrixContext.solve(a: Matrix, b: Point) = + KomaVector(a.toKoma().origin.solve(b.toKoma().origin)) + +fun KomaMatrixContext.inverse(a: Matrix) = + KomaMatrix(a.toKoma().origin.inv()) + +class KomaMatrix(val origin: koma.matrix.Matrix, features: Set? = null) : FeaturedMatrix { + override val rowNum: Int get() = origin.numRows() + override val colNum: Int get() = origin.numCols() + + override val shape: IntArray get() = intArrayOf(origin.numRows(), origin.numCols()) + + override val features: Set = features ?: setOf( + object : DeterminantFeature { + override val determinant: T get() = origin.det() + }, + object : LUPDecompositionFeature { + private val lup by lazy { origin.LU() } + override val l: FeaturedMatrix get() = KomaMatrix(lup.second) + override val u: FeaturedMatrix get() = KomaMatrix(lup.third) + override val p: FeaturedMatrix get() = KomaMatrix(lup.first) + } + ) + + override fun suggestFeature(vararg features: MatrixFeature): FeaturedMatrix = + KomaMatrix(this.origin, this.features + features) + + override fun get(i: Int, j: Int): T = origin.getGeneric(i, j) + + override fun equals(other: Any?): Boolean { + return NDStructure.equals(this, other as? NDStructure<*> ?: return false) + } + + override fun hashCode(): Int { + var result = origin.hashCode() + result = 31 * result + features.hashCode() + return result + } + + +} + +class KomaVector internal constructor(val origin: koma.matrix.Matrix) : Point { + init { + if (origin.numCols() != 1) error("Only single column matrices are allowed") + } + + override val size: Int get() = origin.numRows() + + override fun get(index: Int): T = origin.getGeneric(index) + + override fun iterator(): Iterator = origin.toIterable().iterator() +} + diff --git a/kmath-kotlingrad/README.md b/kmath-kotlingrad/README.md deleted file mode 100644 index aeb44ea13..000000000 --- a/kmath-kotlingrad/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Module kmath-kotlingrad - -[Kotlin∇](https://github.com/breandan/kotlingrad) integration module. - - - [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-14`. - -**Gradle:** -```gradle -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-kotlingrad:0.3.0-dev-14' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-kotlingrad:0.3.0-dev-14") -} -``` diff --git a/kmath-kotlingrad/build.gradle.kts b/kmath-kotlingrad/build.gradle.kts deleted file mode 100644 index d222ed7d6..000000000 --- a/kmath-kotlingrad/build.gradle.kts +++ /dev/null @@ -1,32 +0,0 @@ -plugins { - kotlin("jvm") - id("ru.mipt.npm.gradle.common") -} - -description = "Kotlin∇ integration module" - -dependencies { - api("com.github.breandan:kaliningraph:0.1.6") - api("com.github.breandan:kotlingrad:0.4.5") - api(project(":kmath-core")) - testImplementation(project(":kmath-ast")) -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL - propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) - - feature( - "differentiable-mst-expression", - "src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt", - ) { - "MST based DifferentiableExpression." - } - - feature( - "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 deleted file mode 100644 index bc99bdf5f..000000000 --- a/kmath-kotlingrad/docs/README-TEMPLATE.md +++ /dev/null @@ -1,7 +0,0 @@ -# Module kmath-kotlingrad - -[Kotlin∇](https://github.com/breandan/kotlingrad) integration module. - -${features} - -${artifact} 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 deleted file mode 100644 index 0f10c6cdd..000000000 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KMathNumber.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.kotlingrad - -import edu.umontreal.kotlingrad.api.SConst -import space.kscience.kmath.operations.NumericAlgebra - -/** - * Implements [SConst] by delegating its functionality to [NumericAlgebra]. - * - * @param T The type of number. - * @param A The [NumericAlgebra] over [T]. - * @property algebra The algebra. - * @property value The value of this number. - */ -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]. - */ - override fun toString(): String = value.toString() - - /** - * Wraps [Number] to [KMathNumber]. - */ - 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 deleted file mode 100644 index 06214ca1a..000000000 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/KotlingradExpression.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.kotlingrad - -import edu.umontreal.kotlingrad.api.SFun -import edu.umontreal.kotlingrad.api.SVar -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.NumericAlgebra - -/** - * Represents [MST] based [DifferentiableExpression] relying on [Kotlin∇](https://github.com/breandan/kotlingrad). - * - * The principle of this API is converting the [mst] to an [SFun], differentiating it with Kotlin∇, then converting - * [SFun] 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 KotlingradExpression>( - public val algebra: A, - public val mst: MST, -) : SpecialDifferentiableExpression> { - override fun invoke(arguments: Map): T = mst.interpret(algebra, arguments) - - override fun derivativeOrNull(symbols: List): KotlingradExpression = - KotlingradExpression( - algebra, - symbols.map(Symbol::identity) - .map(MstNumericAlgebra::bindSymbol) - .map>>(Symbol::toSVar) - .fold(mst.toSFun(), SFun>::d) - .toMst(), - ) -} - -/** - * 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/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt b/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt deleted file mode 100644 index 857824275..000000000 --- a/kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/scalarsAdapters.kt +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.kotlingrad - -import edu.umontreal.kotlingrad.api.* -import space.kscience.kmath.expressions.MST -import space.kscience.kmath.expressions.MstExtendedField -import space.kscience.kmath.expressions.MstExtendedField.unaryMinus -import space.kscience.kmath.expressions.MstNumericAlgebra -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.operations.* - -/** - * Maps [SVar] to [Symbol] directly. - * - * @receiver The variable. - * @returnAa node. - */ -public fun > SVar.toMst(): Symbol = MstNumericAlgebra.bindSymbol(name) - -/** - * Maps [SVar] to [MST.Numeric] directly. - * - * @receiver The constant. - * @return A node. - */ -public fun > SConst.toMst(): MST.Numeric = MstNumericAlgebra.number(doubleValue) - -/** - * Maps [SFun] objects to [MST]. Some unsupported operations like [Derivative] are bound and converted then. - * [Power] operation is limited to constant right-hand side arguments. - * - * Detailed mapping is: - * - * - [SVar] -> [MstExtendedField.bindSymbol]; - * - [SConst] -> [MstExtendedField.number]; - * - [Sum] -> [MstExtendedField.add]; - * - [Prod] -> [MstExtendedField.multiply]; - * - [Power] -> [MstExtendedField.power] (limited to constant exponents only); - * - [Negative] -> [MstExtendedField.unaryMinus]; - * - [Log] -> [MstExtendedField.ln] (left) / [MstExtendedField.ln] (right); - * - [Sine] -> [MstExtendedField.sin]; - * - [Cosine] -> [MstExtendedField.cos]; - * - [Tangent] -> [MstExtendedField.tan]; - * - [DProd] is vector operation, and it is requested to be evaluated; - * - [SComposition] is also requested to be evaluated eagerly; - * - [VSumAll] is requested to be evaluated; - * - [Derivative] is requested to be evaluated. - * - * @receiver The scalar function. - * @return A node. - */ -public fun > SFun.toMst(): MST = MstExtendedField { - when (this@toMst) { - is SVar -> toMst() - is SConst -> toMst() - is Sum -> left.toMst() + right.toMst() - is Prod -> left.toMst() * right.toMst() - is Power -> left.toMst() pow ((right as? SConst<*>)?.doubleValue ?: (right() as SConst<*>).doubleValue) - is Negative -> -input.toMst() - is Log -> ln(left.toMst()) / ln(right.toMst()) - is Sine -> sin(input.toMst()) - is Cosine -> cos(input.toMst()) - is Tangent -> tan(input.toMst()) - is DProd -> this@toMst().toMst() - is SComposition -> this@toMst().toMst() - is VSumAll -> this@toMst().toMst() - is Derivative -> this@toMst().toMst() - } -} - -/** - * Maps [MST.Numeric] to [SConst] directly. - * - * @receiver The node. - * @return A new constant. - */ -public fun > MST.Numeric.toSConst(): SConst = SConst(value) - -/** - * Maps [Symbol] to [SVar] directly. - * - * @receiver The node. - * @return A new variable. - */ -internal fun > Symbol.toSVar(): SVar = SVar(identity) - -/** - * Maps [MST] objects to [SFun]. Unsupported operations throw [IllegalStateException]. - * - * Detailed mapping is: - * - * - [MST.Numeric] -> [SConst]; - * - [Symbol] -> [SVar]; - * - [MST.Unary] -> [Negative], [Sine], [Cosine], [Tangent], [Power], [Log]; - * - [MST.Binary] -> [Sum], [Prod], [Power]. - * - * @receiver The node. - * @return A scalar function. - */ -public fun > MST.toSFun(): SFun = when (this) { - is MST.Numeric -> toSConst() - is Symbol -> toSVar() - - is MST.Unary -> when (operation) { - GroupOperations.PLUS_OPERATION -> +value.toSFun() - GroupOperations.MINUS_OPERATION -> -value.toSFun() - TrigonometricOperations.SIN_OPERATION -> sin(value.toSFun()) - TrigonometricOperations.COS_OPERATION -> cos(value.toSFun()) - TrigonometricOperations.TAN_OPERATION -> tan(value.toSFun()) - PowerOperations.SQRT_OPERATION -> sqrt(value.toSFun()) - ExponentialOperations.EXP_OPERATION -> exp(value.toSFun()) - ExponentialOperations.LN_OPERATION -> value.toSFun().ln() - ExponentialOperations.SINH_OPERATION -> MstExtendedField { (exp(value) - exp(-value)) / 2.0 }.toSFun() - ExponentialOperations.COSH_OPERATION -> MstExtendedField { (exp(value) + exp(-value)) / 2.0 }.toSFun() - ExponentialOperations.TANH_OPERATION -> MstExtendedField { (exp(value) - exp(-value)) / (exp(-value) + exp(value)) }.toSFun() - ExponentialOperations.ASINH_OPERATION -> MstExtendedField { ln(sqrt(value * value + one) + value) }.toSFun() - ExponentialOperations.ACOSH_OPERATION -> MstExtendedField { ln(value + sqrt((value - one) * (value + one))) }.toSFun() - ExponentialOperations.ATANH_OPERATION -> MstExtendedField { (ln(value + one) - ln(one - value)) / 2.0 }.toSFun() - else -> error("Unary operation $operation not defined in $this") - } - - is MST.Binary -> when (operation) { - GroupOperations.PLUS_OPERATION -> left.toSFun() + right.toSFun() - GroupOperations.MINUS_OPERATION -> left.toSFun() - right.toSFun() - RingOperations.TIMES_OPERATION -> left.toSFun() * right.toSFun() - FieldOperations.DIV_OPERATION -> left.toSFun() / right.toSFun() - PowerOperations.POW_OPERATION -> left.toSFun() pow (right as MST.Numeric).toSConst() - else -> error("Binary operation $operation not defined in $this") - } -} diff --git a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt b/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt deleted file mode 100644 index 67332a680..000000000 --- a/kmath-kotlingrad/src/test/kotlin/space/kscience/kmath/kotlingrad/AdaptingTests.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.kotlingrad - -import edu.umontreal.kotlingrad.api.* -import space.kscience.kmath.asm.compileToExpression -import space.kscience.kmath.ast.parseMath -import space.kscience.kmath.expressions.MstNumericAlgebra -import space.kscience.kmath.expressions.Symbol.Companion.x -import space.kscience.kmath.expressions.invoke -import space.kscience.kmath.operations.DoubleField -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue -import kotlin.test.fail - -internal class AdaptingTests { - @Test - fun symbol() { - assertEquals(x.identity, x.toSVar>().name) - val c2 = "kitten".parseMath().toSFun>() - if (c2 is SVar) assertTrue(c2.name == "kitten") else fail() - } - - @Test - fun number() { - val c1 = MstNumericAlgebra.number(12354324) - assertTrue(c1.toSConst().doubleValue == 12354324.0) - val c2 = "0.234".parseMath().toSFun>() - if (c2 is SConst) assertTrue(c2.doubleValue == 0.234) else fail() - val c3 = "1e-3".parseMath().toSFun>() - if (c3 is SConst) assertEquals(0.001, c3.value) else fail() - } - - @Test - fun simpleFunctionShape() { - val linear = "2*x+16".parseMath().toSFun>() - if (linear !is Sum) fail() - if (linear.left !is Prod) fail() - if (linear.right !is SConst) fail() - } - - @Test - fun simpleFunctionDerivative() { - 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) - assertEquals(actualDerivative(x to 123.0), expectedDerivative(x to 123.0)) - } - - @Test - fun moreComplexDerivative() { - 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) - - val expectedDerivative = "-(2*x*cos(x^2)+2*sin(x)*cos(x)-16)/(2*sqrt(sin(x^2)-16*x-cos(x)^2))" - .parseMath() - .compileToExpression(DoubleField) - - assertEquals(actualDerivative(x to 0.1), expectedDerivative(x to 0.1)) - } -} diff --git a/kmath-memory/api/kmath-memory.api b/kmath-memory/api/kmath-memory.api deleted file mode 100644 index 9c9641461..000000000 --- a/kmath-memory/api/kmath-memory.api +++ /dev/null @@ -1,72 +0,0 @@ -public final class space/kscience/kmath/memory/ByteBufferMemory : space/kscience/kmath/memory/Memory { - public fun (Ljava/nio/ByteBuffer;II)V - public synthetic fun (Ljava/nio/ByteBuffer;IIILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun copy ()Lspace/kscience/kmath/memory/Memory; - public final fun getBuffer ()Ljava/nio/ByteBuffer; - public fun getSize ()I - public final fun getStartOffset ()I - public fun reader ()Lspace/kscience/kmath/memory/MemoryReader; - public fun view (II)Lspace/kscience/kmath/memory/Memory; - public fun writer ()Lspace/kscience/kmath/memory/MemoryWriter; -} - -public final class space/kscience/kmath/memory/ByteBufferMemoryKt { - public static final fun allocate (Lspace/kscience/kmath/memory/Memory$Companion;I)Lspace/kscience/kmath/memory/Memory; - public static final fun asMemory (Ljava/nio/ByteBuffer;II)Lspace/kscience/kmath/memory/Memory; - public static synthetic fun asMemory$default (Ljava/nio/ByteBuffer;IIILjava/lang/Object;)Lspace/kscience/kmath/memory/Memory; - public static final fun readAsMemory (Ljava/nio/file/Path;JJLkotlin/jvm/functions/Function1;)Ljava/lang/Object; - public static synthetic fun readAsMemory$default (Ljava/nio/file/Path;JJLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/lang/Object; - public static final fun wrap (Lspace/kscience/kmath/memory/Memory$Companion;[B)Lspace/kscience/kmath/memory/Memory; -} - -public abstract interface class space/kscience/kmath/memory/Memory { - public static final field Companion Lspace/kscience/kmath/memory/Memory$Companion; - public abstract fun copy ()Lspace/kscience/kmath/memory/Memory; - public abstract fun getSize ()I - public abstract fun reader ()Lspace/kscience/kmath/memory/MemoryReader; - public abstract fun view (II)Lspace/kscience/kmath/memory/Memory; - public abstract fun writer ()Lspace/kscience/kmath/memory/MemoryWriter; -} - -public final class space/kscience/kmath/memory/Memory$Companion { -} - -public final class space/kscience/kmath/memory/MemoryKt { - public static final fun read (Lspace/kscience/kmath/memory/Memory;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; - public static final fun write (Lspace/kscience/kmath/memory/Memory;Lkotlin/jvm/functions/Function1;)V -} - -public abstract interface class space/kscience/kmath/memory/MemoryReader { - public abstract fun getMemory ()Lspace/kscience/kmath/memory/Memory; - public abstract fun readByte (I)B - public abstract fun readDouble (I)D - public abstract fun readFloat (I)F - public abstract fun readInt (I)I - public abstract fun readLong (I)J - public abstract fun readShort (I)S - public abstract fun release ()V -} - -public abstract interface class space/kscience/kmath/memory/MemorySpec { - public abstract fun getObjectSize ()I - public abstract fun read (Lspace/kscience/kmath/memory/MemoryReader;I)Ljava/lang/Object; - public abstract fun write (Lspace/kscience/kmath/memory/MemoryWriter;ILjava/lang/Object;)V -} - -public final class space/kscience/kmath/memory/MemorySpecKt { - public static final fun read (Lspace/kscience/kmath/memory/MemoryReader;Lspace/kscience/kmath/memory/MemorySpec;I)Ljava/lang/Object; - public static final fun write (Lspace/kscience/kmath/memory/MemoryWriter;Lspace/kscience/kmath/memory/MemorySpec;ILjava/lang/Object;)V - public static final fun writeArray (Lspace/kscience/kmath/memory/MemoryWriter;Lspace/kscience/kmath/memory/MemorySpec;I[Ljava/lang/Object;)V -} - -public abstract interface class space/kscience/kmath/memory/MemoryWriter { - public abstract fun getMemory ()Lspace/kscience/kmath/memory/Memory; - public abstract fun release ()V - public abstract fun writeByte (IB)V - public abstract fun writeDouble (ID)V - public abstract fun writeFloat (IF)V - public abstract fun writeInt (II)V - public abstract fun writeLong (IJ)V - public abstract fun writeShort (IS)V -} - diff --git a/kmath-memory/build.gradle.kts b/kmath-memory/build.gradle.kts index 4478e5b80..1f34a4f17 100644 --- a/kmath-memory/build.gradle.kts +++ b/kmath-memory/build.gradle.kts @@ -1,12 +1,3 @@ plugins { - kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT - description = """ - An API and basic implementation for arranging objects in a continuous memory block. - """.trimIndent() + id("scientifik.mpp") } diff --git a/kmath-memory/src/commonMain/kotlin/scientifik/memory/Memory.kt b/kmath-memory/src/commonMain/kotlin/scientifik/memory/Memory.kt new file mode 100644 index 000000000..7c6886202 --- /dev/null +++ b/kmath-memory/src/commonMain/kotlin/scientifik/memory/Memory.kt @@ -0,0 +1,77 @@ +package scientifik.memory + +interface Memory { + val size: Int + + /** + * Get a projection of this memory (it reflects the changes in the parent memory block) + */ + fun view(offset: Int, length: Int): Memory + + /** + * Create a copy of this memory, which does not know anything about this memory + */ + fun copy(): Memory + + /** + * Create and possibly register a new reader + */ + fun reader(): MemoryReader + + fun writer(): MemoryWriter + + companion object { + + } +} + +interface MemoryReader { + val memory: Memory + + fun readDouble(offset: Int): Double + fun readFloat(offset: Int): Float + fun readByte(offset: Int): Byte + fun readShort(offset: Int): Short + fun readInt(offset: Int): Int + fun readLong(offset: Int): Long + + fun release() +} + +/** + * Use the memory for read then release the reader + */ +inline fun Memory.read(block: MemoryReader.() -> Unit) { + reader().apply(block).apply { release() } +} + +interface MemoryWriter { + val memory: Memory + + fun writeDouble(offset: Int, value: Double) + fun writeFloat(offset: Int, value: Float) + fun writeByte(offset: Int, value: Byte) + fun writeShort(offset: Int, value: Short) + fun writeInt(offset: Int, value: Int) + fun writeLong(offset: Int, value: Long) + + fun release() +} + +/** + * Use the memory for write then release the writer + */ +inline fun Memory.write(block: MemoryWriter.() -> Unit) { + writer().apply(block).apply { release() } +} + +/** + * Allocate the most effective platform-specific memory + */ +expect fun Memory.Companion.allocate(length: Int): Memory + +/** + * Wrap a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied + * and could be mutated independently from the resulting [Memory] + */ +expect fun Memory.Companion.wrap(array: ByteArray): Memory diff --git a/kmath-memory/src/commonMain/kotlin/scientifik/memory/MemorySpec.kt b/kmath-memory/src/commonMain/kotlin/scientifik/memory/MemorySpec.kt new file mode 100644 index 000000000..0896f0dcb --- /dev/null +++ b/kmath-memory/src/commonMain/kotlin/scientifik/memory/MemorySpec.kt @@ -0,0 +1,34 @@ +package scientifik.memory + +/** + * A specification to read or write custom objects with fixed size in bytes + */ +interface MemorySpec { + /** + * Size of [T] in bytes after serialization + */ + val objectSize: Int + + fun MemoryReader.read(offset: Int): T + fun MemoryWriter.write(offset: Int, value: T) +} + +fun MemoryReader.read(spec: MemorySpec, offset: Int): T = spec.run { read(offset) } +fun MemoryWriter.write(spec: MemorySpec, offset: Int, value: T) = spec.run { write(offset, value) } + +inline fun MemoryReader.readArray(spec: MemorySpec, offset: Int, size: Int) = + Array(size) { i -> + spec.run { + read(offset + i * objectSize) + } + } + +fun MemoryWriter.writeArray(spec: MemorySpec, offset: Int, array: Array) { + spec.run { + for (i in array.indices) { + write(offset + i * objectSize, array[i]) + } + } +} + +//TODO It is possible to add elastic MemorySpec with unknown object size \ No newline at end of file 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 deleted file mode 100644 index 9f73ae2f3..000000000 --- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/Memory.kt +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.memory - -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract - -/** - * Represents a display of certain memory structure. - */ -public interface Memory { - /** - * The length of this memory in bytes. - */ - public val size: Int - - /** - * Get a projection of this memory (it reflects the changes in the parent memory block). - */ - public fun view(offset: Int, length: Int): Memory - - /** - * Creates an independent copy of this memory. - */ - public fun copy(): Memory - - /** - * Gets or creates a reader of this memory. - */ - public fun reader(): MemoryReader - - /** - * Gets or creates a writer of this memory. - */ - public fun writer(): MemoryWriter - - public companion object -} - -/** - * The interface to read primitive types in this memory. - */ -public interface MemoryReader { - /** - * The underlying memory. - */ - public val memory: Memory - - /** - * Reads [Double] at certain [offset]. - */ - public fun readDouble(offset: Int): Double - - /** - * Reads [Float] at certain [offset]. - */ - public fun readFloat(offset: Int): Float - - /** - * Reads [Byte] at certain [offset]. - */ - public fun readByte(offset: Int): Byte - - /** - * Reads [Short] at certain [offset]. - */ - public fun readShort(offset: Int): Short - - /** - * Reads [Int] at certain [offset]. - */ - public fun readInt(offset: Int): Int - - /** - * Reads [Long] at certain [offset]. - */ - public fun readLong(offset: Int): Long - - /** - * Disposes this reader if needed. - */ - public fun release() -} - -/** - * Uses the memory for read then releases the reader. - */ -public inline fun Memory.read(block: MemoryReader.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - val reader = reader() - val result = reader.block() - reader.release() - return result -} - -/** - * The interface to write primitive types into this memory. - */ -public interface MemoryWriter { - /** - * The underlying memory. - */ - public val memory: Memory - - /** - * Writes [Double] at certain [offset]. - */ - public fun writeDouble(offset: Int, value: Double) - - /** - * Writes [Float] at certain [offset]. - */ - public fun writeFloat(offset: Int, value: Float) - - /** - * Writes [Byte] at certain [offset]. - */ - public fun writeByte(offset: Int, value: Byte) - - /** - * Writes [Short] at certain [offset]. - */ - public fun writeShort(offset: Int, value: Short) - - /** - * Writes [Int] at certain [offset]. - */ - public fun writeInt(offset: Int, value: Int) - - /** - * Writes [Long] at certain [offset]. - */ - public fun writeLong(offset: Int, value: Long) - - /** - * Disposes this writer if needed. - */ - public fun release() -} - -/** - * Uses the memory for write then releases the writer. - */ -public inline fun Memory.write(block: MemoryWriter.() -> Unit) { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - writer().apply(block).release() -} - -/** - * Allocates the most effective platform-specific memory. - */ -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 of the resulting [Memory]. - */ -public expect fun Memory.Companion.wrap(array: ByteArray): Memory diff --git a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt b/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt deleted file mode 100644 index 2f2af4d9c..000000000 --- a/kmath-memory/src/commonMain/kotlin/space/kscience/kmath/memory/MemorySpec.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.memory - -/** - * A specification to read or write custom objects with fixed size in bytes. - * - * @param T the type of object this spec manages. - */ -public interface MemorySpec { - /** - * Size of [T] in bytes after serialization. - */ - public val objectSize: Int - - /** - * Reads the object starting from [offset]. - */ - public fun MemoryReader.read(offset: Int): T - - // TODO consider thread safety - - /** - * Writes the object [value] starting from [offset]. - */ - public fun MemoryWriter.write(offset: Int, value: T) -} - -/** - * Reads the object with [spec] starting from [offset]. - */ -public fun MemoryReader.read(spec: MemorySpec, offset: Int): T = with(spec) { read(offset) } - -/** - * Writes the object [value] with [spec] starting from [offset]. - */ -public fun MemoryWriter.write(spec: MemorySpec, offset: Int, value: T): Unit = - with(spec) { write(offset, value) } - -/** - * Reads array of [size] objects mapped by [spec] at certain [offset]. - */ -public inline fun MemoryReader.readArray(spec: MemorySpec, offset: Int, size: Int): Array = - Array(size) { i -> with(spec) { read(offset + i * objectSize) } } - -/** - * Writes [array] of objects mapped by [spec] at certain [offset]. - */ -public fun MemoryWriter.writeArray(spec: MemorySpec, offset: Int, array: Array): Unit = - with(spec) { array.indices.forEach { i -> write(offset + i * objectSize, array[i]) } } - -// TODO It is possible to add elastic MemorySpec with unknown object size diff --git a/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt b/kmath-memory/src/jsMain/kotlin/scientifik/memory/DataViewMemory.kt similarity index 74% rename from kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt rename to kmath-memory/src/jsMain/kotlin/scientifik/memory/DataViewMemory.kt index db5eb556e..38ec14824 100644 --- a/kmath-memory/src/jsMain/kotlin/space/kscience/kmath/memory/DataViewMemory.kt +++ b/kmath-memory/src/jsMain/kotlin/scientifik/memory/DataViewMemory.kt @@ -1,21 +1,16 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.memory +package scientifik.memory import org.khronos.webgl.ArrayBuffer import org.khronos.webgl.DataView import org.khronos.webgl.Int8Array -private class DataViewMemory(val view: DataView) : Memory { +class DataViewMemory(val view: DataView) : Memory { + override val size: Int get() = view.byteLength override fun view(offset: Int, length: Int): Memory { require(offset >= 0) { "offset shouldn't be negative: $offset" } require(length >= 0) { "length shouldn't be negative: $length" } - require(offset + length <= size) { "Can't view memory outside the parent region." } if (offset + length > size) throw IndexOutOfBoundsException("offset + length > size: $offset + $length > $size") @@ -38,11 +33,11 @@ private class DataViewMemory(val view: DataView) : Memory { override fun readInt(offset: Int): Int = view.getInt32(offset, false) - override fun readLong(offset: Int): Long = - view.getInt32(offset, false).toLong() shl 32 or view.getInt32(offset + 4, false).toLong() + override fun readLong(offset: Int): Long = (view.getInt32(offset, false).toLong() shl 32) or + view.getInt32(offset + 4, false).toLong() override fun release() { - // does nothing on JS + // does nothing on JS because of GC } } @@ -77,7 +72,7 @@ private class DataViewMemory(val view: DataView) : Memory { } override fun release() { - // does nothing on JS + //does nothing on JS } } @@ -86,18 +81,14 @@ private class DataViewMemory(val view: DataView) : Memory { } /** - * Allocates memory based on a [DataView]. + * Allocate the most effective platform-specific memory */ -public actual fun Memory.Companion.allocate(length: Int): Memory { +actual fun Memory.Companion.allocate(length: Int): Memory { val buffer = ArrayBuffer(length) return DataViewMemory(DataView(buffer, 0, length)) } -/** - * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently of the resulting [Memory]. - */ -public actual fun Memory.Companion.wrap(array: ByteArray): Memory { +actual fun Memory.Companion.wrap(array: ByteArray): Memory { @Suppress("CAST_NEVER_SUCCEEDS") val int8Array = array as Int8Array return DataViewMemory(DataView(int8Array.buffer, int8Array.byteOffset, int8Array.length)) } diff --git a/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/ByteBufferMemory.kt similarity index 52% rename from kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt rename to kmath-memory/src/jvmMain/kotlin/scientifik/memory/ByteBufferMemory.kt index 6e60514f8..9ec2b3a09 100644 --- a/kmath-memory/src/jvmMain/kotlin/space/kscience/kmath/memory/ByteBufferMemory.kt +++ b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/ByteBufferMemory.kt @@ -1,32 +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 file. - */ +package scientifik.memory -package space.kscience.kmath.memory - -import java.io.IOException import java.nio.ByteBuffer import java.nio.channels.FileChannel import java.nio.file.Files import java.nio.file.Path import java.nio.file.StandardOpenOption -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -@PublishedApi -internal class ByteBufferMemory( + +private class ByteBufferMemory( val buffer: ByteBuffer, val startOffset: Int = 0, - override val size: Int = buffer.limit(), + override val size: Int = buffer.limit() ) : Memory { + + @Suppress("NOTHING_TO_INLINE") private inline fun position(o: Int): Int = startOffset + o override fun view(offset: Int, length: Int): Memory { - require(offset >= 0) { "offset shouldn't be negative: $offset" } - require(length >= 0) { "length shouldn't be negative: $length" } - require(offset + length <= size) { "Can't view memory outside the parent region." } + if (offset + length > size) error("Selecting a Memory view outside of memory range") return ByteBufferMemory(buffer, position(offset), length) } @@ -36,9 +28,10 @@ internal class ByteBufferMemory( copy.put(buffer) copy.flip() return ByteBufferMemory(copy) + } - private val reader: MemoryReader = object : MemoryReader { + private val reader = object : MemoryReader { override val memory: Memory get() = this@ByteBufferMemory override fun readDouble(offset: Int) = buffer.getDouble(position(offset)) @@ -54,13 +47,13 @@ internal class ByteBufferMemory( override fun readLong(offset: Int) = buffer.getLong(position(offset)) override fun release() { - // does nothing on JVM + //does nothing on JVM } } override fun reader(): MemoryReader = reader - private val writer: MemoryWriter = object : MemoryWriter { + private val writer = object : MemoryWriter { override val memory: Memory get() = this@ByteBufferMemory override fun writeDouble(offset: Int, value: Double) { @@ -88,7 +81,7 @@ internal class ByteBufferMemory( } override fun release() { - // does nothing on JVM + //does nothing on JVM } } @@ -96,37 +89,26 @@ internal class ByteBufferMemory( } /** - * Allocates memory based on a [ByteBuffer]. + * Allocate the most effective platform-specific memory */ -public actual fun Memory.Companion.allocate(length: Int): Memory = - ByteBufferMemory(checkNotNull(ByteBuffer.allocate(length))) +actual fun Memory.Companion.allocate(length: Int): Memory { + val buffer = ByteBuffer.allocate(length) + return ByteBufferMemory(buffer) +} -/** - * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently of the resulting [Memory]. - */ -public actual fun Memory.Companion.wrap(array: ByteArray): Memory = - ByteBufferMemory(checkNotNull(ByteBuffer.wrap(array))) +actual fun Memory.Companion.wrap(array: ByteArray): Memory { + val buffer = ByteBuffer.wrap(array) + return ByteBufferMemory(buffer) +} -/** - * Wraps this [ByteBuffer] to [Memory] object. - * - * @receiver the byte buffer. - * @param startOffset the start offset. - * @param size the size of memory to map. - * @return the [Memory] object. - */ -public fun ByteBuffer.asMemory(startOffset: Int = 0, size: Int = limit()): Memory = +fun ByteBuffer.asMemory(startOffset: Int = 0, size: Int = limit()): Memory = ByteBufferMemory(this, startOffset, size) /** - * Uses direct memory-mapped buffer from file to read something and close it afterwards. + * Use direct memory-mapped buffer from file to read something and close it afterwards. */ -@Throws(IOException::class) -public inline fun Path.readAsMemory(position: Long = 0, size: Long = Files.size(this), block: Memory.() -> R): R { - contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } - - return FileChannel - .open(this, StandardOpenOption.READ) - .use { ByteBufferMemory(it.map(FileChannel.MapMode.READ_ONLY, position, size)).block() } -} +fun Path.readAsMemory(position: Long = 0, size: Long = Files.size(this), block: Memory.() -> R): R { + return FileChannel.open(this, StandardOpenOption.READ).use { + ByteBufferMemory(it.map(FileChannel.MapMode.READ_ONLY, position, size)).block() + } +} \ No newline at end of file diff --git a/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignMemory.kt b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignMemory.kt new file mode 100644 index 000000000..fc5b518d2 --- /dev/null +++ b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignMemory.kt @@ -0,0 +1,51 @@ +package scientifik.memory.foreign + +import jdk.incubator.foreign.MemoryHandles +import jdk.incubator.foreign.MemorySegment +import scientifik.memory.Memory +import scientifik.memory.MemoryReader +import scientifik.memory.MemoryWriter +import java.lang.invoke.VarHandle +import java.nio.ByteOrder + +fun Memory.Companion.allocateForeign(length: Int): Memory { + return ForeignMemory(MemorySegment.allocateNative(length.toLong())) +} + +internal class ForeignMemory(val scope: MemorySegment) : Memory, AutoCloseable { + override val size: Int + get() = scope.byteSize().toInt() + + private val writer: MemoryWriter = ForeignWriter(this) + private val reader: MemoryReader = ForeignReader(this) + + override fun view(offset: Int, length: Int): ForeignMemory = + ForeignMemory(scope.asSlice(offset.toLong(), length.toLong())) + + override fun copy(): Memory { + val bytes = scope.toByteArray() + val newScope = MemorySegment.allocateNative(scope.byteSize())!! + + var point = newScope.baseAddress() + + bytes.forEach { + byteHandle.set(point, it) + point = point.addOffset(1) + } + + return ForeignMemory(newScope) + } + + override fun reader(): MemoryReader = reader + override fun writer(): MemoryWriter = writer + override fun close(): Unit = scope.close() + + internal companion object { + internal val doubleHandle: VarHandle = MemoryHandles.varHandle(java.lang.Double.TYPE, ByteOrder.nativeOrder())!! + internal val floatHandle: VarHandle = MemoryHandles.varHandle(java.lang.Float.TYPE, ByteOrder.nativeOrder())!! + internal val byteHandle: VarHandle = MemoryHandles.varHandle(java.lang.Byte.TYPE, ByteOrder.nativeOrder())!! + internal val shortHandle: VarHandle = MemoryHandles.varHandle(java.lang.Short.TYPE, ByteOrder.nativeOrder())!! + internal val intHandle: VarHandle = MemoryHandles.varHandle(Integer.TYPE, ByteOrder.nativeOrder())!! + internal val longHandle: VarHandle = MemoryHandles.varHandle(java.lang.Long.TYPE, ByteOrder.nativeOrder())!! + } +} diff --git a/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignReader.kt b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignReader.kt new file mode 100644 index 000000000..3de1f3f20 --- /dev/null +++ b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignReader.kt @@ -0,0 +1,35 @@ +package scientifik.memory.foreign + +import jdk.incubator.foreign.MemorySegment +import scientifik.memory.MemoryReader + +internal class ForeignReader(override val memory: ForeignMemory) : MemoryReader { + private val scope: MemorySegment + get() = memory.scope.asReadOnly() + + override fun readDouble(offset: Int): Double = with(scope) { + ForeignMemory.doubleHandle.get(baseAddress().addOffset(offset.toLong())) as Double + } + + override fun readFloat(offset: Int): Float = with(scope) { + ForeignMemory.floatHandle.get(baseAddress().addOffset(offset.toLong())) as Float + } + + override fun readByte(offset: Int): Byte = with(scope) { + ForeignMemory.byteHandle.get(baseAddress().addOffset(offset.toLong())) as Byte + } + + override fun readShort(offset: Int): Short = with(scope) { + ForeignMemory.shortHandle.get(baseAddress().addOffset(offset.toLong())) as Short + } + + override fun readInt(offset: Int): Int = with(scope) { + ForeignMemory.intHandle.get(baseAddress().addOffset(offset.toLong())) as Int + } + + override fun readLong(offset: Int): Long = with(scope) { + ForeignMemory.longHandle.get(baseAddress().addOffset(offset.toLong())) as Long + } + + override fun release(): Unit = memory.close() +} diff --git a/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignWriter.kt b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignWriter.kt new file mode 100644 index 000000000..8787e2384 --- /dev/null +++ b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignWriter.kt @@ -0,0 +1,35 @@ +package scientifik.memory.foreign + +import jdk.incubator.foreign.MemorySegment +import scientifik.memory.MemoryWriter + +internal class ForeignWriter(override val memory: ForeignMemory) : MemoryWriter { + private val scope: MemorySegment + get() = memory.scope + + override fun writeDouble(offset: Int, value: Double): Unit = with(scope) { + ForeignMemory.doubleHandle.set(baseAddress().addOffset(offset.toLong()), value) + } + + override fun writeFloat(offset: Int, value: Float): Unit = with(scope) { + ForeignMemory.floatHandle.set(baseAddress().addOffset(offset.toLong()), value) + } + + override fun writeByte(offset: Int, value: Byte): Unit = with(scope) { + ForeignMemory.byteHandle.set(baseAddress().addOffset(offset.toLong()), value) + } + + override fun writeShort(offset: Int, value: Short): Unit = with(scope) { + ForeignMemory.shortHandle.set(baseAddress().addOffset(offset.toLong()), value) + } + + override fun writeInt(offset: Int, value: Int): Unit = with(scope) { + ForeignMemory.intHandle.set(baseAddress().addOffset(offset.toLong()), value) + } + + override fun writeLong(offset: Int, value: Long): Unit = with(scope) { + ForeignMemory.longHandle.set(baseAddress().addOffset(offset.toLong()), value) + } + + override fun release(): Unit = memory.close() +} 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 deleted file mode 100644 index d13da1191..000000000 --- a/kmath-memory/src/nativeMain/kotlin/space/kscience/kmath/memory/NativeMemory.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.memory - -@PublishedApi -internal class NativeMemory( - val array: ByteArray, - val startOffset: Int = 0, - override val size: Int = array.size, -) : Memory { - @Suppress("NOTHING_TO_INLINE") - private inline fun position(o: Int): Int = startOffset + o - - override fun view(offset: Int, length: Int): Memory { - require(offset >= 0) { "offset shouldn't be negative: $offset" } - require(length >= 0) { "length shouldn't be negative: $length" } - require(offset + length <= size) { "Can't view memory outside the parent region." } - return NativeMemory(array, position(offset), length) - } - - override fun copy(): Memory { - val copy = array.copyOfRange(startOffset, startOffset + size) - return NativeMemory(copy) - } - - private val reader: MemoryReader = object : MemoryReader { - override val memory: Memory get() = this@NativeMemory - - override fun readDouble(offset: Int) = array.getDoubleAt(position(offset)) - - override fun readFloat(offset: Int) = array.getFloatAt(position(offset)) - - override fun readByte(offset: Int) = array[position(offset)] - - override fun readShort(offset: Int) = array.getShortAt(position(offset)) - - override fun readInt(offset: Int) = array.getIntAt(position(offset)) - - override fun readLong(offset: Int) = array.getLongAt(position(offset)) - - override fun release() { - // does nothing on JVM - } - } - - override fun reader(): MemoryReader = reader - - private val writer: MemoryWriter = object : MemoryWriter { - override val memory: Memory get() = this@NativeMemory - - override fun writeDouble(offset: Int, value: Double) { - array.setDoubleAt(position(offset), value) - } - - override fun writeFloat(offset: Int, value: Float) { - array.setFloatAt(position(offset), value) - } - - override fun writeByte(offset: Int, value: Byte) { - array[position(offset)] = value - } - - override fun writeShort(offset: Int, value: Short) { - array.setShortAt(position(offset), value) - } - - override fun writeInt(offset: Int, value: Int) { - array.setIntAt(position(offset), value) - } - - override fun writeLong(offset: Int, value: Long) { - array.setLongAt(position(offset), value) - } - - override fun release() { - // does nothing on JVM - } - } - - override fun writer(): MemoryWriter = writer -} - -/** - * Wraps a [Memory] around existing [ByteArray]. This operation is unsafe since the array is not copied - * and could be mutated independently of the resulting [Memory]. - */ -public actual fun Memory.Companion.wrap(array: ByteArray): Memory = NativeMemory(array) - -/** - * Allocates the most effective platform-specific memory. - */ -public actual fun Memory.Companion.allocate(length: Int): Memory { - val array = ByteArray(length) - return NativeMemory(array) -} \ No newline at end of file diff --git a/kmath-nd4j/README.md b/kmath-nd4j/README.md deleted file mode 100644 index 5cbb31d5a..000000000 --- a/kmath-nd4j/README.md +++ /dev/null @@ -1,71 +0,0 @@ -# Module kmath-nd4j - -ND4J based implementations of KMath abstractions. - - - [nd4jarraystructure](#) : NDStructure wrapper for INDArray - - [nd4jarrayrings](#) : Rings over Nd4jArrayStructure of Int and Long - - [nd4jarrayfields](#) : Fields over Nd4jArrayStructure of Float and Double - - -## Artifact: - -The Maven coordinates of this project are `space.kscience:kmath-nd4j:0.3.0-dev-14`. - -**Gradle:** -```gradle -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-nd4j:0.3.0-dev-14' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-nd4j:0.3.0-dev-14") -} -``` - -## Examples - -NDStructure wrapper for INDArray: - -```kotlin -import org.nd4j.linalg.factory.* -import scientifik.kmath.nd4j.* -import scientifik.kmath.structures.* - -val array = Nd4j.ones(2, 2).asDoubleStructure() -println(array[0, 0]) // 1.0 -array[intArrayOf(0, 0)] = 24.0 -println(array[0, 0]) // 24.0 -``` - -Fast element-wise and in-place arithmetics for INDArray: - -```kotlin -import org.nd4j.linalg.factory.* -import scientifik.kmath.nd4j.* -import scientifik.kmath.operations.* - -val field = DoubleNd4jArrayField(intArrayOf(2, 2)) -val array = Nd4j.rand(2, 2).asDoubleStructure() - -val res = field { - (25.0 / array + 20) * 4 -} - -println(res.ndArray) -// [[ 250.6449, 428.5840], -// [ 269.7913, 202.2077]] -``` - -Contributed by [Iaroslav Postovalov](https://github.com/CommanderTvis). diff --git a/kmath-nd4j/build.gradle.kts b/kmath-nd4j/build.gradle.kts deleted file mode 100644 index dcb6f1b4a..000000000 --- a/kmath-nd4j/build.gradle.kts +++ /dev/null @@ -1,21 +0,0 @@ -plugins { - kotlin("jvm") - id("ru.mipt.npm.gradle.common") -} - -description = "ND4J NDStructure implementation and according NDAlgebra classes" - -dependencies { - api(project(":kmath-tensors")) - api("org.nd4j:nd4j-api:1.0.0-M1") - testImplementation("org.nd4j:nd4j-native-platform:1.0.0-M1") - testImplementation("org.slf4j:slf4j-simple:1.7.31") -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL - propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) - feature(id = "nd4jarraystructure") { "NDStructure wrapper for INDArray" } - feature(id = "nd4jarrayrings") { "Rings over Nd4jArrayStructure of Int and Long" } - feature(id = "nd4jarrayfields") { "Fields over Nd4jArrayStructure of Float and Double" } -} diff --git a/kmath-nd4j/docs/README-TEMPLATE.md b/kmath-nd4j/docs/README-TEMPLATE.md deleted file mode 100644 index 5f325cab5..000000000 --- a/kmath-nd4j/docs/README-TEMPLATE.md +++ /dev/null @@ -1,43 +0,0 @@ -# Module kmath-nd4j - -ND4J based implementations of KMath abstractions. - -${features} - -${artifact} - -## Examples - -NDStructure wrapper for INDArray: - -```kotlin -import org.nd4j.linalg.factory.* -import scientifik.kmath.nd4j.* -import scientifik.kmath.structures.* - -val array = Nd4j.ones(2, 2).asDoubleStructure() -println(array[0, 0]) // 1.0 -array[intArrayOf(0, 0)] = 24.0 -println(array[0, 0]) // 24.0 -``` - -Fast element-wise and in-place arithmetics for INDArray: - -```kotlin -import org.nd4j.linalg.factory.* -import scientifik.kmath.nd4j.* -import scientifik.kmath.operations.* - -val field = DoubleNd4jArrayField(intArrayOf(2, 2)) -val array = Nd4j.rand(2, 2).asDoubleStructure() - -val res = field { - (25.0 / array + 20) * 4 -} - -println(res.ndArray) -// [[ 250.6449, 428.5840], -// [ 269.7913, 202.2077]] -``` - -Contributed by [Iaroslav Postovalov](https://github.com/CommanderTvis). 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 deleted file mode 100644 index 54df31556..000000000 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebra.kt +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.nd4j - -import org.nd4j.linalg.api.ndarray.INDArray -import org.nd4j.linalg.api.ops.impl.transforms.strict.ACosh -import org.nd4j.linalg.api.ops.impl.transforms.strict.ASinh -import org.nd4j.linalg.factory.Nd4j -import org.nd4j.linalg.ops.transforms.Transforms -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.* - -internal fun AlgebraND<*, *>.checkShape(array: INDArray): INDArray { - val arrayShape = array.shape().toIntArray() - if (!shape.contentEquals(arrayShape)) throw ShapeMismatchException(shape, arrayShape) - return array -} - - -/** - * Represents [AlgebraND] over [Nd4jArrayAlgebra]. - * - * @param T the type of ND-structure element. - * @param C the type of the element context. - */ -public sealed interface Nd4jArrayAlgebra> : AlgebraND { - /** - * Wraps [INDArray] to [Nd4jArrayStructure]. - */ - public fun INDArray.wrap(): Nd4jArrayStructure - - /** - * Unwraps to or get [INDArray] from [StructureND]. - */ - public val StructureND.ndArray: INDArray - - 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 - 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 - } - - override fun StructureND.mapIndexed( - transform: C.(index: IntArray, T) -> T, - ): Nd4jArrayStructure { - val new = Nd4j.create(*this@Nd4jArrayAlgebra.shape).wrap() - new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(idx, this[idx]) } - return new - } - - override fun combine( - a: StructureND, - b: StructureND, - transform: C.(T, T) -> T, - ): Nd4jArrayStructure { - val new = Nd4j.create(*shape).wrap() - new.indicesIterator().forEach { idx -> new[idx] = elementContext.transform(a[idx], b[idx]) } - return new - } -} - -/** - * Represents [GroupND] over [Nd4jArrayStructure]. - * - * @param T the type of the element contained in ND structure. - * @param S the type of space of structure elements. - */ -public sealed interface Nd4jArrayGroup> : GroupND, Nd4jArrayAlgebra { - - override val zero: Nd4jArrayStructure - get() = Nd4j.zeros(*shape).wrap() - - override fun add(a: StructureND, b: StructureND): Nd4jArrayStructure = - a.ndArray.add(b.ndArray).wrap() - - override operator fun StructureND.minus(b: StructureND): Nd4jArrayStructure = - ndArray.sub(b.ndArray).wrap() - - override operator fun StructureND.unaryMinus(): Nd4jArrayStructure = - ndArray.neg().wrap() - - public fun multiply(a: StructureND, k: Number): Nd4jArrayStructure = - a.ndArray.mul(k).wrap() -} - -/** - * Represents [RingND] over [Nd4jArrayStructure]. - * - * @param T the type of the element contained in ND structure. - * @param R the type of ring of structure elements. - */ -@OptIn(UnstableKMathAPI::class) -public sealed interface Nd4jArrayRing> : RingND, Nd4jArrayGroup { - - override val one: Nd4jArrayStructure - get() = Nd4j.ones(*shape).wrap() - - override fun multiply(a: StructureND, b: StructureND): Nd4jArrayStructure = - a.ndArray.mul(b.ndArray).wrap() -// -// override operator fun Nd4jArrayStructure.minus(b: Number): Nd4jArrayStructure { -// check(this) -// return ndArray.sub(b).wrap() -// } -// -// override operator fun Nd4jArrayStructure.plus(b: Number): Nd4jArrayStructure { -// check(this) -// return ndArray.add(b).wrap() -// } -// -// override operator fun Number.minus(b: Nd4jArrayStructure): Nd4jArrayStructure { -// check(b) -// return b.ndArray.rsub(this).wrap() -// } - - public companion object { - private val intNd4jArrayRingCache: ThreadLocal> = - ThreadLocal.withInitial(::HashMap) - - /** - * Creates an [RingND] for [Int] values or pull it from cache if it was created previously. - */ - public fun int(vararg shape: Int): Nd4jArrayRing = - intNd4jArrayRingCache.get().getOrPut(shape) { IntNd4jArrayRing(shape) } - - /** - * Creates a most suitable implementation of [RingND] using reified class. - */ - @Suppress("UNCHECKED_CAST") - public inline fun auto(vararg shape: Int): Nd4jArrayRing> = when { - T::class == Int::class -> int(*shape) as Nd4jArrayRing> - else -> throw UnsupportedOperationException("This factory method only supports Long type.") - } - } -} - -/** - * Represents [FieldND] over [Nd4jArrayStructure]. - * - * @param T the type of the element contained in ND structure. - * @param F the type field of structure elements. - */ -public sealed interface Nd4jArrayField> : FieldND, Nd4jArrayRing { - override fun divide(a: StructureND, b: StructureND): Nd4jArrayStructure = - a.ndArray.div(b.ndArray).wrap() - - public operator fun Number.div(b: StructureND): Nd4jArrayStructure = b.ndArray.rdiv(this).wrap() - - public companion object { - private val floatNd4jArrayFieldCache: ThreadLocal> = - ThreadLocal.withInitial(::HashMap) - - private val doubleNd4JArrayFieldCache: ThreadLocal> = - ThreadLocal.withInitial(::HashMap) - - /** - * Creates an [FieldND] for [Float] values or pull it from cache if it was created previously. - */ - public fun float(vararg shape: Int): Nd4jArrayRing = - floatNd4jArrayFieldCache.get().getOrPut(shape) { FloatNd4jArrayField(shape) } - - /** - * Creates an [FieldND] for [Double] values or pull it from cache if it was created previously. - */ - public fun real(vararg shape: Int): Nd4jArrayRing = - doubleNd4JArrayFieldCache.get().getOrPut(shape) { DoubleNd4jArrayField(shape) } - - /** - * Creates a most suitable implementation of [FieldND] using reified class. - */ - @Suppress("UNCHECKED_CAST") - public inline fun auto(vararg shape: Int): Nd4jArrayField> = when { - T::class == Float::class -> float(*shape) as Nd4jArrayField> - T::class == Double::class -> real(*shape) as Nd4jArrayField> - else -> throw UnsupportedOperationException("This factory method only supports Float and Double types.") - } - } -} - -/** - * Represents intersection of [ExtendedField] and [Field] over [Nd4jArrayStructure]. - */ -public sealed interface Nd4jArrayExtendedField> : ExtendedField>, - Nd4jArrayField { - override fun sin(arg: StructureND): StructureND = Transforms.sin(arg.ndArray).wrap() - override fun cos(arg: StructureND): StructureND = Transforms.cos(arg.ndArray).wrap() - override fun asin(arg: StructureND): StructureND = Transforms.asin(arg.ndArray).wrap() - override fun acos(arg: StructureND): StructureND = Transforms.acos(arg.ndArray).wrap() - override fun atan(arg: StructureND): StructureND = Transforms.atan(arg.ndArray).wrap() - - override fun power(arg: StructureND, pow: Number): StructureND = - Transforms.pow(arg.ndArray, pow).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() - - override fun asinh(arg: StructureND): StructureND = - Nd4j.getExecutioner().exec(ASinh(arg.ndArray, arg.ndArray.ulike())).wrap() - - override fun acosh(arg: StructureND): StructureND = - Nd4j.getExecutioner().exec(ACosh(arg.ndArray, arg.ndArray.ulike())).wrap() - - override fun atanh(arg: StructureND): StructureND = Transforms.atanh(arg.ndArray).wrap() -} - -/** - * Represents [FieldND] over [Nd4jArrayDoubleStructure]. - */ -public class DoubleNd4jArrayField(override val shape: IntArray) : Nd4jArrayExtendedField { - override val elementContext: DoubleField get() = DoubleField - - override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asDoubleStructure() - - @OptIn(PerformancePitfall::class) - override val StructureND.ndArray: INDArray - get() = when (this) { - is Nd4jArrayStructure -> checkShape(ndArray) - else -> Nd4j.zeros(*shape).also { - elements().forEach { (idx, value) -> it.putScalar(idx, value) } - } - } - - override fun scale(a: StructureND, value: Double): Nd4jArrayStructure { - return a.ndArray.mul(value).wrap() - } - - override operator fun StructureND.div(arg: Double): Nd4jArrayStructure { - return ndArray.div(arg).wrap() - } - - override operator fun StructureND.plus(arg: Double): Nd4jArrayStructure { - return ndArray.add(arg).wrap() - } - - override operator fun StructureND.minus(arg: Double): Nd4jArrayStructure { - return ndArray.sub(arg).wrap() - } - - override operator fun StructureND.times(arg: Double): Nd4jArrayStructure { - return ndArray.mul(arg).wrap() - } - - override operator fun Double.div(arg: StructureND): Nd4jArrayStructure { - return arg.ndArray.rdiv(this).wrap() - } - - override operator fun Double.minus(arg: StructureND): Nd4jArrayStructure { - return arg.ndArray.rsub(this).wrap() - } -} - -/** - * Represents [FieldND] over [Nd4jArrayStructure] of [Float]. - */ -public class FloatNd4jArrayField(override val shape: IntArray) : Nd4jArrayExtendedField { - override val elementContext: FloatField get() = FloatField - - override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asFloatStructure() - - @OptIn(PerformancePitfall::class) - override val StructureND.ndArray: INDArray - get() = when (this) { - is Nd4jArrayStructure -> checkShape(ndArray) - else -> Nd4j.zeros(*shape).also { - elements().forEach { (idx, value) -> it.putScalar(idx, value) } - } - } - - override fun scale(a: StructureND, value: Double): StructureND = - a.ndArray.mul(value).wrap() - - override operator fun StructureND.div(arg: Float): Nd4jArrayStructure = - ndArray.div(arg).wrap() - - override operator fun StructureND.plus(arg: Float): Nd4jArrayStructure = - ndArray.add(arg).wrap() - - override operator fun StructureND.minus(arg: Float): Nd4jArrayStructure = - ndArray.sub(arg).wrap() - - override operator fun StructureND.times(arg: Float): Nd4jArrayStructure = - ndArray.mul(arg).wrap() - - override operator fun Float.div(arg: StructureND): Nd4jArrayStructure = - arg.ndArray.rdiv(this).wrap() - - override operator fun Float.minus(arg: StructureND): Nd4jArrayStructure = - arg.ndArray.rsub(this).wrap() -} - -/** - * Represents [RingND] over [Nd4jArrayIntStructure]. - */ -public class IntNd4jArrayRing(override val shape: IntArray) : Nd4jArrayRing { - override val elementContext: IntRing - get() = IntRing - - override fun INDArray.wrap(): Nd4jArrayStructure = checkShape(this).asIntStructure() - - @OptIn(PerformancePitfall::class) - override val StructureND.ndArray: INDArray - get() = when (this) { - is Nd4jArrayStructure -> checkShape(ndArray) - else -> Nd4j.zeros(*shape).also { - elements().forEach { (idx, value) -> it.putScalar(idx, value) } - } - } - - override operator fun StructureND.plus(arg: Int): Nd4jArrayStructure = - ndArray.add(arg).wrap() - - override operator fun StructureND.minus(arg: Int): Nd4jArrayStructure = - ndArray.sub(arg).wrap() - - override operator fun StructureND.times(arg: Int): Nd4jArrayStructure = - ndArray.mul(arg).wrap() - - 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 deleted file mode 100644 index 5ae6f6b01..000000000 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayIterator.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.nd4j - -import org.nd4j.linalg.api.ndarray.INDArray -import org.nd4j.linalg.api.shape.Shape - -private class Nd4jArrayIndicesIterator(private val iterateOver: INDArray) : Iterator { - private var i: Int = 0 - - override fun hasNext(): Boolean = i < iterateOver.length() - - override fun next(): IntArray { - val la = if (iterateOver.ordering() == 'c') - Shape.ind2subC(iterateOver, i++.toLong())!! - else - Shape.ind2sub(iterateOver, i++.toLong())!! - - return la.toIntArray() - } -} - -internal fun INDArray.indicesIterator(): Iterator = Nd4jArrayIndicesIterator(this) - -private sealed class Nd4jArrayIteratorBase(protected val iterateOver: INDArray) : Iterator> { - private var i: Int = 0 - - final override fun hasNext(): Boolean = i < iterateOver.length() - - abstract fun getSingle(indices: LongArray): T - - final override fun next(): Pair { - val la = if (iterateOver.ordering() == 'c') - Shape.ind2subC(iterateOver, i++.toLong())!! - else - Shape.ind2sub(iterateOver, i++.toLong())!! - - return la.toIntArray() to getSingle(la) - } -} - -private class Nd4jArrayDoubleIterator(iterateOver: INDArray) : Nd4jArrayIteratorBase(iterateOver) { - override fun getSingle(indices: LongArray): Double = iterateOver.getDouble(*indices) -} - -internal fun INDArray.realIterator(): Iterator> = Nd4jArrayDoubleIterator(this) - -private class Nd4jArrayIntIterator(iterateOver: INDArray) : Nd4jArrayIteratorBase(iterateOver) { - override fun getSingle(indices: LongArray) = iterateOver.getInt(*indices.toIntArray()) -} - -internal fun INDArray.intIterator(): Iterator> = Nd4jArrayIntIterator(this) - -private class Nd4jArrayFloatIterator(iterateOver: INDArray) : Nd4jArrayIteratorBase(iterateOver) { - override fun getSingle(indices: LongArray) = iterateOver.getFloat(*indices) -} - -internal fun INDArray.floatIterator(): Iterator> = Nd4jArrayFloatIterator(this) 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 deleted file mode 100644 index 82f560fdb..000000000 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructure.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.nd4j - -import org.nd4j.linalg.api.ndarray.INDArray -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.MutableStructureND -import space.kscience.kmath.nd.StructureND - -/** - * Represents a [StructureND] wrapping an [INDArray] object. - * - * @param T the type of items. - */ -public sealed class Nd4jArrayStructure : MutableStructureND { - /** - * 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 - - override val shape: IntArray get() = ndArray.shape().toIntArray() - - internal abstract fun elementsIterator(): Iterator> - internal fun indicesIterator(): Iterator = ndArray.indicesIterator() - - @PerformancePitfall - override fun elements(): Sequence> = Sequence(::elementsIterator) -} - -private data class Nd4jArrayIntStructure(override val ndArray: INDArray) : Nd4jArrayStructure() { - override fun elementsIterator(): Iterator> = ndArray.intIterator() - override fun get(index: IntArray): Int = ndArray.getInt(*index) - override fun set(index: IntArray, value: Int): Unit = run { ndArray.putScalar(index, value) } -} - -/** - * Wraps this [INDArray] to [Nd4jArrayStructure]. - */ -public fun INDArray.asIntStructure(): Nd4jArrayStructure = Nd4jArrayIntStructure(this) - -private data class Nd4jArrayDoubleStructure(override val ndArray: INDArray) : Nd4jArrayStructure() { - override fun elementsIterator(): Iterator> = ndArray.realIterator() - override fun get(index: IntArray): Double = ndArray.getDouble(*index) - override fun set(index: IntArray, value: Double): Unit = run { ndArray.putScalar(index, value) } -} - -/** - * Wraps this [INDArray] to [Nd4jArrayStructure]. - */ -public fun INDArray.asDoubleStructure(): Nd4jArrayStructure = Nd4jArrayDoubleStructure(this) - -private data class Nd4jArrayFloatStructure(override val ndArray: INDArray) : Nd4jArrayStructure() { - override fun elementsIterator(): Iterator> = ndArray.floatIterator() - override fun get(index: IntArray): Float = ndArray.getFloat(*index) - override fun set(index: IntArray, value: Float): Unit = run { ndArray.putScalar(index, value) } -} - -/** - * Wraps this [INDArray] to [Nd4jArrayStructure]. - */ -public fun INDArray.asFloatStructure(): Nd4jArrayStructure = Nd4jArrayFloatStructure(this) 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 deleted file mode 100644 index 0ac37e19b..000000000 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/Nd4jTensorAlgebra.kt +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.nd4j - -import org.nd4j.linalg.api.ndarray.INDArray -import org.nd4j.linalg.api.ops.impl.summarystats.Variance -import org.nd4j.linalg.api.ops.impl.transforms.strict.ACosh -import org.nd4j.linalg.api.ops.impl.transforms.strict.ASinh -import org.nd4j.linalg.factory.Nd4j -import org.nd4j.linalg.factory.ops.NDBase -import org.nd4j.linalg.ops.transforms.Transforms -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.api.TensorAlgebra -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra - -/** - * ND4J based [TensorAlgebra] implementation. - */ -public sealed interface Nd4jTensorAlgebra : AnalyticTensorAlgebra { - /** - * Wraps [INDArray] to [Nd4jArrayStructure]. - */ - public fun INDArray.wrap(): Nd4jArrayStructure - - /** - * Unwraps to or gets [INDArray] from [StructureND]. - */ - public val StructureND.ndArray: INDArray - - override fun T.plus(other: Tensor): Tensor = other.ndArray.add(this).wrap() - override fun Tensor.plus(value: T): Tensor = ndArray.add(value).wrap() - - override fun Tensor.plus(other: Tensor): Tensor = ndArray.add(other.ndArray).wrap() - - override fun Tensor.plusAssign(value: T) { - ndArray.addi(value) - } - - override fun Tensor.plusAssign(other: Tensor) { - ndArray.addi(other.ndArray) - } - - override fun T.minus(other: Tensor): Tensor = other.ndArray.rsub(this).wrap() - override fun Tensor.minus(value: T): Tensor = ndArray.sub(value).wrap() - override fun Tensor.minus(other: Tensor): Tensor = ndArray.sub(other.ndArray).wrap() - - override fun Tensor.minusAssign(value: T) { - ndArray.rsubi(value) - } - - override fun Tensor.minusAssign(other: Tensor) { - ndArray.subi(other.ndArray) - } - - override fun T.times(other: Tensor): Tensor = other.ndArray.mul(this).wrap() - - override fun Tensor.times(value: T): Tensor = - ndArray.mul(value).wrap() - - override fun Tensor.times(other: Tensor): Tensor = ndArray.mul(other.ndArray).wrap() - - override fun Tensor.timesAssign(value: T) { - ndArray.muli(value) - } - - override fun Tensor.timesAssign(other: Tensor) { - ndArray.mmuli(other.ndArray) - } - - override fun Tensor.unaryMinus(): Tensor = ndArray.neg().wrap() - override fun Tensor.get(i: Int): Tensor = ndArray.slice(i.toLong()).wrap() - override fun Tensor.transpose(i: Int, j: Int): Tensor = ndArray.swapAxes(i, j).wrap() - override fun Tensor.dot(other: Tensor): Tensor = ndArray.mmul(other.ndArray).wrap() - - override fun Tensor.min(dim: Int, keepDim: Boolean): Tensor = - ndArray.min(keepDim, dim).wrap() - - override fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor = - ndArray.sum(keepDim, dim).wrap() - - override fun Tensor.max(dim: Int, keepDim: Boolean): Tensor = - ndArray.max(keepDim, dim).wrap() - - override fun Tensor.view(shape: IntArray): Tensor = ndArray.reshape(shape).wrap() - override fun Tensor.viewAs(other: Tensor): Tensor = view(other.shape) - - override fun Tensor.argMax(dim: Int, keepDim: Boolean): Tensor = - ndBase.get().argmax(ndArray, keepDim, dim).wrap() - - override fun Tensor.mean(dim: Int, keepDim: Boolean): Tensor = ndArray.mean(keepDim, dim).wrap() - - override fun Tensor.exp(): Tensor = Transforms.exp(ndArray).wrap() - override fun Tensor.ln(): Tensor = Transforms.log(ndArray).wrap() - override fun Tensor.sqrt(): Tensor = Transforms.sqrt(ndArray).wrap() - override fun Tensor.cos(): Tensor = Transforms.cos(ndArray).wrap() - override fun Tensor.acos(): Tensor = Transforms.acos(ndArray).wrap() - override fun Tensor.cosh(): Tensor = Transforms.cosh(ndArray).wrap() - - override fun Tensor.acosh(): Tensor = - Nd4j.getExecutioner().exec(ACosh(ndArray, ndArray.ulike())).wrap() - - override fun Tensor.sin(): Tensor = Transforms.sin(ndArray).wrap() - override fun Tensor.asin(): Tensor = Transforms.asin(ndArray).wrap() - override fun Tensor.sinh(): Tensor = Transforms.sinh(ndArray).wrap() - - override fun Tensor.asinh(): Tensor = - Nd4j.getExecutioner().exec(ASinh(ndArray, ndArray.ulike())).wrap() - - override fun Tensor.tan(): Tensor = Transforms.tan(ndArray).wrap() - override fun Tensor.atan(): Tensor = Transforms.atan(ndArray).wrap() - override fun Tensor.tanh(): Tensor = Transforms.tanh(ndArray).wrap() - override fun Tensor.atanh(): Tensor = Transforms.atanh(ndArray).wrap() - override fun Tensor.ceil(): Tensor = Transforms.ceil(ndArray).wrap() - override fun Tensor.floor(): Tensor = Transforms.floor(ndArray).wrap() - override fun Tensor.std(dim: Int, keepDim: Boolean): Tensor = ndArray.std(true, keepDim, dim).wrap() - override fun T.div(other: Tensor): Tensor = other.ndArray.rdiv(this).wrap() - override fun Tensor.div(value: T): Tensor = ndArray.div(value).wrap() - override fun Tensor.div(other: Tensor): Tensor = ndArray.div(other.ndArray).wrap() - - override fun Tensor.divAssign(value: T) { - ndArray.divi(value) - } - - override fun Tensor.divAssign(other: Tensor) { - ndArray.divi(other.ndArray) - } - - override fun Tensor.variance(dim: Int, keepDim: Boolean): Tensor = - Nd4j.getExecutioner().exec(Variance(ndArray, true, true, dim)).wrap() - - private companion object { - private val ndBase: ThreadLocal = ThreadLocal.withInitial(::NDBase) - } -} - -/** - * [Double] specialization of [Nd4jTensorAlgebra]. - */ -public object DoubleNd4jTensorAlgebra : Nd4jTensorAlgebra { - override fun INDArray.wrap(): Nd4jArrayStructure = asDoubleStructure() - - @OptIn(PerformancePitfall::class) - override val StructureND.ndArray: INDArray - get() = when (this) { - is Nd4jArrayStructure -> ndArray - else -> Nd4j.zeros(*shape).also { - elements().forEach { (idx, value) -> it.putScalar(idx, value) } - } - } - - override fun Tensor.valueOrNull(): Double? = - if (shape contentEquals intArrayOf(1)) ndArray.getDouble(0) else null - - // TODO rewrite - @PerformancePitfall - override fun diagonalEmbedding( - diagonalEntries: Tensor, - offset: Int, - dim1: Int, - dim2: Int, - ): Tensor = DoubleTensorAlgebra.diagonalEmbedding(diagonalEntries, offset, dim1, dim2) - - 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 deleted file mode 100644 index cc9211b20..000000000 --- a/kmath-nd4j/src/main/kotlin/space/kscience/kmath/nd4j/arrays.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.nd4j - -import space.kscience.kmath.misc.toIntExact - -internal fun LongArray.toIntArray(): IntArray = IntArray(size) { this[it].toIntExact() } diff --git a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt deleted file mode 100644 index a03a7269e..000000000 --- a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayAlgebraTest.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.nd4j - -import org.nd4j.linalg.factory.Nd4j -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.StructureND -import space.kscience.kmath.operations.invoke -import kotlin.math.PI -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue -import kotlin.test.fail - -@OptIn(PerformancePitfall::class) -internal class Nd4jArrayAlgebraTest { - @Test - fun testProduce() { - val res = with(DoubleNd4jArrayField(intArrayOf(2, 2))) { produce { it.sum().toDouble() } } - val expected = (Nd4j.create(2, 2) ?: fail()).asDoubleStructure() - expected[intArrayOf(0, 0)] = 0.0 - expected[intArrayOf(0, 1)] = 1.0 - expected[intArrayOf(1, 0)] = 1.0 - expected[intArrayOf(1, 1)] = 2.0 - assertEquals(expected, res) - } - - @Test - fun testMap() { - val res = with(IntNd4jArrayRing(intArrayOf(2, 2))) { one.map { it + it * 2 } } - val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure() - expected[intArrayOf(0, 0)] = 3 - expected[intArrayOf(0, 1)] = 3 - expected[intArrayOf(1, 0)] = 3 - expected[intArrayOf(1, 1)] = 3 - assertEquals(expected, res) - } - - @Test - fun testAdd() { - val res = with(IntNd4jArrayRing(intArrayOf(2, 2))) { one + 25 } - val expected = (Nd4j.create(2, 2) ?: fail()).asIntStructure() - expected[intArrayOf(0, 0)] = 26 - expected[intArrayOf(0, 1)] = 26 - expected[intArrayOf(1, 0)] = 26 - expected[intArrayOf(1, 1)] = 26 - assertEquals(expected, res) - } - - @Test - fun testSin() = DoubleNd4jArrayField(intArrayOf(2, 2)).invoke { - val initial = produce { (i, j) -> if (i == j) PI / 2 else 0.0 } - val transformed = sin(initial) - val expected = produce { (i, j) -> if (i == j) 1.0 else 0.0 } - - println(transformed) - assertTrue { StructureND.contentEquals(transformed, expected) } - } -} diff --git a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt b/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt deleted file mode 100644 index ff55ad521..000000000 --- a/kmath-nd4j/src/test/kotlin/space/kscience/kmath/nd4j/Nd4jArrayStructureTest.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.nd4j - -import org.nd4j.linalg.factory.Nd4j -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.get -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotEquals -import kotlin.test.fail - -internal class Nd4jArrayStructureTest { - @OptIn(PerformancePitfall::class) - @Test - fun testElements() { - val nd = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0))!! - val struct = nd.asDoubleStructure() - val res = struct.elements().map(Pair::second).toList() - assertEquals(listOf(1.0, 2.0, 3.0), res) - } - - @Test - fun testShape() { - val nd = Nd4j.rand(10, 2, 3, 6) ?: fail() - val struct = nd.asDoubleStructure() - assertEquals(intArrayOf(10, 2, 3, 6).toList(), struct.shape.toList()) - } - - @Test - fun testEquals() { - val nd1 = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0)) ?: fail() - val struct1 = nd1.asDoubleStructure() - assertEquals(struct1, struct1) - assertNotEquals(struct1 as Any?, null) - val nd2 = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0)) ?: fail() - val struct2 = nd2.asDoubleStructure() - assertEquals(struct1, struct2) - assertEquals(struct2, struct1) - val nd3 = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0)) ?: fail() - val struct3 = nd3.asDoubleStructure() - assertEquals(struct2, struct3) - assertEquals(struct1, struct3) - } - - @Test - fun testHashCode() { - val nd1 = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0)) ?: fail() - val struct1 = nd1.asDoubleStructure() - val nd2 = Nd4j.create(doubleArrayOf(1.0, 2.0, 3.0)) ?: fail() - val struct2 = nd2.asDoubleStructure() - assertEquals(struct1.hashCode(), struct2.hashCode()) - } - - @Test - fun testDimension() { - val nd = Nd4j.rand(8, 16, 3, 7, 1)!! - val struct = nd.asFloatStructure() - assertEquals(5, struct.dimension) - } - - @Test - fun testGet() { - val nd = Nd4j.rand(10, 2, 3, 6) ?: fail() - val struct = nd.asIntStructure() - assertEquals(nd.getInt(0, 0, 0, 0), struct[0, 0, 0, 0]) - } - - @Test - fun testSet() { - val nd = Nd4j.rand(17, 12, 4, 8)!! - val struct = nd.asIntStructure() - struct[intArrayOf(1, 2, 3, 4)] = 777 - assertEquals(777, struct[1, 2, 3, 4]) - } -} diff --git a/kmath-stat/build.gradle.kts b/kmath-prob/build.gradle.kts similarity index 53% rename from kmath-stat/build.gradle.kts rename to kmath-prob/build.gradle.kts index e3e396b6f..a69d61b73 100644 --- a/kmath-stat/build.gradle.kts +++ b/kmath-prob/build.gradle.kts @@ -1,11 +1,5 @@ plugins { - kotlin("multiplatform") - id("ru.mipt.npm.gradle.common") - id("ru.mipt.npm.gradle.native") -} - -kscience { - useAtomic() + id("scientifik.mpp") } kotlin.sourceSets { @@ -14,15 +8,10 @@ kotlin.sourceSets { api(project(":kmath-coroutines")) } } - - jvmMain { - dependencies { + jvmMain{ + dependencies{ api("org.apache.commons:commons-rng-sampling:1.3") api("org.apache.commons:commons-rng-simple:1.3") } } -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL } \ No newline at end of file diff --git a/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/Distribution.kt b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/Distribution.kt new file mode 100644 index 000000000..3b874adaa --- /dev/null +++ b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/Distribution.kt @@ -0,0 +1,76 @@ +package scientifik.kmath.prob + +import scientifik.kmath.chains.Chain +import scientifik.kmath.chains.collect +import scientifik.kmath.structures.Buffer +import scientifik.kmath.structures.BufferFactory + +interface Sampler { + fun sample(generator: RandomGenerator): Chain +} + +/** + * A distribution of typed objects + */ +interface Distribution : Sampler { + /** + * A probability value for given argument [arg]. + * For continuous distributions returns PDF + */ + fun probability(arg: T): Double + + /** + * Create a chain of samples from this distribution. + * The chain is not guaranteed to be stateless, but different sample chains should be independent. + */ + override fun sample(generator: RandomGenerator): Chain + + /** + * An empty companion. Distribution factories should be written as its extensions + */ + companion object +} + +interface UnivariateDistribution> : Distribution { + /** + * Cumulative distribution for ordered parameter (CDF) + */ + fun cumulative(arg: T): Double +} + +/** + * Compute probability integral in an interval + */ +fun > UnivariateDistribution.integral(from: T, to: T): Double { + require(to > from) + return cumulative(to) - cumulative(from) +} + +/** + * Sample a bunch of values + */ +fun Sampler.sampleBuffer( + generator: RandomGenerator, + size: Int, + bufferFactory: BufferFactory = Buffer.Companion::boxing +): Chain> { + require(size > 1) + //creating temporary storage once + val tmp = ArrayList(size) + return sample(generator).collect { chain -> + //clear list from previous run + tmp.clear() + //Fill list + repeat(size){ + tmp.add(chain.next()) + } + //return new buffer with elements from tmp + bufferFactory(size) { tmp[it] } + } +} + +/** + * Generate a bunch of samples from real distributions + */ +fun Sampler.sampleBuffer(generator: RandomGenerator, size: Int) = + sampleBuffer(generator, size, Buffer.Companion::real) \ No newline at end of file diff --git a/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/FactorizedDistribution.kt b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/FactorizedDistribution.kt new file mode 100644 index 000000000..ea526c058 --- /dev/null +++ b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/FactorizedDistribution.kt @@ -0,0 +1,47 @@ +package scientifik.kmath.prob + +import scientifik.kmath.chains.Chain +import scientifik.kmath.chains.SimpleChain + +/** + * A multivariate distribution which takes a map of parameters + */ +interface NamedDistribution : Distribution> + +/** + * A multivariate distribution that has independent distributions for separate axis + */ +class FactorizedDistribution(val distributions: Collection>) : NamedDistribution { + + override fun probability(arg: Map): Double { + return distributions.fold(1.0) { acc, distr -> acc * distr.probability(arg) } + } + + override fun sample(generator: RandomGenerator): Chain> { + val chains = distributions.map { it.sample(generator) } + return SimpleChain> { + chains.fold(emptyMap()) { acc, chain -> acc + chain.next() } + } + } +} + +class NamedDistributionWrapper(val name: String, val distribution: Distribution) : NamedDistribution { + override fun probability(arg: Map): Double = distribution.probability( + arg[name] ?: error("Argument with name $name not found in input parameters") + ) + + override fun sample(generator: RandomGenerator): Chain> { + val chain = distribution.sample(generator) + return SimpleChain { + mapOf(name to chain.next()) + } + } +} + +class DistributionBuilder{ + private val distributions = ArrayList>() + + infix fun String.to(distribution: Distribution){ + distributions.add(NamedDistributionWrapper(this,distribution)) + } +} \ No newline at end of file diff --git a/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/RandomChain.kt b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/RandomChain.kt new file mode 100644 index 000000000..47fc6e4c5 --- /dev/null +++ b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/RandomChain.kt @@ -0,0 +1,14 @@ +package scientifik.kmath.prob + +import scientifik.kmath.chains.Chain + +/** + * A possibly stateful chain producing random values. + */ +class RandomChain(val generator: RandomGenerator, private val gen: suspend RandomGenerator.() -> R) : Chain { + override suspend fun next(): R = generator.gen() + + override fun fork(): Chain = RandomChain(generator.fork(), gen) +} + +fun RandomGenerator.chain(gen: suspend RandomGenerator.() -> R): RandomChain = RandomChain(this, gen) \ No newline at end of file diff --git a/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/RandomGenerator.kt b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/RandomGenerator.kt new file mode 100644 index 000000000..2a225fe47 --- /dev/null +++ b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/RandomGenerator.kt @@ -0,0 +1,55 @@ +package scientifik.kmath.prob + +import kotlin.random.Random + +/** + * A basic generator + */ +interface RandomGenerator { + fun nextBoolean(): Boolean + + fun nextDouble(): Double + fun nextInt(): Int + fun nextInt(until: Int): Int + fun nextLong(): Long + fun nextLong(until: Long): Long + + fun fillBytes(array: ByteArray, fromIndex: Int = 0, toIndex: Int = array.size) + 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 + * 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. + * + * The thread safety of this operation is not guaranteed since it could affect the state of the generator. + */ + fun fork(): RandomGenerator + + companion object { + val default by lazy { DefaultGenerator() } + + fun default(seed: Long) = DefaultGenerator(Random(seed)) + } +} + +inline class DefaultGenerator(val random: Random = Random) : RandomGenerator { + 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) + + override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { + random.nextBytes(array, fromIndex, toIndex) + } + + override fun nextBytes(size: Int): ByteArray = random.nextBytes(size) + + override fun fork(): RandomGenerator = RandomGenerator.default(random.nextLong()) +} \ No newline at end of file diff --git a/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/SamplerAlgebra.kt b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/SamplerAlgebra.kt new file mode 100644 index 000000000..3a60c0bda --- /dev/null +++ b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/SamplerAlgebra.kt @@ -0,0 +1,31 @@ +package scientifik.kmath.prob + +import scientifik.kmath.chains.Chain +import scientifik.kmath.chains.ConstantChain +import scientifik.kmath.chains.map +import scientifik.kmath.chains.zip +import scientifik.kmath.operations.Space + +class BasicSampler(val chainBuilder: (RandomGenerator) -> Chain) : Sampler { + override fun sample(generator: RandomGenerator): Chain = chainBuilder(generator) +} + +class ConstantSampler(val value: T) : Sampler { + override fun sample(generator: RandomGenerator): Chain = ConstantChain(value) +} + +/** + * A space for samplers. Allows to perform simple operations on distributions + */ +class SamplerSpace(val space: Space) : Space> { + + override val zero: Sampler = ConstantSampler(space.zero) + + override fun add(a: Sampler, b: Sampler): Sampler = BasicSampler { generator -> + a.sample(generator).zip(b.sample(generator)) { aValue, bValue -> space.run { aValue + bValue } } + } + + override fun multiply(a: Sampler, k: Number): Sampler = BasicSampler { generator -> + a.sample(generator).map { space.run { it * k.toDouble() } } + } +} \ No newline at end of file diff --git a/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/Statistic.kt b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/Statistic.kt new file mode 100644 index 000000000..804aed089 --- /dev/null +++ b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/Statistic.kt @@ -0,0 +1,95 @@ +package scientifik.kmath.prob + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.scanReduce +import scientifik.kmath.coroutines.mapParallel +import scientifik.kmath.operations.* +import scientifik.kmath.structures.Buffer +import scientifik.kmath.structures.asIterable +import scientifik.kmath.structures.asSequence + +/** + * A function, that transforms a buffer of random quantities to some resulting value + */ +interface Statistic { + suspend operator fun invoke(data: Buffer): R +} + +/** + * 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 + */ +interface ComposableStatistic : Statistic { + //compute statistic on a single block + suspend fun computeIntermediate(data: Buffer): I + //Compose two blocks + suspend fun composeIntermediate(first: I, second: I): I + //Transform block to result + suspend fun toResult(intermediate: I): R + + override suspend fun invoke(data: Buffer): R = toResult(computeIntermediate(data)) +} + +@FlowPreview +@ExperimentalCoroutinesApi +private fun ComposableStatistic.flowIntermediate( + flow: Flow>, + dispatcher: CoroutineDispatcher = Dispatchers.Default +): Flow = flow + .mapParallel(dispatcher) { computeIntermediate(it) } + .scanReduce(::composeIntermediate) + + +/** + * Perform a streaming statistical analysis on a chunked data. The computation of inner representation is done in parallel + * if [dispatcher] allows it. + * + * The resulting flow contains values that include the whole previous statistics, not only the last chunk. + */ +@FlowPreview +@ExperimentalCoroutinesApi +fun ComposableStatistic.flow( + flow: Flow>, + dispatcher: CoroutineDispatcher = Dispatchers.Default +): Flow = flowIntermediate(flow,dispatcher).map(::toResult) + +/** + * Arithmetic mean + */ +class Mean(val space: Space) : ComposableStatistic, T> { + override suspend fun computeIntermediate(data: Buffer): Pair = + space.run { sum(data.asIterable()) } to data.size + + override suspend fun composeIntermediate(first: Pair, second: Pair): Pair = + space.run { first.first + second.first } to (first.second + second.second) + + override suspend fun toResult(intermediate: Pair): T = + space.run { intermediate.first / intermediate.second } + + companion object { + //TODO replace with optimized version which respects overflow + val real = Mean(RealField) + val int = Mean(IntRing) + val long = Mean(LongRing) + } +} + +/** + * Non-composable median + */ +class Median(private val comparator: Comparator) : Statistic { + override suspend fun invoke(data: Buffer): T { + return data.asSequence().sortedWith(comparator).toList()[data.size / 2] //TODO check if this is correct + } + + companion object { + val real = Median(Comparator { a: Double, b: Double -> a.compareTo(b) }) + } +} \ No newline at end of file diff --git a/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/UniformDistribution.kt b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/UniformDistribution.kt new file mode 100644 index 000000000..9d96bff59 --- /dev/null +++ b/kmath-prob/src/commonMain/kotlin/scientifik/kmath/prob/UniformDistribution.kt @@ -0,0 +1,34 @@ +package scientifik.kmath.prob + +import scientifik.kmath.chains.Chain +import scientifik.kmath.chains.SimpleChain + +class UniformDistribution(val range: ClosedFloatingPointRange) : UnivariateDistribution { + + private val length = range.endInclusive - range.start + + override fun probability(arg: Double): Double { + return if (arg in range) { + return 1.0 / length + } else { + 0.0 + } + } + + override fun sample(generator: RandomGenerator): Chain { + return SimpleChain { + range.start + generator.nextDouble() * length + } + } + + override fun cumulative(arg: Double): Double { + return when { + arg < range.start -> 0.0 + arg >= range.endInclusive -> 1.0 + else -> (arg - range.start) / length + } + } +} + +fun Distribution.Companion.uniform(range: ClosedFloatingPointRange): UniformDistribution = + UniformDistribution(range) \ No newline at end of file diff --git a/kmath-prob/src/jvmMain/kotlin/scientifik/kmath/prob/RandomSourceGenerator.kt b/kmath-prob/src/jvmMain/kotlin/scientifik/kmath/prob/RandomSourceGenerator.kt new file mode 100644 index 000000000..f5a73a08b --- /dev/null +++ b/kmath-prob/src/jvmMain/kotlin/scientifik/kmath/prob/RandomSourceGenerator.kt @@ -0,0 +1,67 @@ +package scientifik.kmath.prob + +import org.apache.commons.rng.UniformRandomProvider +import org.apache.commons.rng.simple.RandomSource + +class RandomSourceGenerator(val source: RandomSource, seed: Long?) : RandomGenerator { + internal val random: UniformRandomProvider = seed?.let { + RandomSource.create(source, seed) + } ?: RandomSource.create(source) + + 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) + + override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { + require(toIndex > fromIndex) + random.nextBytes(array, fromIndex, toIndex - fromIndex) + } + + override fun fork(): RandomGenerator = RandomSourceGenerator(source, nextLong()) +} + +inline class RandomGeneratorProvider(val generator: RandomGenerator) : UniformRandomProvider { + override fun nextBoolean(): Boolean = generator.nextBoolean() + + override fun nextFloat(): Float = generator.nextDouble().toFloat() + + override fun nextBytes(bytes: ByteArray) { + generator.fillBytes(bytes) + } + + override fun nextBytes(bytes: ByteArray, start: Int, len: Int) { + generator.fillBytes(bytes, start, start + len) + } + + override fun nextInt(): Int = generator.nextInt() + + override fun nextInt(n: Int): Int = generator.nextInt(n) + + override fun nextDouble(): Double = generator.nextDouble() + + override fun nextLong(): Long = generator.nextLong() + + override fun nextLong(n: Long): Long = generator.nextLong(n) +} + +/** + * Represent this [RandomGenerator] as commons-rng [UniformRandomProvider] preserving and mirroring its current state. + * Getting new value from one of those changes the state of another. + */ +fun RandomGenerator.asUniformRandomProvider(): UniformRandomProvider = if (this is RandomSourceGenerator) { + random +} else { + RandomGeneratorProvider(this) +} + +fun RandomGenerator.Companion.fromSource(source: RandomSource, seed: Long? = null): RandomSourceGenerator = + RandomSourceGenerator(source, seed) + +fun RandomGenerator.Companion.mersenneTwister(seed: Long? = null): RandomSourceGenerator = + fromSource(RandomSource.MT, seed) diff --git a/kmath-prob/src/jvmMain/kotlin/scientifik/kmath/prob/distributions.kt b/kmath-prob/src/jvmMain/kotlin/scientifik/kmath/prob/distributions.kt new file mode 100644 index 000000000..412454994 --- /dev/null +++ b/kmath-prob/src/jvmMain/kotlin/scientifik/kmath/prob/distributions.kt @@ -0,0 +1,109 @@ +package scientifik.kmath.prob + +import org.apache.commons.rng.UniformRandomProvider +import org.apache.commons.rng.sampling.distribution.* +import scientifik.kmath.chains.BlockingIntChain +import scientifik.kmath.chains.BlockingRealChain +import scientifik.kmath.chains.Chain +import java.util.* +import kotlin.math.PI +import kotlin.math.exp +import kotlin.math.pow +import kotlin.math.sqrt + +abstract class ContinuousSamplerDistribution : Distribution { + + private inner class ContinuousSamplerChain(val generator: RandomGenerator) : BlockingRealChain() { + private val sampler = buildCMSampler(generator) + + override fun nextDouble(): Double = sampler.sample() + + override fun fork(): Chain = ContinuousSamplerChain(generator.fork()) + } + + protected abstract fun buildCMSampler(generator: RandomGenerator): ContinuousSampler + + override fun sample(generator: RandomGenerator): BlockingRealChain = ContinuousSamplerChain(generator) +} + +abstract class DiscreteSamplerDistribution : Distribution { + + private inner class ContinuousSamplerChain(val generator: RandomGenerator) : BlockingIntChain() { + private val sampler = buildSampler(generator) + + override fun nextInt(): Int = sampler.sample() + + override fun fork(): Chain = ContinuousSamplerChain(generator.fork()) + } + + protected abstract fun buildSampler(generator: RandomGenerator): DiscreteSampler + + override fun sample(generator: RandomGenerator): BlockingIntChain = ContinuousSamplerChain(generator) +} + +enum class NormalSamplerMethod { + BoxMuller, + Marsaglia, + Ziggurat +} + +private fun normalSampler(method: NormalSamplerMethod, provider: UniformRandomProvider): NormalizedGaussianSampler = + when (method) { + NormalSamplerMethod.BoxMuller -> BoxMullerNormalizedGaussianSampler(provider) + NormalSamplerMethod.Marsaglia -> MarsagliaNormalizedGaussianSampler(provider) + NormalSamplerMethod.Ziggurat -> ZigguratNormalizedGaussianSampler(provider) + } + +fun Distribution.Companion.normal( + method: NormalSamplerMethod = NormalSamplerMethod.Ziggurat +): Distribution = object : ContinuousSamplerDistribution() { + override fun buildCMSampler(generator: RandomGenerator): ContinuousSampler { + val provider: UniformRandomProvider = generator.asUniformRandomProvider() + return normalSampler(method, provider) + } + + override fun probability(arg: Double): Double { + return exp(-arg.pow(2) / 2) / sqrt(PI * 2) + } +} + +fun Distribution.Companion.normal( + mean: Double, + sigma: Double, + method: NormalSamplerMethod = NormalSamplerMethod.Ziggurat +): ContinuousSamplerDistribution = object : ContinuousSamplerDistribution() { + private val sigma2 = sigma.pow(2) + private val norm = sigma * sqrt(PI * 2) + + override fun buildCMSampler(generator: RandomGenerator): ContinuousSampler { + val provider: UniformRandomProvider = generator.asUniformRandomProvider() + val normalizedSampler = normalSampler(method, provider) + return GaussianSampler(normalizedSampler, mean, sigma) + } + + override fun probability(arg: Double): Double { + return exp(-(arg - mean).pow(2) / 2 / sigma2) / norm + } +} + +fun Distribution.Companion.poisson( + lambda: Double +): DiscreteSamplerDistribution = object : DiscreteSamplerDistribution() { + + override fun buildSampler(generator: RandomGenerator): DiscreteSampler { + return PoissonSampler.of(generator.asUniformRandomProvider(), lambda) + } + + private val computedProb: HashMap = hashMapOf(0 to exp(-lambda)) + + override fun probability(arg: Int): Double { + require(arg >= 0) { "The argument must be >= 0" } + return if (arg > 40) { + exp(-(arg - lambda).pow(2) / 2 / lambda) / sqrt(2 * PI * lambda) + } else { + computedProb.getOrPut(arg) { + probability(arg - 1) * lambda / arg + } + } + } +} diff --git a/kmath-prob/src/jvmTest/kotlin/scientifik/kmath/prob/CommonsDistributionsTest.kt b/kmath-prob/src/jvmTest/kotlin/scientifik/kmath/prob/CommonsDistributionsTest.kt new file mode 100644 index 000000000..7638c695e --- /dev/null +++ b/kmath-prob/src/jvmTest/kotlin/scientifik/kmath/prob/CommonsDistributionsTest.kt @@ -0,0 +1,28 @@ +package scientifik.kmath.prob + +import kotlinx.coroutines.flow.take +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + +class CommonsDistributionsTest { + @Test + fun testNormalDistributionSuspend() { + val distribution = Distribution.normal(7.0, 2.0) + val generator = RandomGenerator.default(1) + val sample = runBlocking { + distribution.sample(generator).take(1000).toList() + } + Assertions.assertEquals(7.0, sample.average(), 0.1) + } + + @Test + fun testNormalDistributionBlocking() { + val distribution = Distribution.normal(7.0, 2.0) + val generator = RandomGenerator.default(1) + val sample = distribution.sample(generator).nextBlock(1000) + Assertions.assertEquals(7.0, sample.average(), 0.1) + } + +} \ No newline at end of file diff --git a/kmath-prob/src/jvmTest/kotlin/scientifik/kmath/prob/SamplerTest.kt b/kmath-prob/src/jvmTest/kotlin/scientifik/kmath/prob/SamplerTest.kt new file mode 100644 index 000000000..1152f3057 --- /dev/null +++ b/kmath-prob/src/jvmTest/kotlin/scientifik/kmath/prob/SamplerTest.kt @@ -0,0 +1,17 @@ +package scientifik.kmath.prob + +import kotlinx.coroutines.runBlocking +import kotlin.test.Test + +class SamplerTest { + + @Test + fun bufferSamplerTest(){ + val sampler: Sampler = + BasicSampler { it.chain { nextDouble() } } + val data = sampler.sampleBuffer(RandomGenerator.default, 100) + runBlocking { + println(data.next()) + } + } +} \ No newline at end of file diff --git a/kmath-prob/src/jvmTest/kotlin/scientifik/kmath/prob/StatisticTest.kt b/kmath-prob/src/jvmTest/kotlin/scientifik/kmath/prob/StatisticTest.kt new file mode 100644 index 000000000..2613f71d5 --- /dev/null +++ b/kmath-prob/src/jvmTest/kotlin/scientifik/kmath/prob/StatisticTest.kt @@ -0,0 +1,28 @@ +package scientifik.kmath.prob + +import kotlinx.coroutines.flow.drop +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking + +import scientifik.kmath.streaming.chunked +import kotlin.test.Test + +class StatisticTest { + //create a random number generator. + val generator = RandomGenerator.default(1) + //Create a stateless chain from generator. + val data = generator.chain { nextDouble() } + //Convert a chaint to Flow and break it into chunks. + val chunked = data.chunked(1000) + + @Test + fun testParallelMean() { + runBlocking { + val average = Mean.real + .flow(chunked) //create a flow with results + .drop(99) // Skip first 99 values and use one with total data + .first() //get 1e5 data samples average + println(average) + } + } +} \ No newline at end of file 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 deleted file mode 100644 index 298bbc858..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/Distribution.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.distributions - -import space.kscience.kmath.chains.Chain -import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.stat.Sampler - -/** - * A distribution of typed objects. - */ -public interface Distribution : Sampler { - /** - * A probability value for given argument [arg]. - * For continuous distributions returns PDF - */ - public fun probability(arg: T): Double - - override fun sample(generator: RandomGenerator): Chain - - /** - * An empty companion. Distribution factories should be written as its extensions. - */ - public companion object -} - -public interface UnivariateDistribution> : Distribution { - /** - * Cumulative distribution for ordered parameter (CDF) - */ - public fun cumulative(arg: T): Double -} - -/** - * Compute probability integral in an interval - */ -public fun > UnivariateDistribution.integral(from: T, to: T): Double { - require(to > from) - return cumulative(to) - cumulative(from) -} 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 deleted file mode 100644 index 067b47796..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/FactorizedDistribution.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.distributions - -import space.kscience.kmath.chains.Chain -import space.kscience.kmath.chains.SimpleChain -import space.kscience.kmath.stat.RandomGenerator - -/** - * A multivariate distribution that takes a map of parameters. - */ -public interface NamedDistribution : Distribution> - -/** - * A multivariate distribution that has independent distributions for separate axis. - */ -public class FactorizedDistribution(public val distributions: Collection>) : - NamedDistribution { - override fun probability(arg: Map): Double = - distributions.fold(1.0) { acc, dist -> acc * dist.probability(arg) } - - override fun sample(generator: RandomGenerator): Chain> { - val chains = distributions.map { it.sample(generator) } - return SimpleChain { chains.fold(emptyMap()) { acc, chain -> acc + chain.next() } } - } -} - -public class NamedDistributionWrapper(public val name: String, public val distribution: Distribution) : - NamedDistribution { - override fun probability(arg: Map): Double = distribution.probability( - arg[name] ?: error("Argument with name $name not found in input parameters") - ) - - override fun sample(generator: RandomGenerator): Chain> { - val chain = distribution.sample(generator) - return SimpleChain { mapOf(name to chain.next()) } - } -} - -public class DistributionBuilder { - private val distributions = ArrayList>() - - public infix fun String.to(distribution: Distribution) { - distributions += NamedDistributionWrapper(this, distribution) - } -} 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 deleted file mode 100644 index 24429cf32..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/distributions/NormalDistribution.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.distributions - -import space.kscience.kmath.chains.Chain -import space.kscience.kmath.internal.InternalErf -import space.kscience.kmath.samplers.GaussianSampler -import space.kscience.kmath.samplers.NormalizedGaussianSampler -import space.kscience.kmath.samplers.ZigguratNormalizedGaussianSampler -import space.kscience.kmath.stat.RandomGenerator -import kotlin.math.* - -/** - * Implements [UnivariateDistribution] for the normal (gaussian) distribution. - */ -public class NormalDistribution(public val sampler: GaussianSampler) : UnivariateDistribution { - public constructor( - mean: Double, - standardDeviation: Double, - normalized: NormalizedGaussianSampler = ZigguratNormalizedGaussianSampler, - ) : this(GaussianSampler(mean, standardDeviation, normalized)) - - 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))) - } - - override fun sample(generator: RandomGenerator): Chain = sampler.sample(generator) - - override fun cumulative(arg: Double): Double { - val dev = arg - sampler.mean - - return when { - abs(dev) > 40 * sampler.standardDeviation -> if (dev < 0) 0.0 else 1.0 - else -> 0.5 * InternalErf.erfc(-dev / (sampler.standardDeviation * SQRT2)) - } - } - - private companion object { - private val SQRT2 = sqrt(2.0) - } -} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt deleted file mode 100644 index 5b3cb1859..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalErf.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.internal - -import kotlin.math.abs - -/** - * Based on Commons Math implementation. - * See [https://commons.apache.org/proper/commons-math/javadocs/api-3.3/org/apache/commons/math3/special/Erf.html]. - */ -internal object InternalErf { - fun erfc(x: Double): Double { - if (abs(x) > 40) return if (x > 0) 0.0 else 2.0 - val ret = InternalGamma.regularizedGammaQ(0.5, x * x, 10000) - return if (x < 0) 2 - ret else ret - } -} \ No newline at end of file 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 deleted file mode 100644 index 18abd669f..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalGamma.kt +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.internal - -import kotlin.math.* - -private abstract class ContinuedFraction protected constructor() { - protected abstract fun getA(n: Int, x: Double): Double - protected abstract fun getB(n: Int, x: Double): Double - - fun evaluate(x: Double, maxIterations: Int): Double { - val small = 1e-50 - var hPrev = getA(0, x) - if (hPrev == 0.0 || abs(0.0 - hPrev) <= small) hPrev = small - var n = 1 - var dPrev = 0.0 - var cPrev = hPrev - var hN = hPrev - - while (n < maxIterations) { - val a = getA(n, x) - val b = getB(n, x) - var dN = a + b * dPrev - if (dN == 0.0 || abs(0.0 - dN) <= small) dN = small - var cN = a + b / cPrev - if (cN == 0.0 || abs(0.0 - cN) <= small) cN = small - dN = 1 / dN - val deltaN = cN * dN - hN = hPrev * deltaN - check(!hN.isInfinite()) { "hN is infinite" } - check(!hN.isNaN()) { "hN is NaN" } - if (abs(deltaN - 1.0) < 10e-9) break - dPrev = dN - cPrev = cN - hPrev = hN - n++ - } - - check(n < maxIterations) { "n is more than maxIterations" } - return hN - } -} - -internal object InternalGamma { - const val LANCZOS_G = 607.0 / 128.0 - - private val LANCZOS = doubleArrayOf( - 0.99999999999999709182, - 57.156235665862923517, - -59.597960355475491248, - 14.136097974741747174, - -0.49191381609762019978, - .33994649984811888699e-4, - .46523628927048575665e-4, - -.98374475304879564677e-4, - .15808870322491248884e-3, - -.21026444172410488319e-3, - .21743961811521264320e-3, - -.16431810653676389022e-3, - .84418223983852743293e-4, - -.26190838401581408670e-4, - .36899182659531622704e-5 - ) - - private val HALF_LOG_2_PI = 0.5 * ln(2.0 * PI) - private const val INV_GAMMA1P_M1_A0 = .611609510448141581788E-08 - private const val INV_GAMMA1P_M1_A1 = .624730830116465516210E-08 - private const val INV_GAMMA1P_M1_B1 = .203610414066806987300E+00 - private const val INV_GAMMA1P_M1_B2 = .266205348428949217746E-01 - private const val INV_GAMMA1P_M1_B3 = .493944979382446875238E-03 - private const val INV_GAMMA1P_M1_B4 = -.851419432440314906588E-05 - private const val INV_GAMMA1P_M1_B5 = -.643045481779353022248E-05 - private const val INV_GAMMA1P_M1_B6 = .992641840672773722196E-06 - private const val INV_GAMMA1P_M1_B7 = -.607761895722825260739E-07 - private const val INV_GAMMA1P_M1_B8 = .195755836614639731882E-09 - private const val INV_GAMMA1P_M1_P0 = .6116095104481415817861E-08 - private const val INV_GAMMA1P_M1_P1 = .6871674113067198736152E-08 - private const val INV_GAMMA1P_M1_P2 = .6820161668496170657918E-09 - private const val INV_GAMMA1P_M1_P3 = .4686843322948848031080E-10 - private const val INV_GAMMA1P_M1_P4 = .1572833027710446286995E-11 - private const val INV_GAMMA1P_M1_P5 = -.1249441572276366213222E-12 - private const val INV_GAMMA1P_M1_P6 = .4343529937408594255178E-14 - private const val INV_GAMMA1P_M1_Q1 = .3056961078365221025009E+00 - private const val INV_GAMMA1P_M1_Q2 = .5464213086042296536016E-01 - private const val INV_GAMMA1P_M1_Q3 = .4956830093825887312020E-02 - private const val INV_GAMMA1P_M1_Q4 = .2692369466186361192876E-03 - private const val INV_GAMMA1P_M1_C = -.422784335098467139393487909917598E+00 - private const val INV_GAMMA1P_M1_C0 = .577215664901532860606512090082402E+00 - private const val INV_GAMMA1P_M1_C1 = -.655878071520253881077019515145390E+00 - private const val INV_GAMMA1P_M1_C2 = -.420026350340952355290039348754298E-01 - private const val INV_GAMMA1P_M1_C3 = .166538611382291489501700795102105E+00 - private const val INV_GAMMA1P_M1_C4 = -.421977345555443367482083012891874E-01 - private const val INV_GAMMA1P_M1_C5 = -.962197152787697356211492167234820E-02 - private const val INV_GAMMA1P_M1_C6 = .721894324666309954239501034044657E-02 - private const val INV_GAMMA1P_M1_C7 = -.116516759185906511211397108401839E-02 - private const val INV_GAMMA1P_M1_C8 = -.215241674114950972815729963053648E-03 - private const val INV_GAMMA1P_M1_C9 = .128050282388116186153198626328164E-03 - private const val INV_GAMMA1P_M1_C10 = -.201348547807882386556893914210218E-04 - private const val INV_GAMMA1P_M1_C11 = -.125049348214267065734535947383309E-05 - private const val INV_GAMMA1P_M1_C12 = .113302723198169588237412962033074E-05 - private const val INV_GAMMA1P_M1_C13 = -.205633841697760710345015413002057E-06 - - fun logGamma(x: Double): Double = when { - x.isNaN() || x <= 0.0 -> Double.NaN - x < 0.5 -> logGamma1p(x) - ln(x) - x <= 2.5 -> logGamma1p(x - 0.5 - 0.5) - - x <= 8.0 -> { - val n = floor(x - 1.5).toInt() - val prod = (1..n).fold(1.0) { prod, i -> prod * (x - i) } - logGamma1p(x - (n + 1)) + ln(prod) - } - - else -> { - val tmp = x + LANCZOS_G + .5 - (x + .5) * ln(tmp) - tmp + HALF_LOG_2_PI + ln(lanczos(x) / x) - } - } - - private fun regularizedGammaP( - a: Double, - x: Double, - maxIterations: Int = Int.MAX_VALUE - ): Double = when { - a.isNaN() || x.isNaN() || a <= 0.0 || x < 0.0 -> Double.NaN - x == 0.0 -> 0.0 - x >= a + 1 -> 1.0 - regularizedGammaQ(a, x, maxIterations) - - else -> { - // calculate series - var n = 0.0 // current element index - var an = 1.0 / a // n-th element in the series - var sum = an // partial sum - - while (abs(an / sum) > 10e-15 && n < maxIterations && sum < Double.POSITIVE_INFINITY) { - // compute next element in the series - n += 1.0 - an *= x / (a + n) - - // update partial sum - sum += an - } - - when { - n >= maxIterations -> throw error("Maximal iterations is exceeded $maxIterations") - sum.isInfinite() -> 1.0 - else -> exp(-x + a * ln(x) - logGamma(a)) * sum - } - } - } - - fun regularizedGammaQ( - a: Double, - x: Double, - maxIterations: Int = Int.MAX_VALUE - ): Double = when { - a.isNaN() || x.isNaN() || a <= 0.0 || x < 0.0 -> Double.NaN - x == 0.0 -> 1.0 - x < a + 1.0 -> 1.0 - regularizedGammaP(a, x, maxIterations) - - else -> 1.0 / object : ContinuedFraction() { - override fun getA(n: Int, x: Double): Double = 2.0 * n + 1.0 - a + x - override fun getB(n: Int, x: Double): Double = n * (a - n) - }.evaluate(x, maxIterations) * exp(-x + a * ln(x) - logGamma(a)) - } - - private fun lanczos(x: Double): Double = - (LANCZOS.size - 1 downTo 1).sumOf { LANCZOS[it] / (x + it) } + LANCZOS[0] - - private fun invGamma1pm1(x: Double): Double { - require(x >= -0.5) - require(x <= 1.5) - val ret: Double - val t = if (x <= 0.5) x else x - 0.5 - 0.5 - - if (t < 0.0) { - val a = INV_GAMMA1P_M1_A0 + t * INV_GAMMA1P_M1_A1 - var b = INV_GAMMA1P_M1_B8 - b = INV_GAMMA1P_M1_B7 + t * b - b = INV_GAMMA1P_M1_B6 + t * b - b = INV_GAMMA1P_M1_B5 + t * b - b = INV_GAMMA1P_M1_B4 + t * b - b = INV_GAMMA1P_M1_B3 + t * b - b = INV_GAMMA1P_M1_B2 + t * b - b = INV_GAMMA1P_M1_B1 + t * b - b = 1.0 + t * b - var c = INV_GAMMA1P_M1_C13 + t * (a / b) - c = INV_GAMMA1P_M1_C12 + t * c - c = INV_GAMMA1P_M1_C11 + t * c - c = INV_GAMMA1P_M1_C10 + t * c - c = INV_GAMMA1P_M1_C9 + t * c - c = INV_GAMMA1P_M1_C8 + t * c - c = INV_GAMMA1P_M1_C7 + t * c - c = INV_GAMMA1P_M1_C6 + t * c - c = INV_GAMMA1P_M1_C5 + t * c - c = INV_GAMMA1P_M1_C4 + t * c - c = INV_GAMMA1P_M1_C3 + t * c - c = INV_GAMMA1P_M1_C2 + t * c - c = INV_GAMMA1P_M1_C1 + t * c - c = INV_GAMMA1P_M1_C + t * c - ret = (if (x > 0.5) t * c / x else x * (c + 0.5 + 0.5)) - } else { - var p = INV_GAMMA1P_M1_P6 - p = INV_GAMMA1P_M1_P5 + t * p - p = INV_GAMMA1P_M1_P4 + t * p - p = INV_GAMMA1P_M1_P3 + t * p - p = INV_GAMMA1P_M1_P2 + t * p - p = INV_GAMMA1P_M1_P1 + t * p - p = INV_GAMMA1P_M1_P0 + t * p - var q = INV_GAMMA1P_M1_Q4 - q = INV_GAMMA1P_M1_Q3 + t * q - q = INV_GAMMA1P_M1_Q2 + t * q - q = INV_GAMMA1P_M1_Q1 + t * q - q = 1.0 + t * q - var c = INV_GAMMA1P_M1_C13 + p / q * t - c = INV_GAMMA1P_M1_C12 + t * c - c = INV_GAMMA1P_M1_C11 + t * c - c = INV_GAMMA1P_M1_C10 + t * c - c = INV_GAMMA1P_M1_C9 + t * c - c = INV_GAMMA1P_M1_C8 + t * c - c = INV_GAMMA1P_M1_C7 + t * c - c = INV_GAMMA1P_M1_C6 + t * c - c = INV_GAMMA1P_M1_C5 + t * c - c = INV_GAMMA1P_M1_C4 + t * c - c = INV_GAMMA1P_M1_C3 + t * c - c = INV_GAMMA1P_M1_C2 + t * c - c = INV_GAMMA1P_M1_C1 + t * c - c = INV_GAMMA1P_M1_C0 + t * c - ret = (if (x > 0.5) t / x * (c - 0.5 - 0.5) else x * c) - } - - return ret - } - - private fun logGamma1p(x: Double): Double { - require(x >= -0.5) - require(x <= 1.5) - return -ln1p(invGamma1pm1(x)) - } -} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt deleted file mode 100644 index 77ba02a25..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/internal/InternalUtils.kt +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.internal - -import kotlin.math.ln -import kotlin.math.min - -internal object InternalUtils { - private val FACTORIALS = longArrayOf( - 1L, 1L, 2L, - 6L, 24L, 120L, - 720L, 5040L, 40320L, - 362880L, 3628800L, 39916800L, - 479001600L, 6227020800L, 87178291200L, - 1307674368000L, 20922789888000L, 355687428096000L, - 6402373705728000L, 121645100408832000L, 2432902008176640000L - ) - - private const val BEGIN_LOG_FACTORIALS = 2 - - fun factorial(n: Int): Long = FACTORIALS[n] - - fun validateProbabilities(probabilities: DoubleArray?): Double { - require(!(probabilities == null || probabilities.isEmpty())) { "Probabilities must not be empty." } - - val sumProb = probabilities.sumOf { prob -> - require(!(prob < 0 || prob.isInfinite() || prob.isNaN())) { "Invalid probability: $prob" } - prob - } - - require(!(sumProb.isInfinite() || sumProb <= 0)) { "Invalid sum of probabilities: $sumProb" } - return sumProb - } - - class FactorialLog private constructor(numValues: Int, cache: DoubleArray?) { - private val logFactorials: DoubleArray = DoubleArray(numValues) - - init { - val endCopy: Int - - if (cache != null && cache.size > BEGIN_LOG_FACTORIALS) { - // Copy available values. - endCopy = min(cache.size, numValues) - - cache.copyInto( - logFactorials, - BEGIN_LOG_FACTORIALS, - BEGIN_LOG_FACTORIALS, endCopy - ) - } else - // All values to be computed - endCopy = BEGIN_LOG_FACTORIALS - - // Compute remaining values. - (endCopy until numValues).forEach { i -> - if (i < FACTORIALS.size) - logFactorials[i] = ln(FACTORIALS[i].toDouble()) - else - logFactorials[i] = logFactorials[i - 1] + ln(i.toDouble()) - } - } - - fun value(n: Int): Double { - if (n < logFactorials.size) return logFactorials[n] - return if (n < FACTORIALS.size) ln(FACTORIALS[n].toDouble()) else InternalGamma.logGamma(n + 1.0) - } - - companion object { - fun create(): FactorialLog = FactorialLog(0, null) - } - } -} \ No newline at end of file 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 deleted file mode 100644 index 16f616fe2..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/FunctionOptimization.kt +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.optimization - -import space.kscience.kmath.expressions.* -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.indices - -/** - * A likelihood function optimization problem with provided derivatives. - */ -public interface FunctionOptimization : Optimization { - /** - * The optimization direction. If true search for function maximum, if false, search for the minimum. - */ - public var maximize: Boolean - - /** - * Defines the initial guess for the optimization problem. - */ - public fun initialGuess(map: Map) - - /** - * Set a differentiable expression as objective function as function and gradient provider. - */ - public fun diffFunction(expression: DifferentiableExpression) - - public companion object { - /** - * Generate a chi squared expression from given x-y-sigma data and inline model. Provides automatic - * differentiation. - */ - public fun chiSquared( - autoDiff: AutoDiffProcessor>, - x: Buffer, - y: Buffer, - yErr: Buffer, - model: A.(I) -> I, - ): DifferentiableExpression where A : ExtendedField, A : ExpressionAlgebra { - require(x.size == y.size) { "X and y buffers should be of the same size" } - require(y.size == yErr.size) { "Y and yErr buffer should of the same size" } - - return autoDiff.process { - var sum = zero - - x.indices.forEach { - val xValue = const(x[it]) - val yValue = const(y[it]) - val yErrValue = const(yErr[it]) - val modelValue = model(xValue) - sum += ((yValue - modelValue) / yErrValue).pow(2) - } - - sum - } - } - } -} - -/** - * Defines a chi-squared-based objective function. - */ -public fun FunctionOptimization.chiSquared( - autoDiff: AutoDiffProcessor>, - x: Buffer, - y: Buffer, - yErr: Buffer, - model: A.(I) -> I, -) where A : ExtendedField, A : ExpressionAlgebra { - val chiSquared = FunctionOptimization.chiSquared(autoDiff, x, y, yErr, model) - diffFunction(chiSquared) - maximize = false -} - -/** - * Optimizes differentiable expression using specific [OptimizationProblemFactory]. - */ -public fun > DifferentiableExpression.optimizeWith( - factory: OptimizationProblemFactory, - vararg symbols: Symbol, - configuration: F.() -> Unit, -): OptimizationResult { - require(symbols.isNotEmpty()) { "Must provide a list of symbols for optimization" } - val problem = factory(symbols.toList(), configuration) - problem.diffFunction(this) - return problem.optimize() -} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt deleted file mode 100644 index fbc5074ef..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/NoDerivFunctionOptimization.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.optimization - -import space.kscience.kmath.expressions.Expression -import space.kscience.kmath.expressions.Symbol -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.indices -import kotlin.math.pow - -/** - * A likelihood function optimization problem - */ -public interface NoDerivFunctionOptimization : Optimization { - /** - * The optimization direction. If `true` search for function maximum, search for the minimum otherwise. - */ - public var maximize: Boolean - - /** - * Define the initial guess for the optimization problem - */ - public fun initialGuess(map: Map) - - /** - * Set an objective function expression - */ - public fun function(expression: Expression) - - public companion object { - /** - * Generate a chi squared expression from given x-y-sigma model represented by an expression. Does not provide derivatives - */ - public fun chiSquared( - x: Buffer, - y: Buffer, - yErr: Buffer, - model: Expression, - xSymbol: Symbol = Symbol.x, - ): Expression { - require(x.size == y.size) { "X and y buffers should be of the same size" } - require(y.size == yErr.size) { "Y and yErr buffer should of the same size" } - - return Expression { arguments -> - x.indices.sumOf { - val xValue = x[it] - val yValue = y[it] - val yErrValue = yErr[it] - val modifiedArgs = arguments + (xSymbol to xValue) - val modelValue = model(modifiedArgs) - ((yValue - modelValue) / yErrValue).pow(2) - } - } - } - } -} - - -/** - * Optimize expression without derivatives using specific [OptimizationProblemFactory] - */ -public fun > Expression.noDerivOptimizeWith( - factory: OptimizationProblemFactory, - vararg symbols: Symbol, - configuration: F.() -> Unit, -): OptimizationResult { - require(symbols.isNotEmpty()) { "Must provide a list of symbols for optimization" } - val problem = factory(symbols.toList(), configuration) - problem.function(this) - return problem.optimize() -} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt deleted file mode 100644 index d6d15755c..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/Optimization.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.optimization - -import space.kscience.kmath.expressions.Symbol - -public interface OptimizationFeature - -public class OptimizationResult( - public val point: Map, - public val value: T, - public val features: Set = emptySet(), -) { - override fun toString(): String { - return "OptimizationResult(point=$point, value=$value)" - } -} - -public operator fun OptimizationResult.plus( - feature: OptimizationFeature, -): OptimizationResult = OptimizationResult(point, value, features + feature) - -/** - * A builder of optimization problems over [T] variables - */ -public interface Optimization { - - /** - * Update the problem from previous optimization run - */ - public fun update(result: OptimizationResult) - - /** - * Make an optimization run - */ - public fun optimize(): OptimizationResult -} - -public fun interface OptimizationProblemFactory> { - public fun build(symbols: List): P -} - -public operator fun > OptimizationProblemFactory.invoke( - symbols: List, - block: P.() -> Unit, -): P = build(symbols).apply(block) diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt deleted file mode 100644 index 33400040d..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/optimization/XYFit.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.optimization - -import space.kscience.kmath.data.ColumnarData -import space.kscience.kmath.expressions.* -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.Field - -@UnstableKMathAPI -public interface XYFit : Optimization { - - public val algebra: Field - - /** - * Set X-Y data for this fit optionally including x and y errors - */ - public fun data( - dataSet: ColumnarData, - xSymbol: Symbol, - ySymbol: Symbol, - xErrSymbol: Symbol? = null, - yErrSymbol: Symbol? = null, - ) - - public fun model(model: (T) -> DifferentiableExpression) - - /** - * Set the differentiable model for this fit - */ - public fun model( - autoDiff: AutoDiffProcessor>, - modelFunction: A.(I) -> I, - ): Unit where A : ExtendedField, A : ExpressionAlgebra = model { arg -> - autoDiff.process { modelFunction(const(arg)) } - } -} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt deleted file mode 100644 index 5f923fe5f..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterExponentialSampler.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.samplers - -import space.kscience.kmath.chains.BlockingDoubleChain -import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.stat.Sampler -import space.kscience.kmath.structures.DoubleBuffer -import kotlin.math.ln -import kotlin.math.pow - -/** - * Sampling from an [exponential distribution](http://mathworld.wolfram.com/ExponentialDistribution.html). - * - * Based on Commons RNG implementation. - * See [https://commons.apache.org/proper/commons-rng/commons-rng-sampling/apidocs/org/apache/commons/rng/sampling/distribution/AhrensDieterExponentialSampler.html]. - */ -public class AhrensDieterExponentialSampler(public val mean: Double) : Sampler { - - init { - require(mean > 0) { "mean is not strictly positive: $mean" } - } - - override fun sample(generator: RandomGenerator): BlockingDoubleChain = object : BlockingDoubleChain { - override fun nextBlocking(): Double { - // Step 1: - var a = 0.0 - var u = generator.nextDouble() - - // Step 2 and 3: - while (u < 0.5) { - a += EXPONENTIAL_SA_QI[0] - u *= 2.0 - } - - // Step 4 (now u >= 0.5): - u += u - 1 - // Step 5: - if (u <= EXPONENTIAL_SA_QI[0]) return mean * (a + u) - // Step 6: - var i = 0 // Should be 1, be we iterate before it in while using 0. - var u2 = generator.nextDouble() - var umin = u2 - - // Step 7 and 8: - do { - ++i - u2 = generator.nextDouble() - if (u2 < umin) umin = u2 - // Step 8: - } while (u > EXPONENTIAL_SA_QI[i]) // Ensured to exit since EXPONENTIAL_SA_QI[MAX] = 1. - - return mean * (a + umin * EXPONENTIAL_SA_QI[0]) - } - - override fun nextBufferBlocking(size: Int): DoubleBuffer = DoubleBuffer(size) { nextBlocking() } - - override suspend fun fork(): BlockingDoubleChain = sample(generator.fork()) - } - - public companion object { - private val EXPONENTIAL_SA_QI by lazy { - val ln2 = ln(2.0) - var qi = 0.0 - - DoubleArray(16) { i -> - qi += ln2.pow(i + 1.0) / space.kscience.kmath.internal.InternalUtils.factorial(i + 1) - qi - } - } - } - -} - 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 deleted file mode 100644 index 063e055ce..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AhrensDieterMarsagliaTsangGammaSampler.kt +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.samplers - -import space.kscience.kmath.chains.Chain -import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.stat.Sampler -import space.kscience.kmath.stat.chain -import space.kscience.kmath.stat.next -import kotlin.math.* - -/** - * Sampling from the [gamma distribution](http://mathworld.wolfram.com/GammaDistribution.html). - * * 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: - * 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. - * - * See [https://commons.apache.org/proper/commons-rng/commons-rng-sampling/apidocs/org/apache/commons/rng/sampling/distribution/AhrensDieterMarsagliaTsangGammaSampler.html]. - */ -public class AhrensDieterMarsagliaTsangGammaSampler private constructor( - alpha: Double, - theta: Double -) : Sampler { - private val delegate: BaseGammaSampler = - if (alpha < 1) AhrensDieterGammaSampler(alpha, theta) else MarsagliaTsangGammaSampler(alpha, theta) - - private abstract class BaseGammaSampler internal constructor( - protected val alpha: Double, - protected val theta: Double - ) : Sampler { - init { - require(alpha > 0) { "alpha is not strictly positive: $alpha" } - require(theta > 0) { "theta is not strictly positive: $theta" } - } - - override fun toString(): String = "Ahrens-Dieter-Marsaglia-Tsang Gamma deviate" - } - - private class AhrensDieterGammaSampler(alpha: Double, theta: Double) : - BaseGammaSampler(alpha, theta) { - private val oneOverAlpha: Double = 1.0 / alpha - private val bGSOptim: Double = 1.0 + alpha / E - - override fun sample(generator: RandomGenerator): Chain = generator.chain { - var x: Double - - // [1]: p. 228, Algorithm GS. - while (true) { - // Step 1: - val u = generator.nextDouble() - val p = bGSOptim * u - - if (p <= 1) { - // Step 2: - x = p.pow(oneOverAlpha) - val u2 = generator.nextDouble() - - if (u2 > exp(-x)) // Reject. - continue - - break - } - - // Step 3: - x = -ln((bGSOptim - p) * oneOverAlpha) - val u2: Double = generator.nextDouble() - if (u2 <= x.pow(alpha - 1.0)) break - // Reject and continue. - } - - x * theta - } - } - - private class MarsagliaTsangGammaSampler(alpha: Double, theta: Double) : - BaseGammaSampler(alpha, theta) { - private val dOptim: Double - private val cOptim: Double - private val gaussian: NormalizedGaussianSampler - - init { - gaussian = ZigguratNormalizedGaussianSampler - dOptim = alpha - ONE_THIRD - cOptim = ONE_THIRD / sqrt(dOptim) - } - - override fun sample(generator: RandomGenerator): Chain = generator.chain { - var v: Double - - while (true) { - val x = gaussian.next(generator) - val oPcTx = 1 + cOptim * x - v = oPcTx * oPcTx * oPcTx - if (v <= 0) continue - val x2 = x * x - val u = generator.nextDouble() - // Squeeze. - if (u < 1 - 0.0331 * x2 * x2) break - if (ln(u) < 0.5 * x2 + dOptim * (1 - v + ln(v))) break - } - - theta * dOptim * v - } - - companion object { - private const val ONE_THIRD = 1.0 / 3.0 - } - } - - override fun sample(generator: RandomGenerator): Chain = delegate.sample(generator) - override fun toString(): String = delegate.toString() - - public companion object { - public fun of( - alpha: Double, - theta: Double - ): Sampler = AhrensDieterMarsagliaTsangGammaSampler(alpha, theta) - } -} \ No newline at end of file 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 deleted file mode 100644 index b00db5b30..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/AliasMethodDiscreteSampler.kt +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.samplers - -import space.kscience.kmath.chains.Chain -import space.kscience.kmath.internal.InternalUtils -import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.stat.Sampler -import space.kscience.kmath.stat.chain -import kotlin.math.ceil -import kotlin.math.max -import kotlin.math.min - -/** - * Distribution sampler that uses the Alias method. It can be used to sample from n values each with an associated - * probability. This implementation is based on the detailed explanation of the alias method by Keith Schartz and - * 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. 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 - * case sampling uses UniformRandomProvider.nextInt(int) and the upper 53-bits from UniformRandomProvider.nextLong(). - * - * Zero padding the input probabilities can be used to make more sampling more efficient. Any zero entry will always be - * aliased removing the requirement to compute a long. Increased sampling speed comes at the cost of increased storage - * space. The algorithm requires approximately 12 bytes of storage per input probability, that is n * 12 for size n. - * Zero-padding only requires 4 bytes of storage per padded value as the probability is known to be zero. - * - * An optimisation is performed for small table sizes that are a power of 2. In this case the sampling uses 1 or 2 - * calls from UniformRandomProvider.nextInt() to generate up to 64-bits for creation of an 11-bit index and 53-bits - * for the long. This optimisation requires a generator with a high cycle length for the lower order bits. - * - * Larger table sizes that are a power of 2 will benefit from fast algorithms for UniformRandomProvider.nextInt(int) - * that exploit the power of 2. - * - * Based on Commons RNG implementation. - * See [https://commons.apache.org/proper/commons-rng/commons-rng-sampling/apidocs/org/apache/commons/rng/sampling/distribution/AliasMethodDiscreteSampler.html]. - */ -public open class AliasMethodDiscreteSampler private constructor( - // Deliberate direct storage of input arrays - protected val probability: LongArray, - protected val alias: IntArray, -) : Sampler { - - private class SmallTableAliasMethodDiscreteSampler( - probability: LongArray, - alias: IntArray, - ) : AliasMethodDiscreteSampler(probability, alias) { - // Assume the table size is a power of 2 and create the mask - private val mask: Int = alias.size - 1 - - override fun sample(generator: RandomGenerator): Chain = generator.chain { - val bits = generator.nextInt() - // Isolate lower bits - val j = bits and mask - - // Optimisation for zero-padded input tables - if (j >= probability.size) - // No probability must use the alias - return@chain alias[j] - - // Create a uniform random deviate as a long. - // This replicates functionality from the o.a.c.rng.core.utils.NumberFactory.makeLong - val longBits = generator.nextInt().toLong() shl 32 or (bits.toLong() and hex_ffffffff) - // Choose between the two. Use a 53-bit long for the probability. - if (longBits ushr 11 < probability[j]) j else alias[j] - } - - private companion object { - private const val hex_ffffffff = 4294967295L - } - } - - 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 - // return j - // else - // return alias[j] - val j = generator.nextInt(alias.size) - - // Optimisation for zero-padded input tables - // No probability must use the alias - if (j >= probability.size) return@chain alias[j] - - // Note: We could check the probability before computing a deviate. - // p(j) == 0 => alias[j] - // 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 - // 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. - // - // The probability table will be 0 when an input probability was zero. We - // will assume this is also rare if modelling a discrete distribution where - // all samples are possible. The edge case for zero-padded tables is handled above. - - // Choose between the two. Use a 53-bit long for the probability. - if (generator.nextLong() ushr 11 < probability[j]) j else alias[j] - } - - override fun toString(): String = "Alias method" - - public companion object { - private const val DEFAULT_ALPHA = 0 - private const val ZERO = 0.0 - private const val ONE_AS_NUMERATOR = 1L shl 53 - private const val CONVERT_TO_NUMERATOR: Double = ONE_AS_NUMERATOR.toDouble() - private const val MAX_SMALL_POWER_2_SIZE = 1 shl 11 - - private fun fillRemainingIndices(length: Int, indices: IntArray, small: Int): Int { - var updatedSmall = small - (length until indices.size).forEach { i -> indices[updatedSmall++] = i } - return updatedSmall - } - - private fun findLastNonZeroIndex(probabilities: DoubleArray): Int { - // No bounds check is performed when decrementing as the array contains at least one - // value above zero. - var nonZeroIndex = probabilities.size - 1 - while (probabilities[nonZeroIndex] == ZERO) nonZeroIndex-- - return nonZeroIndex - } - - private fun computeSize(length: Int, alpha: Int): Int { - // If No padding - if (alpha < 0) return length - // Use the number of leading zeros function to find the next power of 2, - // i.e. ceil(log2(x)) - var pow2 = 32 - numberOfLeadingZeros(length - 1) - // Increase by the alpha. Clip this to limit to a positive integer (2^30) - pow2 = min(30, pow2 + alpha) - // Use max to handle a length above the highest possible power of 2 - return max(length, 1 shl pow2) - } - - private fun fillTable( - probability: LongArray, - alias: IntArray, - indices: IntArray, - start: Int, - end: Int, - ) = (start until end).forEach { i -> - val index = indices[i] - probability[index] = ONE_AS_NUMERATOR - alias[index] = index - } - - private fun isSmallPowerOf2(n: Int): Boolean = n <= MAX_SMALL_POWER_2_SIZE && n and n - 1 == 0 - - private fun numberOfLeadingZeros(i: Int): Int { - var mutI = i - if (mutI <= 0) return if (mutI == 0) 32 else 0 - var n = 31 - - if (mutI >= 1 shl 16) { - n -= 16 - mutI = mutI ushr 16 - } - - if (mutI >= 1 shl 8) { - n -= 8 - mutI = mutI ushr 8 - } - - if (mutI >= 1 shl 4) { - n -= 4 - mutI = mutI ushr 4 - } - - if (mutI >= 1 shl 2) { - n -= 2 - mutI = mutI ushr 2 - } - - return n - (mutI ushr 1) - } - } - - @Suppress("FunctionName") - public fun AliasMethodDiscreteSampler( - probabilities: DoubleArray, - alpha: Int = DEFAULT_ALPHA, - ): Sampler { - // The Alias method balances N categories with counts around the mean into N sections, - // each allocated 'mean' observations. - // - // Consider 4 categories with counts 6,3,2,1. The histogram can be balanced into a - // 2D array as 4 sections with a height of the mean: - // - // 6 - // 6 - // 6 - // 63 => 6366 -- - // 632 6326 |-- mean - // 6321 6321 -- - // - // section abcd - // - // Each section is divided as: - // a: 6=1/1 - // b: 3=1/1 - // 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 - // from the pair based on a uniform random deviate. - val sumProb = InternalUtils.validateProbabilities(probabilities) - // Allow zero-padding - val n = computeSize(probabilities.size, alpha) - // Partition into small and large by splitting on the average. - val mean = sumProb / n - // The cardinality of smallSize + largeSize = n. - // So fill the same array from either end. - val indices = IntArray(n) - var large = n - var small = 0 - - probabilities.indices.forEach { i -> - if (probabilities[i] >= mean) indices[--large] = i else indices[small++] = i - } - - small = fillRemainingIndices(probabilities.size, indices, small) - // This may be smaller than the input length if the probabilities were already padded. - val nonZeroIndex = findLastNonZeroIndex(probabilities) - // The probabilities are modified so use a copy. - // Note: probabilities are required only up to last nonZeroIndex - val remainingProbabilities = probabilities.copyOf(nonZeroIndex + 1) - // Allocate the final tables. - // Probability table may be truncated (when zero padded). - // The alias table is full length. - val probability = LongArray(remainingProbabilities.size) - 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). - // 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 - // 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. - while (large != n && small != 0) { - // Index of the small and the large probabilities. - val j = indices[--small] - val k = indices[large++] - - // Optimisation for zero-padded input: - // p(j) = 0 above the last nonZeroIndex - if (j > nonZeroIndex) - // The entire amount for the section is taken from the alias. - remainingProbabilities[k] -= mean - else { - val pj = remainingProbabilities[j] - // Item j is a small probability that is below the mean. - // Compute the weight of the section for item j: pj / mean. - // This is scaled by 2^53 and the ceiling function used to round-up - // the probability to a numerator of a fraction in the range [1,2^53]. - // Ceiling ensures non-zero values. - probability[j] = ceil(CONVERT_TO_NUMERATOR * (pj / mean)).toLong() - // The remaining amount for the section is taken from the alias. - // Effectively: probabilities[k] -= (mean - pj) - remainingProbabilities[k] += pj - mean - } - - // If not j then the alias is k - alias[j] = k - - // Add the remaining probability from large to the appropriate list. - if (remainingProbabilities[k] >= mean) indices[--large] = k else indices[small++] = k - } - - // Final loop conditions to consume unpaired items. - // Note: The large set should never be non-empty but this can occur due to round-off - // error so consume from both. - fillTable(probability, alias, indices, 0, small) - fillTable(probability, alias, indices, large, n) - - // Change the algorithm for small power of 2 sized tables - return if (isSmallPowerOf2(n)) { - SmallTableAliasMethodDiscreteSampler(probability, alias) - } else { - AliasMethodDiscreteSampler(probability, alias) - } - } -} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt deleted file mode 100644 index 14aa26275..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/BoxMullerSampler.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.samplers - -import space.kscience.kmath.chains.BlockingDoubleChain -import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.structures.DoubleBuffer -import kotlin.math.* - -/** - * [Box-Muller algorithm](https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform) for sampling from a Gaussian - * distribution. - * - * Based on Commons RNG implementation. - * See [https://commons.apache.org/proper/commons-rng/commons-rng-sampling/apidocs/org/apache/commons/rng/sampling/distribution/BoxMullerNormalizedGaussianSampler.html]. - */ - -public object BoxMullerSampler : NormalizedGaussianSampler { - override fun sample(generator: RandomGenerator): BlockingDoubleChain = object : BlockingDoubleChain { - var state = Double.NaN - - override fun nextBufferBlocking(size: Int): DoubleBuffer { - val xs = generator.nextDoubleBuffer(size) - val ys = generator.nextDoubleBuffer(size) - - return DoubleBuffer(size) { index -> - if (state.isNaN()) { - // Generate a pair of Gaussian numbers. - val x = xs[index] - val y = ys[index] - val alpha = 2 * PI * x - val r = sqrt(-2 * ln(y)) - - // Keep second element of the pair for next invocation. - state = r * sin(alpha) - - // Return the first element of the generated pair. - r * cos(alpha) - } else { - // Use the second element of the pair (generated at the - // previous invocation). - state.also { - // Both elements of the pair have been used. - state = Double.NaN - } - } - } - } - - - override suspend fun fork(): BlockingDoubleChain = sample(generator.fork()) - } - -} 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 deleted file mode 100644 index e5d1ecb49..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/GaussianSampler.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.samplers - -import space.kscience.kmath.chains.BlockingDoubleChain -import space.kscience.kmath.chains.map -import space.kscience.kmath.stat.RandomGenerator - -/** - * Sampling from a Gaussian distribution with given mean and standard deviation. - * - * Based on Commons RNG implementation. - * See [https://commons.apache.org/proper/commons-rng/commons-rng-sampling/apidocs/org/apache/commons/rng/sampling/distribution/GaussianSampler.html]. - * - * @property mean the mean of the distribution. - * @property standardDeviation the variance of the distribution. - */ -public class GaussianSampler( - public val mean: Double, - public val standardDeviation: Double, - private val normalized: NormalizedGaussianSampler = BoxMullerSampler -) : BlockingDoubleSampler { - - init { - require(standardDeviation > 0.0) { "standard deviation is not strictly positive: $standardDeviation" } - } - - override fun sample(generator: RandomGenerator): BlockingDoubleChain = normalized - .sample(generator) - .map { standardDeviation * it + mean } - - override fun toString(): String = "N($mean, $standardDeviation)" - - public companion object -} 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 deleted file mode 100644 index 16f91570f..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/KempSmallMeanPoissonSampler.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.samplers - -import space.kscience.kmath.chains.BlockingIntChain -import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.stat.Sampler -import space.kscience.kmath.structures.IntBuffer -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. - * 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. - * - * Sampling uses 1 call to UniformRandomProvider.nextDouble(). This method provides an alternative to the SmallMeanPoissonSampler for slow generators of double. - * - * Based on Commons RNG implementation. - * See [https://commons.apache.org/proper/commons-rng/commons-rng-sampling/apidocs/org/apache/commons/rng/sampling/distribution/KempSmallMeanPoissonSampler.html]. - */ -public class KempSmallMeanPoissonSampler internal constructor( - private val p0: Double, - private val mean: Double, -) : Sampler { - override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { - override fun nextBlocking(): Int { - //TODO move to nextBufferBlocking - // Note on the algorithm: - // - X is the unknown sample deviate (the output of the algorithm) - // - x is the current value from the distribution - // - p is the probability of the current value x, p(X=x) - // - u is effectively the cumulative probability that the sample X - // is equal or above the current value x, p(X>=x) - // So if p(X>=x) > p(X=x) the sample must be above x, otherwise it is x - var u = generator.nextDouble() - var x = 0 - var p = p0 - - while (u > p) { - u -= p - // Compute the next probability using a recurrence relation. - // p(x+1) = p(x) * mean / (x+1) - p *= mean / ++x - // The algorithm listed in Kemp (1981) does not check that the rolling probability - // is positive. This check is added to ensure no errors when the limit of the summation - // 1 - sum(p(x)) is above 0 due to cumulative error in floating point arithmetic. - if (p == 0.0) return x - } - - return x - } - - override fun nextBufferBlocking(size: Int): IntBuffer = IntBuffer(size) { nextBlocking() } - - override suspend fun fork(): BlockingIntChain = sample(generator.fork()) - } - - 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, 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/MarsagliaNormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt deleted file mode 100644 index 5e636f246..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/MarsagliaNormalizedGaussianSampler.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.samplers - -import space.kscience.kmath.chains.BlockingDoubleChain -import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.structures.DoubleBuffer -import kotlin.math.ln -import kotlin.math.sqrt - -/** - * [Marsaglia polar method](https://en.wikipedia.org/wiki/Marsaglia_polar_method) for sampling from a Gaussian - * distribution with mean 0 and standard deviation 1. This is a variation of the algorithm implemented in - * [BoxMullerNormalizedGaussianSampler]. - * - * Based on Commons RNG implementation. - * See [https://commons.apache.org/proper/commons-rng/commons-rng-sampling/apidocs/org/apache/commons/rng/sampling/distribution/MarsagliaNormalizedGaussianSampler.html] - */ -public object MarsagliaNormalizedGaussianSampler : NormalizedGaussianSampler { - - override fun sample(generator: RandomGenerator): BlockingDoubleChain = object : BlockingDoubleChain { - var nextGaussian = Double.NaN - - override fun nextBlocking(): Double { - return if (nextGaussian.isNaN()) { - val alpha: Double - var x: Double - - // Rejection scheme for selecting a pair that lies within the unit circle. - while (true) { - // Generate a pair of numbers within [-1 , 1). - x = 2.0 * generator.nextDouble() - 1.0 - val y = 2.0 * generator.nextDouble() - 1.0 - val r2 = x * x + y * y - - if (r2 < 1 && r2 > 0) { - // Pair (x, y) is within unit circle. - alpha = sqrt(-2 * ln(r2) / r2) - // Keep second element of the pair for next invocation. - nextGaussian = alpha * y - // Return the first element of the generated pair. - break - } - // Pair is not within the unit circle: Generate another one. - } - - // Return the first element of the generated pair. - alpha * x - } else { - // Use the second element of the pair (generated at the - // previous invocation). - val r = nextGaussian - // Both elements of the pair have been used. - nextGaussian = Double.NaN - r - } - } - - override fun nextBufferBlocking(size: Int): DoubleBuffer = DoubleBuffer(size) { nextBlocking() } - - override suspend fun fork(): BlockingDoubleChain = sample(generator.fork()) - } -} diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt deleted file mode 100644 index ceb324e8d..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/NormalizedGaussianSampler.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.samplers - -import space.kscience.kmath.chains.BlockingDoubleChain -import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.stat.Sampler - -public interface BlockingDoubleSampler: Sampler{ - override fun sample(generator: RandomGenerator): BlockingDoubleChain -} - - -/** - * Marker interface for a sampler that generates values from an N(0,1) - * [Gaussian distribution](https://en.wikipedia.org/wiki/Normal_distribution). - */ -public fun interface NormalizedGaussianSampler : BlockingDoubleSampler{ - public companion object -} 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 deleted file mode 100644 index d3ff05b06..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/PoissonSampler.kt +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.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 -import kotlin.math.* - - -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 - * 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 - * Devroye, Luc. (1981). The Computer Generation of Poisson Random Variables Computing vol. 26 pp. 197-207. - * - * Based on Commons RNG implementation. - * See [https://commons.apache.org/proper/commons-rng/commons-rng-sampling/apidocs/org/apache/commons/rng/sampling/distribution/PoissonSampler.html]. - */ -@Suppress("FunctionName") -public fun PoissonSampler(mean: Double): Sampler { - return if (mean < PIVOT) SmallMeanPoissonSampler(mean) else LargeMeanPoissonSampler(mean) -} - -/** - * Sampler for the Poisson distribution. - * * 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. - * This sampler is suitable for mean < 40. For large means, [LargeMeanPoissonSampler] should be used instead. - * - * Based on Commons RNG implementation. - * - * See [https://commons.apache.org/proper/commons-rng/commons-rng-sampling/apidocs/org/apache/commons/rng/sampling/distribution/SmallMeanPoissonSampler.html]. - */ -public class SmallMeanPoissonSampler(public val mean: Double) : Sampler { - - init { - require(mean > 0) { "mean is not strictly positive: $mean" } - } - - private val p0: Double = exp(-mean) - - private val limit: Int = if (p0 > 0) { - ceil(1000 * mean) - } else { - throw IllegalArgumentException("No p(x=0) probability for mean: $mean") - }.toInt() - - override fun sample(generator: RandomGenerator): BlockingIntChain = object : BlockingIntChain { - override fun nextBlocking(): Int { - var n = 0 - var r = 1.0 - - while (n < limit) { - r *= generator.nextDouble() - if (r >= p0) n++ else break - } - - return n - } - - override fun nextBufferBlocking(size: Int): IntBuffer = IntBuffer(size) { nextBlocking() } - - override suspend fun fork(): BlockingIntChain = sample(generator.fork()) - } - - override fun toString(): String = "Small Mean Poisson deviate" -} - - -/** - * Sampler for the Poisson distribution. - * - 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. - * - * This sampler is suitable for mean >= 40. - * - * Based on Commons RNG implementation. - * See [https://commons.apache.org/proper/commons-rng/commons-rng-sampling/apidocs/org/apache/commons/rng/sampling/distribution/LargeMeanPoissonSampler.html]. - */ -public class LargeMeanPoissonSampler(public val mean: Double) : Sampler { - - init { - require(mean >= 1) { "mean is not >= 1: $mean" } - // The algorithm is not valid if Math.floor(mean) is not an integer. - require(mean <= MAX_MEAN) { "mean $mean > $MAX_MEAN" } - } - - private val factorialLog: InternalUtils.FactorialLog = NO_CACHE_FACTORIAL_LOG - private val lambda: Double = floor(mean) - private val logLambda: Double = ln(lambda) - private val logLambdaFactorial: Double = getFactorialLog(lambda.toInt()) - private val delta: Double = sqrt(lambda * ln(32 * lambda / PI + 1)) - private val halfDelta: Double = delta / 2 - private val twolpd: Double = 2 * lambda + delta - private val c1: Double = 1 / (8 * lambda) - private val a1: Double = sqrt(PI * twolpd) * exp(c1) - private val a2: Double = twolpd / delta * exp(-delta * (1 + delta) / twolpd) - private val aSum: Double = a1 + a2 + 1 - private val p1: Double = a1 / aSum - private val p2: Double = a2 / aSum - - 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 - } else { - KempSmallMeanPoissonSampler(mean - lambda).sample(generator) - } - - val y2 = smallMeanPoissonSampler?.nextBlocking() ?: 0 - var x: Double - var y: Double - var v: Double - var a: Int - var t: Double - var qr: Double - var qa: Double - - while (true) { - // Step 1: - val u = generator.nextDouble() - - if (u <= p1) { - // Step 2: - val n = gaussian.nextBlocking() - x = n * sqrt(lambda + halfDelta) - 0.5 - if (x > delta || x < -lambda) continue - y = if (x < 0) floor(x) else ceil(x) - val e = exponential.nextBlocking() - v = -e - 0.5 * n * n + c1 - } else { - // Step 3: - if (u > p1 + p2) { - y = lambda - break - } - - x = delta + twolpd / delta * exponential.nextBlocking() - y = ceil(x) - v = -exponential.nextBlocking() - delta * (x + 1) / twolpd - } - - // The Squeeze Principle - // Step 4.1: - a = if (x < 0) 1 else 0 - t = y * (y + 1) / (2 * lambda) - - // Step 4.2 - if (v < -t && a == 0) { - y += lambda - break - } - - // Step 4.3: - qr = t * ((2 * y + 1) / (6 * lambda) - 1) - qa = qr - t * t / (3 * (lambda + a * (y + 1))) - - // Step 4.4: - if (v < qa) { - y += lambda - break - } - - // Step 4.5: - if (v > qr) continue - - // Step 4.6: - if (v < y * logLambda - getFactorialLog((y + lambda).toInt()) + logLambdaFactorial) { - y += lambda - break - } - } - - return min(y2 + y.toLong(), Int.MAX_VALUE.toLong()).toIntExact() - } - - override fun nextBufferBlocking(size: Int): IntBuffer = IntBuffer(size) { nextBlocking() } - - override suspend fun fork(): BlockingIntChain = sample(generator.fork()) - } - - private fun getFactorialLog(n: Int): Double = factorialLog.value(n) - override fun toString(): String = "Large Mean Poisson deviate" - - public companion object { - private const val MAX_MEAN: Double = 0.5 * Int.MAX_VALUE - private val NO_CACHE_FACTORIAL_LOG: InternalUtils.FactorialLog = InternalUtils.FactorialLog.create() - } -} - - 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 deleted file mode 100644 index bda6f9819..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/samplers/ZigguratNormalizedGaussianSampler.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.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.* - -/** - * [Marsaglia and Tsang "Ziggurat"](https://en.wikipedia.org/wiki/Ziggurat_algorithm) method for sampling from a - * Gaussian distribution with mean 0 and standard deviation 1. The algorithm is explained in this paper and this - * implementation has been adapted from the C code provided therein. - * - * Based on Commons RNG implementation. - * See [https://commons.apache.org/proper/commons-rng/commons-rng-sampling/apidocs/org/apache/commons/rng/sampling/distribution/ZigguratNormalizedGaussianSampler.html]. - */ -public object ZigguratNormalizedGaussianSampler : NormalizedGaussianSampler { - - private const val R: Double = 3.442619855899 - private const val ONE_OVER_R: Double = 1 / R - private const val V: Double = 9.91256303526217e-3 - private val MAX: Double = 2.0.pow(63.0) - private val ONE_OVER_MAX: Double = 1.0 / MAX - private const val LEN: Int = 128 - private const val LAST: Int = LEN - 1 - private val K: LongArray = LongArray(LEN) - private val W: DoubleArray = DoubleArray(LEN) - private val F: DoubleArray = DoubleArray(LEN) - - init { - // Filling the tables. - var d = R - var t = d - var fd = gauss(d) - val q = V / fd - K[0] = (d / q * MAX).toLong() - K[1] = 0 - W[0] = q * ONE_OVER_MAX - W[LAST] = d * ONE_OVER_MAX - F[0] = 1.0 - F[LAST] = fd - - (LAST - 1 downTo 1).forEach { i -> - d = sqrt(-2 * ln(V / d + fd)) - fd = gauss(d) - K[i + 1] = (d / t * MAX).toLong() - t = d - F[i] = fd - W[i] = d * ONE_OVER_MAX - } - } - - private fun gauss(x: Double): Double = exp(-0.5 * x * x) - - private fun sampleOne(generator: RandomGenerator): Double { - val j = generator.nextLong() - val i = (j and LAST.toLong()).toInt() - return if (abs(j) < K[i]) j * W[i] else fix(generator, j, i) - } - - override fun sample(generator: RandomGenerator): BlockingDoubleChain = object : BlockingDoubleChain { - override fun nextBufferBlocking(size: Int): DoubleBuffer = DoubleBuffer(size) { sampleOne(generator) } - - override suspend fun fork(): BlockingDoubleChain = sample(generator.fork()) - } - - - private fun fix(generator: RandomGenerator, hz: Long, iz: Int): Double { - var x = hz * W[iz] - - return when { - iz == 0 -> { - var y: Double - - do { - y = -ln(generator.nextDouble()) - x = -ln(generator.nextDouble()) * ONE_OVER_R - } while (y + y < x * x) - - val out = R + x - if (hz > 0) out else -out - } - - F[iz] + generator.nextDouble() * (F[iz - 1] - F[iz]) < gauss(x) -> x - else -> sampleOne(generator) - } - } - -} 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 deleted file mode 100644 index 5e1e577ba..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/MCScope.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.stat - -import kotlinx.coroutines.* -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract -import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.EmptyCoroutineContext -import kotlin.coroutines.coroutineContext - -/** - * A scope for a Monte-Carlo computations or multi-coroutine random number generation. - * The scope preserves the order of random generator calls as long as all concurrency calls is done via [launch] and [async] - * functions. - */ -public class MCScope( - public val coroutineContext: CoroutineContext, - public val random: RandomGenerator, -) - -/** - * Launches a supervised Monte-Carlo scope - */ -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 { - 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. - * The method itself is not thread safe. - */ -public inline fun MCScope.launch( - context: CoroutineContext = EmptyCoroutineContext, - start: CoroutineStart = CoroutineStart.DEFAULT, - crossinline block: suspend MCScope.() -> Unit, -): Job { - val newRandom = random.fork() - return CoroutineScope(coroutineContext).launch(context, start) { - MCScope(coroutineContext, newRandom).block() - } -} - -/** - * Specialized async for [MCScope]. Behaves the same way as regular [CoroutineScope.async], but also stores the generator fork. - * The method itself is not thread safe. - */ -public inline fun MCScope.async( - context: CoroutineContext = EmptyCoroutineContext, - start: CoroutineStart = CoroutineStart.DEFAULT, - crossinline block: suspend MCScope.() -> T, -): Deferred { - val newRandom = random.fork() - return CoroutineScope(coroutineContext).async(context, start) { - MCScope(coroutineContext, newRandom).block() - } -} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt deleted file mode 100644 index 7daed5798..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Mean.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.stat - -import space.kscience.kmath.operations.* -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.indices - -/** - * Arithmetic mean - */ -public class Mean( - private val group: Ring, - private val division: (sum: T, count: Int) -> T, -) : ComposableStatistic, T>, BlockingStatistic { - - override fun evaluateBlocking(data: Buffer): T = group { - var res = zero - for (i in data.indices) { - res += data[i] - } - division(res, data.size) - } - - override suspend fun evaluate(data: Buffer): T = super.evaluate(data) - - override suspend fun computeIntermediate(data: Buffer): Pair = - evaluateBlocking(data) to data.size - - override suspend fun composeIntermediate(first: Pair, second: Pair): Pair = - group { first.first + second.first } to (first.second + second.second) - - override suspend fun toResult(intermediate: Pair): T = group { - division(intermediate.first, intermediate.second) - } - - public companion object { - //TODO replace with optimized version which respects overflow - public val double: Mean = Mean(DoubleField) { sum, count -> sum / count } - public val int: Mean = Mean(IntRing) { sum, count -> sum / count } - public val long: Mean = Mean(LongRing) { sum, count -> sum / count } - - public fun evaluate(buffer: Buffer): Double = double.evaluateBlocking(buffer) - public fun evaluate(buffer: Buffer): Int = int.evaluateBlocking(buffer) - public fun evaluate(buffer: Buffer): Long = long.evaluateBlocking(buffer) - } -} \ No newline at end of file diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt deleted file mode 100644 index 54b2e42b3..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Median.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.stat - -import space.kscience.kmath.structures.Buffer -import space.kscience.kmath.structures.asSequence - -/** - * Non-composable median - */ -public class Median(private val comparator: Comparator) : BlockingStatistic { - override fun evaluateBlocking(data: Buffer): T = - data.asSequence().sortedWith(comparator).toList()[data.size / 2] //TODO check if this is correct - - public companion object { - public val real: Median = Median { a: Double, b: Double -> a.compareTo(b) } - } -} \ No newline at end of file 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 deleted file mode 100644 index 61e472334..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomChain.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.stat - -import space.kscience.kmath.chains.BlockingDoubleChain -import space.kscience.kmath.chains.Chain -import space.kscience.kmath.structures.DoubleBuffer - -/** - * A possibly stateful chain producing random values. - * - * @property generator the underlying [RandomGenerator] instance. - */ -public class RandomChain( - public val generator: RandomGenerator, - private val gen: suspend RandomGenerator.() -> R, -) : Chain { - override suspend fun next(): R = generator.gen() - override suspend fun fork(): Chain = RandomChain(generator.fork(), gen) -} - -/** - * Create a generic random chain with provided [generator] - */ -public fun RandomGenerator.chain(generator: suspend RandomGenerator.() -> R): RandomChain = RandomChain(this, generator) - -/** - * A type-specific double chunk random chain - */ -public class UniformDoubleChain(public val generator: RandomGenerator) : BlockingDoubleChain { - 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 deleted file mode 100644 index 98ee6402a..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/RandomGenerator.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.stat - -import space.kscience.kmath.structures.DoubleBuffer -import kotlin.random.Random - -/** - * An interface that is implemented by random number generator algorithms. - */ -public interface RandomGenerator { - /** - * Gets the next random [Boolean] value. - */ - public fun nextBoolean(): Boolean - - /** - * Gets the next random [Double] value uniformly distributed between 0 (inclusive) and 1 (exclusive). - */ - public fun nextDouble(): Double - - /** - * A chunk of doubles of given [size]. - */ - public fun nextDoubleBuffer(size: Int): DoubleBuffer = DoubleBuffer(size) { nextDouble() } - - /** - * Gets the next random `Int` from the random number generator. - * - * Generates an `Int` random value uniformly distributed between [Int.MIN_VALUE] and [Int.MAX_VALUE] (inclusive). - */ - public fun nextInt(): Int - - /** - * Gets the next random non-negative `Int` from the random number generator less than the specified [until] bound. - * - * Generates an `Int` random value uniformly distributed between `0` (inclusive) and the specified [until] bound - * (exclusive). - */ - public fun nextInt(until: Int): Int - - /** - * Gets the next random `Long` from the random number generator. - * - * Generates a `Long` random value uniformly distributed between [Long.MIN_VALUE] and [Long.MAX_VALUE] (inclusive). - */ - public fun nextLong(): Long - - /** - * Gets the next random non-negative `Long` from the random number generator less than the specified [until] bound. - * - * Generates a `Long` random value uniformly distributed between `0` (inclusive) and the specified [until] bound (exclusive). - */ - public fun nextLong(until: Long): Long - - /** - * 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. - */ - public fun fillBytes(array: ByteArray, fromIndex: Int = 0, toIndex: Int = array.size) - - /** - * Creates a byte array of the specified [size], filled with random bytes. - */ - public fun nextBytes(size: Int): ByteArray = ByteArray(size).also { fillBytes(it) } - - /** - * 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. - * - * The thread safety of this operation is not guaranteed since it could affect the state of the generator. - */ - public fun fork(): RandomGenerator - - public companion object { - /** - * The [DefaultGenerator] instance. - */ - public val default: DefaultGenerator by lazy(::DefaultGenerator) - - /** - * Returns [DefaultGenerator] of given [seed]. - */ - public fun default(seed: Long): DefaultGenerator = DefaultGenerator(Random(seed)) - } -} - -/** - * Implements [RandomGenerator] by delegating all operations to [Random]. - * - * @property random the underlying [Random] object. - */ -public class DefaultGenerator(public val random: Random = Random) : RandomGenerator { - 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) - - override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { - random.nextBytes(array, fromIndex, toIndex) - } - - 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 deleted file mode 100644 index 0b3b52cab..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Sampler.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.stat - -import kotlinx.coroutines.flow.first -import space.kscience.kmath.chains.Chain -import space.kscience.kmath.chains.collect -import space.kscience.kmath.structures.* -import kotlin.jvm.JvmName - -/** - * Sampler that generates chains of values of type [T]. - */ -public fun interface Sampler { - /** - * Generates a chain of samples. - * - * @param generator the randomness provider. - * @return the new chain. - */ - public fun sample(generator: RandomGenerator): Chain -} - -/** - * Sample a bunch of values - */ -public fun Sampler.sampleBuffer( - generator: RandomGenerator, - size: Int, - bufferFactory: BufferFactory = Buffer.Companion::boxing, -): Chain> { - require(size > 1) - //creating temporary storage once - val tmp = ArrayList(size) - - return sample(generator).collect { chain -> - //clear list from previous run - tmp.clear() - //Fill list - repeat(size) { tmp.add(chain.next()) } - //return new buffer with elements from tmp - bufferFactory(size) { tmp[it] } - } -} - -/** - * Samples one value from this [Sampler]. - */ -public suspend fun Sampler.next(generator: RandomGenerator): T = sample(generator).first() - -/** - * Generates [size] real samples and chunks them into some buffers. - */ -@JvmName("sampleRealBuffer") -public fun Sampler.sampleBuffer(generator: RandomGenerator, size: Int): Chain> = - sampleBuffer(generator, size, ::DoubleBuffer) - -/** - * Generates [size] integer samples and chunks them into some buffers. - */ -@JvmName("sampleIntBuffer") -public fun Sampler.sampleBuffer(generator: RandomGenerator, size: Int): Chain> = - sampleBuffer(generator, size, ::IntBuffer) 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 deleted file mode 100644 index c1bbace86..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/SamplerAlgebra.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.stat - -import space.kscience.kmath.chains.Chain -import space.kscience.kmath.chains.ConstantChain -import space.kscience.kmath.chains.map -import space.kscience.kmath.chains.zip -import space.kscience.kmath.operations.Group -import space.kscience.kmath.operations.ScaleOperations -import space.kscience.kmath.operations.invoke - -/** - * Implements [Sampler] by sampling only certain [value]. - * - * @property value the value to sample. - */ -public class ConstantSampler(public val value: T) : Sampler { - override fun sample(generator: RandomGenerator): Chain = ConstantChain(value) -} - -/** - * Implements [Sampler] by delegating sampling to value of [chainBuilder]. - * - * @property chainBuilder the provider of [Chain]. - */ -public class BasicSampler(public val chainBuilder: (RandomGenerator) -> Chain) : Sampler { - override fun sample(generator: RandomGenerator): Chain = chainBuilder(generator) -} - -/** - * 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>, - ScaleOperations> where S : Group, S : ScaleOperations { - - override val zero: Sampler = ConstantSampler(algebra.zero) - - override fun add(a: Sampler, b: Sampler): Sampler = BasicSampler { generator -> - a.sample(generator).zip(b.sample(generator)) { aValue, bValue -> algebra { aValue + bValue } } - } - - override fun scale(a: Sampler, value: Double): Sampler = BasicSampler { generator -> - a.sample(generator).map { a -> - algebra { a * value } - } - } - - 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 deleted file mode 100644 index ab80fbe1c..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/Statistic.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.stat - -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.runningReduce -import space.kscience.kmath.coroutines.mapParallel -import space.kscience.kmath.structures.Buffer - -/** - * A function, that transforms a buffer of random quantities to some resulting value - */ -public interface Statistic { - public suspend fun evaluate(data: Buffer): R -} - -public interface BlockingStatistic : Statistic { - public fun evaluateBlocking(data: Buffer): R - - 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 the source type. - * @param I the intermediate block type. - * @param R the result type. - */ -public interface ComposableStatistic : Statistic { - //compute statistic on a single block - public suspend fun computeIntermediate(data: Buffer): I - - //Compose two blocks - public suspend fun composeIntermediate(first: I, second: I): I - - //Transform block to result - public suspend fun toResult(intermediate: I): R - - override suspend fun evaluate(data: Buffer): R = toResult(computeIntermediate(data)) -} - -@FlowPreview -@ExperimentalCoroutinesApi -private fun ComposableStatistic.flowIntermediate( - flow: Flow>, - dispatcher: CoroutineDispatcher = Dispatchers.Default, -): Flow = flow - .mapParallel(dispatcher) { computeIntermediate(it) } - .runningReduce(::composeIntermediate) - - -/** - * Perform a streaming statistical analysis on a chunked data. The computation of inner representation is done in parallel - * if [dispatcher] allows it. - * - * The resulting flow contains values that include the whole previous statistics, not only the last chunk. - */ -@OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class) -public fun ComposableStatistic.flow( - flow: Flow>, - dispatcher: CoroutineDispatcher = Dispatchers.Default, -): Flow = flowIntermediate(flow, dispatcher).map(::toResult) - diff --git a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt b/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt deleted file mode 100644 index 4c0d08720..000000000 --- a/kmath-stat/src/commonMain/kotlin/space/kscience/kmath/stat/UniformDistribution.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.stat - -import space.kscience.kmath.chains.Chain -import space.kscience.kmath.chains.SimpleChain -import space.kscience.kmath.distributions.Distribution -import space.kscience.kmath.distributions.UnivariateDistribution - -public class UniformDistribution(public val range: ClosedFloatingPointRange) : UnivariateDistribution { - private val length: Double = range.endInclusive - range.start - - override fun probability(arg: Double): Double = if (arg in range) 1.0 / length else 0.0 - - override fun sample(generator: RandomGenerator): Chain = - SimpleChain { range.start + generator.nextDouble() * length } - - override fun cumulative(arg: Double): Double = when { - arg < range.start -> 0.0 - arg >= range.endInclusive -> 1.0 - else -> (arg - range.start) / length - } -} - -public fun Distribution.Companion.uniform(range: ClosedFloatingPointRange): UniformDistribution = - UniformDistribution(range) 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 deleted file mode 100644 index a8e6a3362..000000000 --- a/kmath-stat/src/jvmMain/kotlin/space/kscience/kmath/stat/RandomSourceGenerator.kt +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.stat - -import org.apache.commons.rng.UniformRandomProvider -import org.apache.commons.rng.simple.RandomSource - -/** - * Implements [RandomGenerator] by delegating all operations to [RandomSource]. - * - * @property source the underlying [RandomSource] object. - */ -public class RandomSourceGenerator internal constructor(public val source: RandomSource, seed: Long?) : RandomGenerator { - internal val random: UniformRandomProvider = seed?.let { RandomSource.create(source, seed) } - ?: RandomSource.create(source) - - 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) - - override fun fillBytes(array: ByteArray, fromIndex: Int, toIndex: Int) { - require(toIndex > fromIndex) - random.nextBytes(array, fromIndex, toIndex - fromIndex) - } - - override fun fork(): RandomGenerator = RandomSourceGenerator(source, nextLong()) -} - -/** - * Implements [UniformRandomProvider] by delegating all operations to [RandomGenerator]. - * - * @property generator the underlying [RandomGenerator] object. - */ -public class RandomGeneratorProvider(public val generator: RandomGenerator) : UniformRandomProvider { - /** - * Generates a [Boolean] value. - * - * @return the next random value. - */ - override fun nextBoolean(): Boolean = generator.nextBoolean() - - /** - * Generates a [Float] value between 0 and 1. - * - * @return the next random value between 0 and 1. - */ - 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 byte array. - * - * @param bytes byte array in which to put the random bytes. - */ - override fun nextBytes(bytes: ByteArray): Unit = generator.fillBytes(bytes) - - /** - * Generates [Byte] values and places them into a user-supplied array. - * - * The array is filled with bytes extracted from random integers. This implies that the number of random bytes - * generated may be larger than the length of the byte array. - * - * @param bytes the array in which to put the generated bytes. - * @param start the index at which to start inserting the generated bytes. - * @param len the number of bytes to insert. - */ - override fun nextBytes(bytes: ByteArray, start: Int, len: Int) { - generator.fillBytes(bytes, start, start + len) - } - - /** - * Generates an [Int] value. - * - * @return the next random value. - */ - override fun nextInt(): Int = generator.nextInt() - - /** - * Generates an [Int] value between 0 (inclusive) and the specified value (exclusive). - * - * @param n the bound on the random number to be returned. Must be positive. - * @return a random integer between 0 (inclusive) and [n] (exclusive). - */ - 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. - */ - override fun nextDouble(): Double = generator.nextDouble() - - /** - * Generates a [Long] value. - * - * @return the next random value. - */ - override fun nextLong(): Long = generator.nextLong() - - /** - * Generates a [Long] value between 0 (inclusive) and the specified value (exclusive). - * - * @param n Bound on the random number to be returned. Must be positive. - * @return a random long value between 0 (inclusive) and [n] (exclusive). - */ - override fun nextLong(n: Long): Long = generator.nextLong(n) -} - -/** - * Represent this [RandomGenerator] as commons-rng [UniformRandomProvider] preserving and mirroring its current state. - * Getting new value from one of those changes the state of another. - */ -public fun RandomGenerator.asUniformRandomProvider(): UniformRandomProvider = if (this is RandomSourceGenerator) - random -else - RandomGeneratorProvider(this) - -/** - * Returns [RandomSourceGenerator] with given [RandomSource] and [seed]. - */ -public fun RandomGenerator.Companion.fromSource(source: RandomSource, seed: Long? = null): RandomSourceGenerator = - RandomSourceGenerator(source, seed) - -/** - * Returns [RandomSourceGenerator] with [RandomSource.MT] algorithm and given [seed]. - */ -public fun RandomGenerator.Companion.mersenneTwister(seed: Long? = null): RandomSourceGenerator = - fromSource(RandomSource.MT, seed) diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt deleted file mode 100644 index 2b6b1ca60..000000000 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/CommonsDistributionsTest.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.stat - -import kotlinx.coroutines.runBlocking -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test -import space.kscience.kmath.samplers.GaussianSampler - -internal class CommonsDistributionsTest { - @Test - fun testNormalDistributionSuspend() = runBlocking { - val distribution = GaussianSampler(7.0, 2.0) - val generator = RandomGenerator.default(1) - val sample = distribution.sample(generator).nextBuffer(1000) - Assertions.assertEquals(7.0, Mean.evaluate(sample), 0.2) - } - - @Test - fun testNormalDistributionBlocking() { - val distribution = GaussianSampler(7.0, 2.0) - val generator = RandomGenerator.default(1) - val sample = distribution.sample(generator).nextBufferBlocking(1000) - Assertions.assertEquals(7.0, Mean.evaluate(sample), 0.2) - } -} diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt deleted file mode 100644 index 0c3d9cb0d..000000000 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/MCScopeTest.kt +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.stat - -import kotlinx.coroutines.* -import java.util.* -import kotlin.test.Test -import kotlin.test.assertEquals - -data class RandomResult(val branch: String, val order: Int, val value: Int) - -typealias ATest = suspend CoroutineScope.() -> Set - -class MCScopeTest { - val simpleTest: ATest = { - mcScope(1111) { - val res = Collections.synchronizedSet(HashSet()) - - launch { - //println(random) - repeat(10) { - delay(10) - res.add(RandomResult("first", it, random.nextInt())) - } - launch { - //empty fork - } - } - - launch { - //println(random) - repeat(10) { - delay(10) - res.add(RandomResult("second", it, random.nextInt())) - } - } - - - res - } - } - - val testWithJoin: ATest = { - mcScope(1111) { - val res = Collections.synchronizedSet(HashSet()) - - val job = launch { - repeat(10) { - delay(10) - res.add(RandomResult("first", it, random.nextInt())) - } - } - launch { - repeat(10) { - delay(10) - if (it == 4) job.join() - res.add(RandomResult("second", it, random.nextInt())) - } - } - - res - } - } - - - @OptIn(ObsoleteCoroutinesApi::class) - fun compareResult(test: ATest) { - val res1 = runBlocking(Dispatchers.Default) { test() } - val res2 = runBlocking(newSingleThreadContext("test")) { test() } - assertEquals( - res1.find { it.branch == "first" && it.order == 7 }?.value, - res2.find { it.branch == "first" && it.order == 7 }?.value - ) - assertEquals(res1, res2) - } - - @Test - fun testParallel() { - compareResult(simpleTest) - } - - - @Test - fun testConditionalJoin() { - compareResult(testWithJoin) - } -} \ No newline at end of file diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt deleted file mode 100644 index 4060c0505..000000000 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/SamplerTest.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.stat - -import kotlinx.coroutines.runBlocking -import kotlin.test.Test - -class SamplerTest { - - @Test - fun bufferSamplerTest() { - val sampler = Sampler { it.chain { nextDouble() } } - val data = sampler.sampleBuffer(RandomGenerator.default, 100) - runBlocking { println(data.next()) } - } -} \ No newline at end of file diff --git a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt b/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt deleted file mode 100644 index c64bcc78c..000000000 --- a/kmath-stat/src/jvmTest/kotlin/space/kscience/kmath/stat/StatisticTest.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.stat - -import kotlinx.coroutines.flow.drop -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.runBlocking -import space.kscience.kmath.streaming.chunked -import kotlin.test.Test - -internal class StatisticTest { - //create a random number generator. - val generator = RandomGenerator.default(1) - - //Create a stateless chain from generator. - val data = generator.chain { nextDouble() } - - //Convert a chain to Flow and break it into chunks. - val chunked = data.chunked(1000) - - @Test - fun testParallelMean() = runBlocking { - val average = Mean.double - .flow(chunked) //create a flow with results - .drop(99) // Skip first 99 values and use one with total data - .first() //get 1e5 data samples average - - println(average) - } -} diff --git a/kmath-symja/build.gradle.kts b/kmath-symja/build.gradle.kts deleted file mode 100644 index 65c329d52..000000000 --- a/kmath-symja/build.gradle.kts +++ /dev/null @@ -1,42 +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. - */ - -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 deleted file mode 100644 index a343256fa..000000000 --- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/SymjaExpression.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.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 deleted file mode 100644 index 8def1ae83..000000000 --- a/kmath-symja/src/main/kotlin/space/kscience/kmath/symja/adapters.kt +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.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 deleted file mode 100644 index b19a55381..000000000 --- a/kmath-tensors/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Module kmath-tensors - -Common linear algebra operations on tensors. - - - [tensor algebra](src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt) : Basic linear algebra operations on tensors (plus, dot, etc.) - - [tensor algebra with broadcasting](src/commonMain/kotlin/space/kscience/kmath/tensors/core/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-14`. - -**Gradle:** -```gradle -repositories { - maven { url 'https://repo.kotlin.link' } - mavenCentral() -} - -dependencies { - implementation 'space.kscience:kmath-tensors:0.3.0-dev-14' -} -``` -**Gradle Kotlin DSL:** -```kotlin -repositories { - maven("https://repo.kotlin.link") - mavenCentral() -} - -dependencies { - implementation("space.kscience:kmath-tensors:0.3.0-dev-14") -} -``` diff --git a/kmath-tensors/build.gradle.kts b/kmath-tensors/build.gradle.kts deleted file mode 100644 index d084878ea..000000000 --- a/kmath-tensors/build.gradle.kts +++ /dev/null @@ -1,38 +0,0 @@ -plugins { - 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")) - api(project(":kmath-stat")) - } - } -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE - propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md")) - - feature( - id = "tensor algebra", - 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", - ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt" - ) { "Basic linear algebra operations implemented with broadcasting." } - - feature( - id = "linear algebra operations", - ref = "src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt" - ) { "Advanced linear algebra operations like LU decomposition, SVD, etc." } -} diff --git a/kmath-tensors/docs/README-TEMPLATE.md b/kmath-tensors/docs/README-TEMPLATE.md deleted file mode 100644 index 5fd968afd..000000000 --- a/kmath-tensors/docs/README-TEMPLATE.md +++ /dev/null @@ -1,7 +0,0 @@ -# Module kmath-tensors - -Common linear algebra operations on tensors. - -${features} - -${artifact} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt deleted file mode 100644 index 851810c8d..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/AnalyticTensorAlgebra.kt +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.api - - -/** - * Analytic operations on [Tensor]. - * - * @param T the type of items closed under analytic functions in the tensors. - */ -public interface AnalyticTensorAlgebra : TensorPartialDivisionAlgebra { - - /** - * @return the mean of all elements in the input tensor. - */ - public fun Tensor.mean(): T - - /** - * Returns the mean of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the mean of each row of the input tensor in the given dimension [dim]. - */ - public fun Tensor.mean(dim: Int, keepDim: Boolean): Tensor - - /** - * @return the standard deviation of all elements in the input tensor. - */ - public fun Tensor.std(): T - - /** - * Returns the standard deviation of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the standard deviation of each row of the input tensor in the given dimension [dim]. - */ - public fun Tensor.std(dim: Int, keepDim: Boolean): Tensor - - /** - * @return the variance of all elements in the input tensor. - */ - public fun Tensor.variance(): T - - /** - * Returns the variance of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the variance of each row of the input tensor in the given dimension [dim]. - */ - public fun Tensor.variance(dim: Int, keepDim: Boolean): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.exp.html - public fun Tensor.exp(): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.log.html - public fun Tensor.ln(): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.sqrt.html - public fun Tensor.sqrt(): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.acos.html#torch.cos - public fun Tensor.cos(): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.acos.html#torch.acos - public fun Tensor.acos(): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.cosh - public fun Tensor.cosh(): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.acosh.html#torch.acosh - public fun Tensor.acosh(): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sin - public fun Tensor.sin(): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asin - public fun Tensor.asin(): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.sinh - public fun Tensor.sinh(): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.asin.html#torch.asinh - public fun Tensor.asinh(): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.atan.html#torch.tan - public fun Tensor.tan(): Tensor - - //https://pytorch.org/docs/stable/generated/torch.atan.html#torch.atan - public fun Tensor.atan(): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.tanh - public fun Tensor.tanh(): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.atanh.html#torch.atanh - public fun Tensor.atanh(): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.ceil.html#torch.ceil - public fun Tensor.ceil(): Tensor - - //For information: https://pytorch.org/docs/stable/generated/torch.floor.html#torch.floor - public fun Tensor.floor(): Tensor - -} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt deleted file mode 100644 index 78aad2189..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/LinearOpsTensorAlgebra.kt +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.api - -/** - * Common linear algebra operations. Operates on [Tensor]. - * - * @param T the type of items closed under division in the tensors. - */ -public interface LinearOpsTensorAlgebra : TensorPartialDivisionAlgebra { - - /** - * Computes the determinant of a square matrix input, or of each square matrix in a batched input. - * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.det - * - * @return the determinant. - */ - public fun Tensor.det(): Tensor - - /** - * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input. - * Given a square matrix `A`, return the matrix `AInv` satisfying - * `A dot AInv == AInv dot A == eye(a.shape[0])`. - * For more information: https://pytorch.org/docs/stable/linalg.html#torch.linalg.inv - * - * @return the multiplicative inverse of a matrix. - */ - public fun Tensor.inv(): Tensor - - /** - * Cholesky decomposition. - * - * Computes the Cholesky decomposition of a Hermitian (or symmetric for real-valued matrices) - * positive-definite matrix or the Cholesky decompositions for a batch of such matrices. - * Each decomposition has the form: - * Given a tensor `input`, return the tensor `L` satisfying `input = L 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 - * - * @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 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 - * - * @receiver the `input`. - * @return pair of `Q` and `R` tensors. - */ - public fun Tensor.qr(): Pair, Tensor> - - /** - * 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 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. - * - * @receiver the `input`. - * @return triple of P, L and U tensors - */ - public fun Tensor.lu(): Triple, Tensor, Tensor> - - /** - * 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 `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 - * - * @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 to eigenvectors`. - * For more information: https://pytorch.org/docs/stable/generated/torch.symeig.html - * - * @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/Tensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt deleted file mode 100644 index e0f296057..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/Tensor.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.api - -import space.kscience.kmath.nd.MutableStructureND - -public typealias Tensor = MutableStructureND diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt deleted file mode 100644 index 6076748d9..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorAlgebra.kt +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.api - -import space.kscience.kmath.operations.Algebra - -/** - * Algebra over a ring on [Tensor]. - * For more information: https://proofwiki.org/wiki/Definition:Algebra_over_Ring - * - * @param T the type of items in the tensors. - */ -public interface TensorAlgebra : Algebra> { - /** - * Returns a single tensor value of unit dimension if tensor shape equals to [1]. - * - * @return a nullable value of a potentially scalar tensor. - */ - public fun Tensor.valueOrNull(): T? - - /** - * Returns a single tensor value of unit dimension. The tensor shape must be equal to [1]. - * - * @return the value of a scalar tensor. - */ - public fun Tensor.value(): T = - valueOrNull() ?: throw IllegalArgumentException("Inconsistent value for tensor of with $shape shape") - - /** - * Each element of the tensor [other] is added to this value. - * The resulting tensor is returned. - * - * @param other tensor to be added. - * @return the sum of this value and tensor [other]. - */ - public operator fun T.plus(other: Tensor): Tensor - - /** - * Adds the scalar [value] to each element of this tensor and returns a new resulting tensor. - * - * @param value the number to be added to each element of this tensor. - * @return the sum of this tensor and [value]. - */ - public operator fun Tensor.plus(value: T): Tensor - - /** - * Each element of the tensor [other] is added to each element of this tensor. - * The resulting tensor is returned. - * - * @param other tensor to be added. - * @return the sum of this tensor and [other]. - */ - public operator fun Tensor.plus(other: Tensor): Tensor - - /** - * Adds the scalar [value] to each element of this tensor. - * - * @param value the number to be added to each element of this tensor. - */ - public operator fun Tensor.plusAssign(value: T) - - /** - * Each element of the tensor [other] is added to each element of this tensor. - * - * @param other tensor to be added. - */ - public operator fun Tensor.plusAssign(other: Tensor) - - /** - * Each element of the tensor [other] is subtracted from this value. - * The resulting tensor is returned. - * - * @param other tensor to be subtracted. - * @return the difference between this value and tensor [other]. - */ - public operator fun T.minus(other: Tensor): Tensor - - /** - * Subtracts the scalar [value] from each element of this tensor and returns a new resulting tensor. - * - * @param value the number to be subtracted from each element of this tensor. - * @return the difference between this tensor and [value]. - */ - public operator fun Tensor.minus(value: T): Tensor - - /** - * Each element of the tensor [other] is subtracted from each element of this tensor. - * The resulting tensor is returned. - * - * @param other tensor to be subtracted. - * @return the difference between this tensor and [other]. - */ - public operator fun Tensor.minus(other: Tensor): Tensor - - /** - * Subtracts the scalar [value] from each element of this tensor. - * - * @param value the number to be subtracted from each element of this tensor. - */ - public operator fun Tensor.minusAssign(value: T) - - /** - * Each element of the tensor [other] is subtracted from each element of this tensor. - * - * @param other tensor to be subtracted. - */ - public operator fun Tensor.minusAssign(other: Tensor) - - - /** - * Each element of the tensor [other] is multiplied by this value. - * The resulting tensor is returned. - * - * @param other tensor to be multiplied. - * @return the product of this value and tensor [other]. - */ - public operator fun T.times(other: Tensor): Tensor - - /** - * Multiplies the scalar [value] by each element of this tensor and returns a new resulting tensor. - * - * @param value the number to be multiplied by each element of this tensor. - * @return the product of this tensor and [value]. - */ - public operator fun Tensor.times(value: T): Tensor - - /** - * Each element of the tensor [other] is multiplied by each element of this tensor. - * The resulting tensor is returned. - * - * @param other tensor to be multiplied. - * @return the product of this tensor and [other]. - */ - public operator fun Tensor.times(other: Tensor): Tensor - - /** - * Multiplies the scalar [value] by each element of this tensor. - * - * @param value the number to be multiplied by each element of this tensor. - */ - public operator fun Tensor.timesAssign(value: T) - - /** - * Each element of the tensor [other] is multiplied by each element of this tensor. - * - * @param other tensor to be multiplied. - */ - public operator fun Tensor.timesAssign(other: Tensor) - - /** - * Numerical negative, element-wise. - * - * @return tensor negation of the original tensor. - */ - public operator fun Tensor.unaryMinus(): Tensor - - /** - * Returns the tensor at index i - * For more information: https://pytorch.org/cppdocs/notes/tensor_indexing.html - * - * @param i index of the extractable tensor - * @return subtensor of the original tensor with index [i] - */ - public operator fun Tensor.get(i: Int): Tensor - - /** - * Returns a tensor that is a transposed version of this tensor. The given dimensions [i] and [j] are swapped. - * For more information: https://pytorch.org/docs/stable/generated/torch.transpose.html - * - * @param i the first dimension to be transposed - * @param j the second dimension to be transposed - * @return transposed tensor - */ - public fun Tensor.transpose(i: Int = -2, j: Int = -1): Tensor - - /** - * Returns a new tensor with the same data as the self tensor but of a different shape. - * The returned tensor shares the same data and must have the same number of elements, but may have a different size - * For more information: https://pytorch.org/docs/stable/tensor_view.html - * - * @param shape the desired size - * @return tensor with new shape - */ - public fun Tensor.view(shape: IntArray): Tensor - - /** - * View this tensor as the same size as [other]. - * `this.viewAs(other)` is equivalent to `this.view(other.shape)`. - * For more information: https://pytorch.org/cppdocs/notes/tensor_indexing.html - * - * @param other the result tensor has the same size as other. - * @return the result tensor with the same size as other. - */ - public fun Tensor.viewAs(other: Tensor): Tensor - - /** - * Matrix product of two tensors. - * - * The behavior depends on the dimensionality of the tensors as follows: - * 1. If both tensors are 1-dimensional, the dot product (scalar) is returned. - * - * 2. If both arguments are 2-dimensional, the matrix-matrix product is returned. - * - * 3. If the first argument is 1-dimensional and the second argument is 2-dimensional, - * a 1 is prepended to its dimension for the purpose of the matrix multiply. - * After the matrix multiply, the prepended dimension is removed. - * - * 4. If the first argument is 2-dimensional and the second argument is 1-dimensional, - * the matrix-vector product is returned. - * - * 5. If both arguments are at least 1-dimensional and at least one argument is N-dimensional (where N > 2), - * then a batched matrix multiply is returned. If the first argument is 1-dimensional, - * a 1 is prepended to its dimension for the purpose of the batched matrix multiply and removed after. - * If the second argument is 1-dimensional, a 1 is appended to its dimension for the purpose of the batched matrix - * multiple and removed after. - * The non-matrix (i.e., batch) dimensions are 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 a mathematical product of two tensors. - */ - public infix fun Tensor.dot(other: Tensor): Tensor - - /** - * Creates a tensor whose diagonals of certain 2D planes (specified by [dim1] and [dim2]) - * are filled by [diagonalEntries]. - * To facilitate creating batched diagonal matrices, - * the 2D planes formed by the last two dimensions of the returned tensor are chosen by default. - * - * The argument [offset] controls, which diagonal to consider: - * 1. If [offset] = 0, it is the main diagonal. - * 1. If [offset] > 0, it is above the main diagonal. - * 1. If [offset] < 0, it is below the main diagonal. - * - * The size of the new matrix will be calculated - * to make the specified diagonal of the size of the last input dimension. - * For more information: https://pytorch.org/docs/stable/generated/torch.diag_embed.html - * - * @param diagonalEntries the input tensor. Must be at least 1-dimensional. - * @param offset which diagonal to consider. Default: 0 (main diagonal). - * @param dim1 first dimension with respect to which to take diagonal. Default: -2. - * @param dim2 second dimension with respect to which to take diagonal. Default: -1. - * - * @return tensor whose diagonals of certain 2D planes (specified by [dim1] and [dim2]) - * are filled by [diagonalEntries] - */ - public fun diagonalEmbedding( - diagonalEntries: Tensor, - offset: Int = 0, - dim1: Int = -2, - dim2: Int = -1, - ): Tensor - - /** - * @return the sum of all elements in the input tensor. - */ - public fun Tensor.sum(): T - - /** - * Returns the sum of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the sum of each row of the input tensor in the given dimension [dim]. - */ - public fun Tensor.sum(dim: Int, keepDim: Boolean): Tensor - - /** - * @return the minimum value of all elements in the input tensor. - */ - public fun Tensor.min(): T - - /** - * Returns the minimum value of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the minimum value of each row of the input tensor in the given dimension [dim]. - */ - public fun Tensor.min(dim: Int, keepDim: Boolean): Tensor - - /** - * Returns the maximum value of all elements in the input tensor. - */ - public fun Tensor.max(): T - - /** - * Returns the maximum value of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the maximum value of each row of the input tensor in the given dimension [dim]. - */ - public fun Tensor.max(dim: Int, keepDim: Boolean): Tensor - - /** - * Returns the index of maximum value of each row of the input tensor in the given dimension [dim]. - * - * If [keepDim] is true, the output tensor is of the same size as - * input except in the dimension [dim] where it is of size 1. - * Otherwise, [dim] is squeezed, resulting in the output tensor having 1 fewer dimension. - * - * @param dim the dimension to reduce. - * @param keepDim whether the output tensor has [dim] retained or not. - * @return the 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 deleted file mode 100644 index ce519288b..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/api/TensorPartialDivisionAlgebra.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.api - -/** - * Algebra over a field with partial division on [Tensor]. - * For more information: https://proofwiki.org/wiki/Definition:Division_Algebra - * - * @param T the type of items closed under division in the tensors. - */ -public interface TensorPartialDivisionAlgebra : TensorAlgebra { - - /** - * Each element of the tensor [other] is divided by this value. - * The resulting tensor is returned. - * - * @param other tensor to divide by. - * @return the division of this value by the tensor [other]. - */ - public operator fun T.div(other: Tensor): Tensor - - /** - * Divide by the scalar [value] each element of this tensor returns a new resulting tensor. - * - * @param value the number to divide by each element of this tensor. - * @return the division of this tensor by the [value]. - */ - public operator fun Tensor.div(value: T): Tensor - - /** - * Each element of the tensor [other] is divided by each element of this tensor. - * The resulting tensor is returned. - * - * @param other tensor to be divided by. - * @return the division of this tensor by [other]. - */ - public operator fun Tensor.div(other: Tensor): Tensor - - /** - * Divides by the scalar [value] each element of this tensor. - * - * @param value the number to divide by each element of this tensor. - */ - public operator fun Tensor.divAssign(value: T) - - /** - * Each element of this tensor is divided by each element of the [other] tensor. - * - * @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/BroadcastDoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt deleted file mode 100644 index 3eb8e5636..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BroadcastDoubleTensorAlgebra.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.internal.array -import space.kscience.kmath.tensors.core.internal.broadcastTensors -import space.kscience.kmath.tensors.core.internal.broadcastTo -import space.kscience.kmath.tensors.core.internal.tensor - -/** - * Basic linear algebra operations implemented with broadcasting. - * For more information: https://pytorch.org/docs/stable/notes/broadcasting.html - */ -public object BroadcastDoubleTensorAlgebra : DoubleTensorAlgebra() { - - override fun Tensor.plus(other: Tensor): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> - newThis.mutableBuffer.array()[i] + newOther.mutableBuffer.array()[i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun Tensor.plusAssign(other: Tensor) { - val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.linearSize) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] += - newOther.mutableBuffer.array()[tensor.bufferStart + i] - } - } - - override fun Tensor.minus(other: Tensor): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> - newThis.mutableBuffer.array()[i] - newOther.mutableBuffer.array()[i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun Tensor.minusAssign(other: Tensor) { - val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.linearSize) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] -= - newOther.mutableBuffer.array()[tensor.bufferStart + i] - } - } - - override fun Tensor.times(other: Tensor): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> - newThis.mutableBuffer.array()[newThis.bufferStart + i] * - newOther.mutableBuffer.array()[newOther.bufferStart + i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun Tensor.timesAssign(other: Tensor) { - val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.linearSize) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] *= - newOther.mutableBuffer.array()[tensor.bufferStart + i] - } - } - - override fun Tensor.div(other: Tensor): DoubleTensor { - val broadcast = broadcastTensors(tensor, other.tensor) - val newThis = broadcast[0] - val newOther = broadcast[1] - val resBuffer = DoubleArray(newThis.linearStructure.linearSize) { i -> - newThis.mutableBuffer.array()[newOther.bufferStart + i] / - newOther.mutableBuffer.array()[newOther.bufferStart + i] - } - return DoubleTensor(newThis.shape, resBuffer) - } - - override fun Tensor.divAssign(other: Tensor) { - val newOther = broadcastTo(other.tensor, tensor.shape) - for (i in 0 until tensor.linearStructure.linearSize) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] /= - newOther.mutableBuffer.array()[tensor.bufferStart + i] - } - } -} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt deleted file mode 100644 index bf9a9f7f7..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/BufferedTensor.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.Strides -import space.kscience.kmath.structures.MutableBuffer -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.internal.TensorLinearStructure - -/** - * Represents [Tensor] over a [MutableBuffer] intended to be used through [DoubleTensor] and [IntTensor] - */ -public open class BufferedTensor internal constructor( - override val shape: IntArray, - @PublishedApi internal val mutableBuffer: MutableBuffer, - @PublishedApi internal val bufferStart: Int, -) : Tensor { - - /** - * Buffer strides based on [TensorLinearStructure] implementation - */ - public val linearStructure: Strides - get() = TensorLinearStructure(shape) - - /** - * Number of elements in tensor - */ - public val numElements: Int - get() = linearStructure.linearSize - - override fun get(index: IntArray): T = mutableBuffer[bufferStart + linearStructure.offset(index)] - - override fun set(index: IntArray, value: T) { - mutableBuffer[bufferStart + linearStructure.offset(index)] = value - } - - @PerformancePitfall - override fun elements(): Sequence> = linearStructure.indices().map { - it to get(it) - } -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt deleted file mode 100644 index ad7831fb9..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensor.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.tensors.core.internal.toPrettyString - -/** - * Default [BufferedTensor] implementation for [Double] values - */ -public class DoubleTensor @PublishedApi internal constructor( - shape: IntArray, - buffer: DoubleArray, - offset: Int = 0 -) : BufferedTensor(shape, DoubleBuffer(buffer), offset) { - override fun toString(): String = toPrettyString() -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt deleted file mode 100644 index 4b9d13827..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/DoubleTensorAlgebra.kt +++ /dev/null @@ -1,932 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.nd.as1D -import space.kscience.kmath.nd.as2D -import space.kscience.kmath.tensors.api.AnalyticTensorAlgebra -import space.kscience.kmath.tensors.api.LinearOpsTensorAlgebra -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.api.TensorPartialDivisionAlgebra -import space.kscience.kmath.tensors.core.internal.* -import kotlin.math.* - -/** - * Implementation of basic operations over double tensors and basic algebra operations on them. - */ -public open class DoubleTensorAlgebra : - TensorPartialDivisionAlgebra, - AnalyticTensorAlgebra, - LinearOpsTensorAlgebra { - - public companion object : DoubleTensorAlgebra() - - override fun Tensor.valueOrNull(): Double? = if (tensor.shape contentEquals intArrayOf(1)) - tensor.mutableBuffer.array()[tensor.bufferStart] else null - - override fun Tensor.value(): Double = valueOrNull() - ?: throw IllegalArgumentException("The tensor shape is $shape, but value method is allowed only for shape [1]") - - /** - * Constructs a tensor with the specified shape and data. - * - * @param shape the desired shape for the tensor. - * @param buffer one-dimensional data array. - * @return tensor with the [shape] shape and [buffer] data. - */ - public fun fromArray(shape: IntArray, buffer: DoubleArray): DoubleTensor { - checkEmptyShape(shape) - checkEmptyDoubleBuffer(buffer) - checkBufferShapeConsistency(shape, buffer) - return DoubleTensor(shape, buffer, 0) - } - - /** - * Constructs a tensor with the specified shape and initializer. - * - * @param shape the desired shape for the tensor. - * @param initializer mapping tensor indices to values. - * @return tensor with the [shape] shape and data generated by the [initializer]. - */ - public fun produce(shape: IntArray, initializer: (IntArray) -> Double): DoubleTensor = - fromArray( - shape, - TensorLinearStructure(shape).indices().map(initializer).toMutableList().toDoubleArray() - ) - - override operator fun Tensor.get(i: Int): DoubleTensor { - val lastShape = tensor.shape.drop(1).toIntArray() - val newShape = if (lastShape.isNotEmpty()) lastShape else intArrayOf(1) - val newStart = newShape.reduce(Int::times) * i + tensor.bufferStart - return DoubleTensor(newShape, tensor.mutableBuffer.array(), newStart) - } - - /** - * Creates a tensor of a given shape and fills all elements with a given value. - * - * @param value the value to fill the output tensor with. - * @param shape array of integers defining the shape of the output tensor. - * @return tensor with the [shape] shape and filled with [value]. - */ - public fun full(value: Double, shape: IntArray): DoubleTensor { - checkEmptyShape(shape) - val buffer = DoubleArray(shape.reduce(Int::times)) { value } - return DoubleTensor(shape, buffer) - } - - /** - * Returns a tensor with the same shape as `input` filled with [value]. - * - * @param value the value to fill the output tensor with. - * @return tensor with the `input` tensor shape and filled with [value]. - */ - public fun Tensor.fullLike(value: Double): DoubleTensor { - val shape = tensor.shape - val buffer = DoubleArray(tensor.numElements) { value } - return DoubleTensor(shape, buffer) - } - - /** - * Returns a tensor filled with the scalar value `0.0`, with the shape defined by the variable argument [shape]. - * - * @param shape array of integers defining the shape of the output tensor. - * @return tensor filled with the scalar value `0.0`, with the [shape] shape. - */ - public fun zeros(shape: IntArray): DoubleTensor = full(0.0, shape) - - /** - * Returns a tensor filled with the scalar value `0.0`, with the same shape as a given array. - * - * @return tensor filled with the scalar value `0.0`, with the same shape as `input` tensor. - */ - public fun Tensor.zeroesLike(): DoubleTensor = tensor.fullLike(0.0) - - /** - * Returns a tensor filled with the scalar value `1.0`, with the shape defined by the variable argument [shape]. - * - * @param shape array of integers defining the shape of the output tensor. - * @return tensor filled with the scalar value `1.0`, with the [shape] shape. - */ - public fun ones(shape: IntArray): DoubleTensor = full(1.0, shape) - - /** - * Returns a tensor filled with the scalar value `1.0`, with the same shape as a given array. - * - * @return tensor filled with the scalar value `1.0`, with the same shape as `input` tensor. - */ - public fun Tensor.onesLike(): DoubleTensor = tensor.fullLike(1.0) - - /** - * Returns a 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. - */ - public fun eye(n: Int): DoubleTensor { - val shape = intArrayOf(n, n) - val buffer = DoubleArray(n * n) { 0.0 } - val res = DoubleTensor(shape, buffer) - for (i in 0 until n) { - res[intArrayOf(i, i)] = 1.0 - } - return res - } - - /** - * Return a copy of the tensor. - * - * @return a copy of the `input` tensor with a copied buffer. - */ - public fun Tensor.copy(): DoubleTensor { - return DoubleTensor(tensor.shape, tensor.mutableBuffer.array().copyOf(), tensor.bufferStart) - } - - override fun Double.plus(other: Tensor): DoubleTensor { - val resBuffer = DoubleArray(other.tensor.numElements) { i -> - other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] + this - } - return DoubleTensor(other.shape, resBuffer) - } - - override fun Tensor.plus(value: Double): DoubleTensor = value + tensor - - override fun Tensor.plus(other: Tensor): DoubleTensor { - checkShapesCompatible(tensor, other.tensor) - val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[i] + other.tensor.mutableBuffer.array()[i] - } - return DoubleTensor(tensor.shape, resBuffer) - } - - override fun Tensor.plusAssign(value: Double) { - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] += value - } - } - - override fun Tensor.plusAssign(other: Tensor) { - checkShapesCompatible(tensor, other.tensor) - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] += - other.tensor.mutableBuffer.array()[tensor.bufferStart + i] - } - } - - override fun Double.minus(other: Tensor): DoubleTensor { - val resBuffer = DoubleArray(other.tensor.numElements) { i -> - this - other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] - } - return DoubleTensor(other.shape, resBuffer) - } - - override fun Tensor.minus(value: Double): DoubleTensor { - val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[tensor.bufferStart + i] - value - } - return DoubleTensor(tensor.shape, resBuffer) - } - - override fun Tensor.minus(other: Tensor): DoubleTensor { - checkShapesCompatible(tensor, other) - val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[i] - other.tensor.mutableBuffer.array()[i] - } - return DoubleTensor(tensor.shape, resBuffer) - } - - override fun Tensor.minusAssign(value: Double) { - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] -= value - } - } - - override fun Tensor.minusAssign(other: Tensor) { - checkShapesCompatible(tensor, other) - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] -= - other.tensor.mutableBuffer.array()[tensor.bufferStart + i] - } - } - - override fun Double.times(other: Tensor): DoubleTensor { - val resBuffer = DoubleArray(other.tensor.numElements) { i -> - other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] * this - } - return DoubleTensor(other.shape, resBuffer) - } - - override fun Tensor.times(value: Double): DoubleTensor = value * tensor - - override fun Tensor.times(other: Tensor): DoubleTensor { - checkShapesCompatible(tensor, other) - val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[tensor.bufferStart + i] * - other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] - } - return DoubleTensor(tensor.shape, resBuffer) - } - - override fun Tensor.timesAssign(value: Double) { - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] *= value - } - } - - override fun Tensor.timesAssign(other: Tensor) { - checkShapesCompatible(tensor, other) - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] *= - other.tensor.mutableBuffer.array()[tensor.bufferStart + i] - } - } - - override fun Double.div(other: Tensor): DoubleTensor { - val resBuffer = DoubleArray(other.tensor.numElements) { i -> - this / other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] - } - return DoubleTensor(other.shape, resBuffer) - } - - override fun Tensor.div(value: Double): DoubleTensor { - val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[tensor.bufferStart + i] / value - } - return DoubleTensor(shape, resBuffer) - } - - override fun Tensor.div(other: Tensor): DoubleTensor { - checkShapesCompatible(tensor, other) - val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[other.tensor.bufferStart + i] / - other.tensor.mutableBuffer.array()[other.tensor.bufferStart + i] - } - return DoubleTensor(tensor.shape, resBuffer) - } - - override fun Tensor.divAssign(value: Double) { - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] /= value - } - } - - override fun Tensor.divAssign(other: Tensor) { - checkShapesCompatible(tensor, other) - for (i in 0 until tensor.numElements) { - tensor.mutableBuffer.array()[tensor.bufferStart + i] /= - other.tensor.mutableBuffer.array()[tensor.bufferStart + i] - } - } - - override fun Tensor.unaryMinus(): DoubleTensor { - val resBuffer = DoubleArray(tensor.numElements) { i -> - tensor.mutableBuffer.array()[tensor.bufferStart + i].unaryMinus() - } - return DoubleTensor(tensor.shape, resBuffer) - } - - override fun Tensor.transpose(i: Int, j: Int): DoubleTensor { - val ii = tensor.minusIndex(i) - val jj = tensor.minusIndex(j) - checkTranspose(tensor.dimension, ii, jj) - val n = tensor.numElements - val resBuffer = DoubleArray(n) - - val resShape = tensor.shape.copyOf() - resShape[ii] = resShape[jj].also { resShape[jj] = resShape[ii] } - - val resTensor = DoubleTensor(resShape, resBuffer) - - for (offset in 0 until n) { - val oldMultiIndex = tensor.linearStructure.index(offset) - val newMultiIndex = oldMultiIndex.copyOf() - newMultiIndex[ii] = newMultiIndex[jj].also { newMultiIndex[jj] = newMultiIndex[ii] } - - val linearIndex = resTensor.linearStructure.offset(newMultiIndex) - resTensor.mutableBuffer.array()[linearIndex] = - tensor.mutableBuffer.array()[tensor.bufferStart + offset] - } - return resTensor - } - - override fun Tensor.view(shape: IntArray): DoubleTensor { - checkView(tensor, shape) - return DoubleTensor(shape, tensor.mutableBuffer.array(), tensor.bufferStart) - } - - override fun Tensor.viewAs(other: Tensor): DoubleTensor = - tensor.view(other.shape) - - override infix fun Tensor.dot(other: Tensor): DoubleTensor { - if (tensor.shape.size == 1 && other.shape.size == 1) { - return DoubleTensor(intArrayOf(1), doubleArrayOf(tensor.times(other).tensor.mutableBuffer.array().sum())) - } - - var newThis = tensor.copy() - var newOther = other.copy() - - var penultimateDim = false - var lastDim = false - if (tensor.shape.size == 1) { - penultimateDim = true - newThis = tensor.view(intArrayOf(1) + tensor.shape) - } - if (other.shape.size == 1) { - lastDim = true - newOther = other.tensor.view(other.shape + intArrayOf(1)) - } - - val broadcastTensors = broadcastOuterTensors(newThis.tensor, newOther.tensor) - newThis = broadcastTensors[0] - newOther = broadcastTensors[1] - - val l = newThis.shape[newThis.shape.size - 2] - val m1 = newThis.shape[newThis.shape.size - 1] - val m2 = newOther.shape[newOther.shape.size - 2] - val n = newOther.shape[newOther.shape.size - 1] - check(m1 == m2) { - "Tensors dot operation dimension mismatch: ($l, $m1) x ($m2, $n)" - } - - val resShape = newThis.shape.sliceArray(0..(newThis.shape.size - 2)) + intArrayOf(newOther.shape.last()) - val resSize = resShape.reduce { acc, i -> acc * i } - val resTensor = DoubleTensor(resShape, DoubleArray(resSize)) - - for ((res, ab) in resTensor.matrixSequence().zip(newThis.matrixSequence().zip(newOther.matrixSequence()))) { - val (a, b) = ab - dotHelper(a.as2D(), b.as2D(), res.as2D(), l, m1, n) - } - - if (penultimateDim) { - return resTensor.view( - resTensor.shape.dropLast(2).toIntArray() + - intArrayOf(resTensor.shape.last()) - ) - } - if (lastDim) { - return resTensor.view(resTensor.shape.dropLast(1).toIntArray()) - } - return resTensor - } - - override fun diagonalEmbedding(diagonalEntries: Tensor, offset: Int, dim1: Int, dim2: Int): - DoubleTensor { - val n = diagonalEntries.shape.size - val d1 = minusIndexFrom(n + 1, dim1) - val d2 = minusIndexFrom(n + 1, dim2) - - check(d1 != d2) { - "Diagonal dimensions cannot be identical $d1, $d2" - } - check(d1 <= n && d2 <= n) { - "Dimension out of range" - } - - var lessDim = d1 - var greaterDim = d2 - var realOffset = offset - if (lessDim > greaterDim) { - realOffset *= -1 - lessDim = greaterDim.also { greaterDim = lessDim } - } - - val resShape = diagonalEntries.shape.slice(0 until lessDim).toIntArray() + - intArrayOf(diagonalEntries.shape[n - 1] + abs(realOffset)) + - diagonalEntries.shape.slice(lessDim until greaterDim - 1).toIntArray() + - intArrayOf(diagonalEntries.shape[n - 1] + abs(realOffset)) + - diagonalEntries.shape.slice(greaterDim - 1 until n - 1).toIntArray() - val resTensor = zeros(resShape) - - for (i in 0 until diagonalEntries.tensor.numElements) { - val multiIndex = diagonalEntries.tensor.linearStructure.index(i) - - var offset1 = 0 - var offset2 = abs(realOffset) - if (realOffset < 0) { - offset1 = offset2.also { offset2 = offset1 } - } - val diagonalMultiIndex = multiIndex.slice(0 until lessDim).toIntArray() + - intArrayOf(multiIndex[n - 1] + offset1) + - multiIndex.slice(lessDim until greaterDim - 1).toIntArray() + - intArrayOf(multiIndex[n - 1] + offset2) + - multiIndex.slice(greaterDim - 1 until n - 1).toIntArray() - - resTensor[diagonalMultiIndex] = diagonalEntries[multiIndex] - } - - return resTensor.tensor - } - - /** - * Applies the [transform] function to each element of the tensor and returns the resulting modified tensor. - * - * @param transform the function to be applied to each element of the tensor. - * @return the resulting tensor after applying the function. - */ - public inline fun Tensor.map(transform: (Double) -> Double): DoubleTensor = DoubleTensor( - tensor.shape, - tensor.mutableBuffer.array().map { transform(it) }.toDoubleArray(), - tensor.bufferStart - ) - - /** - * Compares element-wise two tensors with a specified precision. - * - * @param other the tensor to compare with `input` tensor. - * @param epsilon permissible error when comparing two Double values. - * @return true if two tensors have the same shape and elements, false otherwise. - */ - public fun Tensor.eq(other: Tensor, epsilon: Double): Boolean = - tensor.eq(other) { x, y -> abs(x - y) < epsilon } - - /** - * Compares element-wise two tensors. - * Comparison of two Double values occurs with `1e-5` precision. - * - * @param other the tensor to compare with `input` tensor. - * @return true if two tensors have the same shape and elements, false otherwise. - */ - public infix fun Tensor.eq(other: Tensor): Boolean = tensor.eq(other, 1e-5) - - private fun Tensor.eq( - other: Tensor, - eqFunction: (Double, Double) -> Boolean, - ): Boolean { - checkShapesCompatible(tensor, other) - val n = tensor.numElements - if (n != other.tensor.numElements) { - return false - } - for (i in 0 until n) { - if (!eqFunction( - tensor.mutableBuffer[tensor.bufferStart + i], - other.tensor.mutableBuffer[other.tensor.bufferStart + i] - ) - ) { - return false - } - } - return true - } - - /** - * Returns a tensor of random numbers drawn from normal distributions with `0.0` mean and `1.0` standard deviation. - * - * @param shape the desired shape for the output tensor. - * @param seed the random seed of the pseudo-random number generator. - * @return tensor of a given shape filled with numbers from the normal distribution - * with `0.0` mean and `1.0` standard deviation. - */ - public fun randomNormal(shape: IntArray, seed: Long = 0): DoubleTensor = - DoubleTensor(shape, getRandomNormals(shape.reduce(Int::times), seed)) - - /** - * Returns a tensor with the same shape as `input` of random numbers drawn from normal distributions - * with `0.0` mean and `1.0` standard deviation. - * - * @receiver the `input`. - * @param seed the random seed of the pseudo-random number generator. - * @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)) - - /** - * Concatenates a sequence of tensors with equal shapes along the first dimension. - * - * @param tensors the [List] of tensors with same shapes to concatenate - * @return tensor with concatenation result - */ - public fun stack(tensors: List>): DoubleTensor { - check(tensors.isNotEmpty()) { "List must have at least 1 element" } - val shape = tensors[0].shape - check(tensors.all { it.shape contentEquals shape }) { "Tensors must have same shapes" } - val resShape = intArrayOf(tensors.size) + shape - val resBuffer = tensors.flatMap { - it.tensor.mutableBuffer.array().drop(it.tensor.bufferStart).take(it.tensor.numElements) - }.toDoubleArray() - return DoubleTensor(resShape, resBuffer, 0) - } - - /** - * Builds tensor from rows of the input tensor. - * - * @param indices the [IntArray] of 1-dimensional indices - * @return tensor with rows corresponding to row by [indices] - */ - public fun Tensor.rowsByIndices(indices: IntArray): DoubleTensor = stack(indices.map { this[it] }) - - internal inline fun Tensor.fold(foldFunction: (DoubleArray) -> Double): Double = - foldFunction(tensor.toDoubleArray()) - - internal inline fun Tensor.foldDim( - foldFunction: (DoubleArray) -> Double, - dim: Int, - keepDim: Boolean, - ): DoubleTensor { - check(dim < dimension) { "Dimension $dim out of range $dimension" } - val resShape = if (keepDim) { - shape.take(dim).toIntArray() + intArrayOf(1) + shape.takeLast(dimension - dim - 1).toIntArray() - } else { - shape.take(dim).toIntArray() + shape.takeLast(dimension - dim - 1).toIntArray() - } - val resNumElements = resShape.reduce(Int::times) - val resTensor = DoubleTensor(resShape, DoubleArray(resNumElements) { 0.0 }, 0) - for (index in resTensor.linearStructure.indices()) { - val prefix = index.take(dim).toIntArray() - val suffix = index.takeLast(dimension - dim - 1).toIntArray() - resTensor[index] = foldFunction(DoubleArray(shape[dim]) { i -> - tensor[prefix + intArrayOf(i) + suffix] - }) - } - - return resTensor - } - - override fun Tensor.sum(): Double = tensor.fold { it.sum() } - - override fun Tensor.sum(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim({ x -> x.sum() }, dim, keepDim) - - override fun Tensor.min(): Double = this.fold { it.minOrNull()!! } - - override fun Tensor.min(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim({ x -> x.minOrNull()!! }, dim, keepDim) - - override fun Tensor.max(): Double = this.fold { it.maxOrNull()!! } - - override fun Tensor.max(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim({ x -> x.maxOrNull()!! }, dim, keepDim) - - override fun Tensor.argMax(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim({ x -> - x.withIndex().maxByOrNull { it.value }?.index!!.toDouble() - }, dim, keepDim) - - - override fun Tensor.mean(): Double = this.fold { it.sum() / tensor.numElements } - - override fun Tensor.mean(dim: Int, keepDim: Boolean): DoubleTensor = - foldDim( - { arr -> - check(dim < dimension) { "Dimension $dim out of range $dimension" } - arr.sum() / shape[dim] - }, - dim, - keepDim - ) - - override fun Tensor.std(): Double = this.fold { arr -> - val mean = arr.sum() / tensor.numElements - sqrt(arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1)) - } - - override fun Tensor.std(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( - { arr -> - check(dim < dimension) { "Dimension $dim out of range $dimension" } - val mean = arr.sum() / shape[dim] - sqrt(arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1)) - }, - dim, - keepDim - ) - - override fun Tensor.variance(): Double = this.fold { arr -> - val mean = arr.sum() / tensor.numElements - arr.sumOf { (it - mean) * (it - mean) } / (tensor.numElements - 1) - } - - override fun Tensor.variance(dim: Int, keepDim: Boolean): DoubleTensor = foldDim( - { arr -> - check(dim < dimension) { "Dimension $dim out of range $dimension" } - val mean = arr.sum() / shape[dim] - arr.sumOf { (it - mean) * (it - mean) } / (shape[dim] - 1) - }, - dim, - keepDim - ) - - private fun cov(x: DoubleTensor, y: DoubleTensor): Double { - val n = x.shape[0] - return ((x - x.mean()) * (y - y.mean())).mean() * n / (n - 1) - } - - /** - * Returns the covariance matrix `M` of given vectors. - * - * `M[i, j]` contains covariance of `i`-th and `j`-th given vectors - * - * @param tensors the [List] of 1-dimensional tensors with same shape - * @return `M`. - */ - public fun cov(tensors: List>): DoubleTensor { - check(tensors.isNotEmpty()) { "List must have at least 1 element" } - val n = tensors.size - val m = tensors[0].shape[0] - check(tensors.all { it.shape contentEquals intArrayOf(m) }) { "Tensors must have same shapes" } - val resTensor = DoubleTensor( - intArrayOf(n, n), - DoubleArray(n * n) { 0.0 } - ) - for (i in 0 until n) { - for (j in 0 until n) { - resTensor[intArrayOf(i, j)] = cov(tensors[i].tensor, tensors[j].tensor) - } - } - return resTensor - } - - override fun Tensor.exp(): DoubleTensor = tensor.map(::exp) - - override fun Tensor.ln(): DoubleTensor = tensor.map(::ln) - - override fun Tensor.sqrt(): DoubleTensor = tensor.map(::sqrt) - - override fun Tensor.cos(): DoubleTensor = tensor.map(::cos) - - override fun Tensor.acos(): DoubleTensor = tensor.map(::acos) - - override fun Tensor.cosh(): DoubleTensor = tensor.map(::cosh) - - override fun Tensor.acosh(): DoubleTensor = tensor.map(::acosh) - - override fun Tensor.sin(): DoubleTensor = tensor.map(::sin) - - override fun Tensor.asin(): DoubleTensor = tensor.map(::asin) - - override fun Tensor.sinh(): DoubleTensor = tensor.map(::sinh) - - override fun Tensor.asinh(): DoubleTensor = tensor.map(::asinh) - - override fun Tensor.tan(): DoubleTensor = tensor.map(::tan) - - override fun Tensor.atan(): DoubleTensor = tensor.map(::atan) - - override fun Tensor.tanh(): DoubleTensor = tensor.map(::tanh) - - override fun Tensor.atanh(): DoubleTensor = tensor.map(::atanh) - - override fun Tensor.ceil(): DoubleTensor = tensor.map(::ceil) - - override fun Tensor.floor(): DoubleTensor = tensor.map(::floor) - - override fun Tensor.inv(): DoubleTensor = invLU(1e-9) - - override fun Tensor.det(): DoubleTensor = detLU(1e-9) - - /** - * Computes the LU factorization of a matrix or batches of matrices `input`. - * Returns a tuple containing the LU factorization and pivots of `input`. - * - * @param epsilon permissible error when comparing the determinant of a matrix with zero - * @return pair of `factorization` and `pivots`. - * The `factorization` has the shape ``(*, m, n)``, where``(*, m, n)`` is the shape of the `input` tensor. - * The `pivots` has the shape ``(∗, min(m, n))``. `pivots` stores all the intermediate transpositions of rows. - */ - public fun Tensor.luFactor(epsilon: Double): Pair = - computeLU(tensor, epsilon) - ?: throw IllegalArgumentException("Tensor contains matrices which are singular at precision $epsilon") - - /** - * Computes the LU factorization of a matrix or batches of matrices `input`. - * Returns a tuple containing the LU factorization and pivots of `input`. - * Uses an error of ``1e-9`` when calculating whether a matrix is degenerate. - * - * @return pair of `factorization` and `pivots`. - * The `factorization` has the shape ``(*, m, n)``, where``(*, m, n)`` is the shape of the `input` tensor. - * The `pivots` has the shape ``(∗, min(m, n))``. `pivots` stores all the intermediate transpositions of rows. - */ - public fun Tensor.luFactor(): Pair = luFactor(1e-9) - - /** - * Unpacks the data and pivots from a LU factorization of a tensor. - * Given a tensor [luTensor], return tensors `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 - */ - public fun luPivot( - luTensor: Tensor, - pivotsTensor: Tensor, - ): Triple { - checkSquareMatrix(luTensor.shape) - check( - luTensor.shape.dropLast(2).toIntArray() contentEquals pivotsTensor.shape.dropLast(1).toIntArray() || - luTensor.shape.last() == pivotsTensor.shape.last() - 1 - ) { "Inappropriate shapes of input tensors" } - - val n = luTensor.shape.last() - val pTensor = luTensor.zeroesLike() - pTensor - .matrixSequence() - .zip(pivotsTensor.tensor.vectorSequence()) - .forEach { (p, pivot) -> pivInit(p.as2D(), pivot.as1D(), n) } - - val lTensor = luTensor.zeroesLike() - val uTensor = luTensor.zeroesLike() - - lTensor.matrixSequence() - .zip(uTensor.matrixSequence()) - .zip(luTensor.tensor.matrixSequence()) - .forEach { (pairLU, lu) -> - val (l, u) = pairLU - luPivotHelper(l.as2D(), u.as2D(), lu.as2D(), n) - } - - return Triple(pTensor, lTensor, uTensor) - } - - /** - * QR decomposition. - * - * Computes the QR decomposition of a matrix or a batch of matrices, and returns a pair `Q 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. - * - * @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 a pair of `Q` and `R` tensors. - */ - public fun Tensor.cholesky(epsilon: Double): DoubleTensor { - checkSquareMatrix(shape) - checkPositiveDefinite(tensor, epsilon) - - val n = shape.last() - val lTensor = zeroesLike() - - for ((a, l) in tensor.matrixSequence().zip(lTensor.matrixSequence())) - for (i in 0 until n) choleskyHelper(a.as2D(), l.as2D(), n) - - return lTensor - } - - override fun Tensor.cholesky(): DoubleTensor = cholesky(1e-6) - - override fun Tensor.qr(): Pair { - checkSquareMatrix(shape) - val qTensor = zeroesLike() - val rTensor = zeroesLike() - tensor.matrixSequence() - .zip( - (qTensor.matrixSequence() - .zip(rTensor.matrixSequence())) - ).forEach { (matrix, qr) -> - val (q, r) = qr - qrHelper(matrix.asTensor(), q.asTensor(), r.as2D()) - } - - return qTensor to rTensor - } - - override fun Tensor.svd(): Triple = - svd(epsilon = 1e-10) - - /** - * Singular Value Decomposition. - * - * Computes the singular value decomposition of either a matrix or batch of matrices `input`. - * The singular value decomposition is represented as a triple `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. - * - * @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 - val commonShape = tensor.shape.sliceArray(0 until size - 2) - val (n, m) = tensor.shape.sliceArray(size - 2 until size) - val uTensor = zeros(commonShape + intArrayOf(min(n, m), n)) - val sTensor = zeros(commonShape + intArrayOf(min(n, m))) - val vTensor = zeros(commonShape + intArrayOf(min(n, m), m)) - - tensor.matrixSequence() - .zip( - uTensor.matrixSequence() - .zip( - sTensor.vectorSequence() - .zip(vTensor.matrixSequence()) - ) - ).forEach { (matrix, USV) -> - val matrixSize = matrix.shape.reduce { acc, i -> acc * i } - val curMatrix = DoubleTensor( - matrix.shape, - matrix.mutableBuffer.array().slice(matrix.bufferStart until matrix.bufferStart + matrixSize) - .toDoubleArray() - ) - svdHelper(curMatrix, USV, m, n, epsilon) - } - - return Triple(uTensor.transpose(), sTensor, vTensor.transpose()) - } - - override fun Tensor.symEig(): Pair = - symEig(epsilon = 1e-15) - - /** - * Returns eigenvalues and eigenvectors of a real symmetric matrix input or a batch of real symmetric matrices, - * represented by a pair `eigenvalues to eigenvectors`. - * - * @param epsilon the permissible error when comparing tensors for equality - * and when the cosine approaches 1 in the SVD algorithm. - * @return a pair `eigenvalues to eigenvectors`. - */ - public fun Tensor.symEig(epsilon: Double): Pair { - checkSymmetric(tensor, epsilon) - val (u, s, v) = tensor.svd(epsilon) - val shp = s.shape + intArrayOf(1) - val utv = u.transpose() dot v - val n = s.shape.last() - for (matrix in utv.matrixSequence()) - cleanSymHelper(matrix.as2D(), n) - - val eig = (utv dot s.view(shp)).view(s.shape) - return eig to v - } - - /** - * Computes the determinant of a square matrix input, or of each square matrix in a batched input - * using LU factorization algorithm. - * - * @param epsilon 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() - - val n = shape.size - - val detTensorShape = IntArray(n - 1) { i -> shape[i] } - detTensorShape[n - 2] = 1 - val resBuffer = DoubleArray(detTensorShape.reduce(Int::times)) { 0.0 } - - val detTensor = DoubleTensor( - detTensorShape, - resBuffer - ) - - luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).forEachIndexed { index, (lu, pivots) -> - resBuffer[index] = if (luHelper(lu.as2D(), pivots.as1D(), epsilon)) - 0.0 else luMatrixDet(lu.as2D(), pivots.as1D()) - } - - return detTensor - } - - /** - * Computes the multiplicative inverse matrix of a square matrix input, or of each square matrix in a batched input - * using LU factorization algorithm. - * Given a square matrix `a`, return the matrix `aInv` satisfying - * `a dot aInv == aInv dot a == eye(a.shape[0])`. - * - * @param epsilon error in the LU algorithm—permissible error when comparing the determinant of a matrix with zero - * @return the multiplicative inverse of a matrix. - */ - public fun Tensor.invLU(epsilon: Double = 1e-9): DoubleTensor { - val (luTensor, pivotsTensor) = luFactor(epsilon) - val invTensor = luTensor.zeroesLike() - - val seq = luTensor.matrixSequence().zip(pivotsTensor.vectorSequence()).zip(invTensor.matrixSequence()) - for ((luP, invMatrix) in seq) { - val (lu, pivots) = luP - luMatrixInv(lu.as2D(), pivots.as1D(), invMatrix.as2D()) - } - - return invTensor - } - - /** - * LUP decomposition. - * - * Computes the LUP decomposition of a matrix or a batch of matrices. - * Given a tensor `input`, return tensors `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. - */ - public fun Tensor.lu(epsilon: Double = 1e-9): Triple { - val (lu, pivots) = tensor.luFactor(epsilon) - return luPivot(lu, pivots) - } - - override fun Tensor.lu(): Triple = lu(1e-9) -} - - diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt deleted file mode 100644 index dd9f9c0c1..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/IntTensor.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.structures.IntBuffer - -/** - * Default [BufferedTensor] implementation for [Int] values - */ -public class IntTensor internal constructor( - shape: IntArray, - buffer: IntArray, - offset: Int = 0 -) : BufferedTensor(shape, IntBuffer(buffer), offset) diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt deleted file mode 100644 index 817ed60d8..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/TensorLinearStructure.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core.internal - -import space.kscience.kmath.nd.Strides -import kotlin.math.max - - -internal fun stridesFromShape(shape: IntArray): IntArray { - val nDim = shape.size - val res = IntArray(nDim) - if (nDim == 0) - return res - - var current = nDim - 1 - res[current] = 1 - - while (current > 0) { - res[current - 1] = max(1, shape[current]) * res[current] - current-- - } - return res -} - -internal fun indexFromOffset(offset: Int, strides: IntArray, nDim: Int): IntArray { - val res = IntArray(nDim) - var current = offset - var strideIndex = 0 - - while (strideIndex < nDim) { - res[strideIndex] = (current / strides[strideIndex]) - current %= strides[strideIndex] - strideIndex++ - } - return res -} - -/** - * This [Strides] implementation follows the last dimension first convention - * For more information: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.strides.html - * - * @param shape the shape of the tensor. - */ -internal class TensorLinearStructure(override val shape: IntArray) : Strides { - override val strides: IntArray - get() = stridesFromShape(shape) - - override fun index(offset: Int): IntArray = - indexFromOffset(offset, strides, shape.size) - - override val linearSize: Int - get() = shape.reduce(Int::times) - -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt deleted file mode 100644 index 4b9c0c382..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/broadcastUtils.kt +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core.internal - -import space.kscience.kmath.tensors.core.DoubleTensor -import kotlin.math.max - -internal fun multiIndexBroadCasting(tensor: DoubleTensor, resTensor: DoubleTensor, linearSize: Int) { - for (linearIndex in 0 until linearSize) { - val totalMultiIndex = resTensor.linearStructure.index(linearIndex) - val curMultiIndex = tensor.shape.copyOf() - - val offset = totalMultiIndex.size - curMultiIndex.size - - for (i in curMultiIndex.indices) { - if (curMultiIndex[i] != 1) { - curMultiIndex[i] = totalMultiIndex[i + offset] - } else { - curMultiIndex[i] = 0 - } - } - - val curLinearIndex = tensor.linearStructure.offset(curMultiIndex) - resTensor.mutableBuffer.array()[linearIndex] = - tensor.mutableBuffer.array()[tensor.bufferStart + curLinearIndex] - } -} - -internal fun broadcastShapes(vararg shapes: IntArray): IntArray { - var totalDim = 0 - for (shape in shapes) { - totalDim = max(totalDim, shape.size) - } - - val totalShape = IntArray(totalDim) { 0 } - for (shape in shapes) { - for (i in shape.indices) { - val curDim = shape[i] - val offset = totalDim - shape.size - totalShape[i + offset] = max(totalShape[i + offset], curDim) - } - } - - for (shape in shapes) { - for (i in shape.indices) { - val curDim = shape[i] - val offset = totalDim - shape.size - check(curDim == 1 || totalShape[i + offset] == curDim) { - "Shapes are not compatible and cannot be broadcast" - } - } - } - - return totalShape -} - -internal fun broadcastTo(tensor: DoubleTensor, newShape: IntArray): DoubleTensor { - require(tensor.shape.size <= newShape.size) { - "Tensor is not compatible with the new shape" - } - - val n = newShape.reduce { acc, i -> acc * i } - val resTensor = DoubleTensor(newShape, DoubleArray(n)) - - for (i in tensor.shape.indices) { - val curDim = tensor.shape[i] - val offset = newShape.size - tensor.shape.size - check(curDim == 1 || newShape[i + offset] == curDim) { - "Tensor is not compatible with the new shape and cannot be broadcast" - } - } - - multiIndexBroadCasting(tensor, resTensor, n) - return resTensor -} - -internal fun broadcastTensors(vararg tensors: DoubleTensor): List { - val totalShape = broadcastShapes(*(tensors.map { it.shape }).toTypedArray()) - val n = totalShape.reduce { acc, i -> acc * i } - - return tensors.map { tensor -> - val resTensor = DoubleTensor(totalShape, DoubleArray(n)) - multiIndexBroadCasting(tensor, resTensor, n) - resTensor - } -} - -internal fun broadcastOuterTensors(vararg tensors: DoubleTensor): List { - val onlyTwoDims = tensors.asSequence().onEach { - require(it.shape.size >= 2) { - "Tensors must have at least 2 dimensions" - } - }.any { it.shape.size != 2 } - - if (!onlyTwoDims) { - return tensors.asList() - } - - val totalShape = broadcastShapes(*(tensors.map { it.shape.sliceArray(0..it.shape.size - 3) }).toTypedArray()) - val n = totalShape.reduce { acc, i -> acc * i } - - return buildList { - for (tensor in tensors) { - val matrixShape = tensor.shape.sliceArray(tensor.shape.size - 2 until tensor.shape.size).copyOf() - val matrixSize = matrixShape[0] * matrixShape[1] - val matrix = DoubleTensor(matrixShape, DoubleArray(matrixSize)) - - val outerTensor = DoubleTensor(totalShape, DoubleArray(n)) - val resTensor = DoubleTensor(totalShape + matrixShape, DoubleArray(n * matrixSize)) - - for (linearIndex in 0 until n) { - val totalMultiIndex = outerTensor.linearStructure.index(linearIndex) - var curMultiIndex = tensor.shape.sliceArray(0..tensor.shape.size - 3).copyOf() - curMultiIndex = IntArray(totalMultiIndex.size - curMultiIndex.size) { 1 } + curMultiIndex - - val newTensor = DoubleTensor(curMultiIndex + matrixShape, tensor.mutableBuffer.array()) - - for (i in curMultiIndex.indices) { - if (curMultiIndex[i] != 1) { - curMultiIndex[i] = totalMultiIndex[i] - } else { - curMultiIndex[i] = 0 - } - } - - for (i in 0 until matrixSize) { - val curLinearIndex = newTensor.linearStructure.offset( - curMultiIndex + - matrix.linearStructure.index(i) - ) - val newLinearIndex = resTensor.linearStructure.offset( - totalMultiIndex + - matrix.linearStructure.index(i) - ) - - resTensor.mutableBuffer.array()[resTensor.bufferStart + newLinearIndex] = - newTensor.mutableBuffer.array()[newTensor.bufferStart + curLinearIndex] - } - } - add(resTensor) - } - } -} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt deleted file mode 100644 index e901415d1..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/checks.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core.internal - -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra - - -internal fun checkEmptyShape(shape: IntArray) = - check(shape.isNotEmpty()) { - "Illegal empty shape provided" - } - -internal fun checkEmptyDoubleBuffer(buffer: DoubleArray) = - check(buffer.isNotEmpty()) { - "Illegal empty buffer provided" - } - -internal fun checkBufferShapeConsistency(shape: IntArray, buffer: DoubleArray) = - check(buffer.size == shape.reduce(Int::times)) { - "Inconsistent shape ${shape.toList()} for buffer of size ${buffer.size} provided" - } - -internal fun checkShapesCompatible(a: Tensor, b: Tensor) = - check(a.shape contentEquals b.shape) { - "Incompatible shapes ${a.shape.toList()} and ${b.shape.toList()} " - } - -internal fun checkTranspose(dim: Int, i: Int, j: Int) = - check((i < dim) and (j < dim)) { - "Cannot transpose $i to $j for a tensor of dim $dim" - } - -internal fun checkView(a: Tensor, shape: IntArray) = - check(a.shape.reduce(Int::times) == shape.reduce(Int::times)) - -internal fun checkSquareMatrix(shape: IntArray) { - val n = shape.size - check(n >= 2) { - "Expected tensor with 2 or more dimensions, got size $n instead" - } - check(shape[n - 1] == shape[n - 2]) { - "Tensor must be batches of square matrices, but they are ${shape[n - 1]} by ${shape[n - 1]} matrices" - } -} - -internal fun DoubleTensorAlgebra.checkSymmetric( - tensor: Tensor, epsilon: Double = 1e-6 -) = - check(tensor.eq(tensor.transpose(), epsilon)) { - "Tensor is not symmetric about the last 2 dimensions at precision $epsilon" - } - -internal fun DoubleTensorAlgebra.checkPositiveDefinite(tensor: DoubleTensor, epsilon: Double = 1e-6) { - checkSymmetric(tensor, epsilon) - for (mat in tensor.matrixSequence()) - check(mat.asTensor().detLU().value() > 0.0) { - "Tensor contains matrices which are not positive definite ${mat.asTensor().detLU().value()}" - } -} \ No newline at end of file diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt deleted file mode 100644 index f3ac92872..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/linUtils.kt +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core.internal - -import space.kscience.kmath.nd.MutableStructure1D -import space.kscience.kmath.nd.MutableStructure2D -import space.kscience.kmath.nd.as1D -import space.kscience.kmath.nd.as2D -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.BufferedTensor -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.DoubleTensorAlgebra -import space.kscience.kmath.tensors.core.IntTensor -import kotlin.math.abs -import kotlin.math.min -import kotlin.math.sign -import kotlin.math.sqrt - -internal fun BufferedTensor.vectorSequence(): Sequence> = sequence { - val n = shape.size - val vectorOffset = shape[n - 1] - val vectorShape = intArrayOf(shape.last()) - for (offset in 0 until numElements step vectorOffset) { - val vector = BufferedTensor(vectorShape, mutableBuffer, bufferStart + offset) - yield(vector) - } -} - -internal fun BufferedTensor.matrixSequence(): Sequence> = sequence { - val n = shape.size - check(n >= 2) { "Expected tensor with 2 or more dimensions, got size $n" } - val matrixOffset = shape[n - 1] * shape[n - 2] - val matrixShape = intArrayOf(shape[n - 2], shape[n - 1]) - for (offset in 0 until numElements step matrixOffset) { - val matrix = BufferedTensor(matrixShape, mutableBuffer, bufferStart + offset) - yield(matrix) - } -} - -internal fun dotHelper( - a: MutableStructure2D, - b: MutableStructure2D, - res: MutableStructure2D, - l: Int, m: Int, n: Int -) { - for (i in 0 until l) { - for (j in 0 until n) { - var curr = 0.0 - for (k in 0 until m) { - curr += a[i, k] * b[k, j] - } - res[i, j] = curr - } - } -} - -internal fun luHelper( - lu: MutableStructure2D, - pivots: MutableStructure1D, - epsilon: Double -): Boolean { - - val m = lu.rowNum - - for (row in 0..m) pivots[row] = row - - for (i in 0 until m) { - var maxVal = 0.0 - var maxInd = i - - for (k in i until m) { - val absA = abs(lu[k, i]) - if (absA > maxVal) { - maxVal = absA - maxInd = k - } - } - - if (abs(maxVal) < epsilon) - return true // matrix is singular - - if (maxInd != i) { - - val j = pivots[i] - pivots[i] = pivots[maxInd] - pivots[maxInd] = j - - for (k in 0 until m) { - val tmp = lu[i, k] - lu[i, k] = lu[maxInd, k] - lu[maxInd, k] = tmp - } - - pivots[m] += 1 - - } - - for (j in i + 1 until m) { - lu[j, i] /= lu[i, i] - for (k in i + 1 until m) { - lu[j, k] -= lu[j, i] * lu[i, k] - } - } - } - return false -} - -internal fun BufferedTensor.setUpPivots(): IntTensor { - val n = this.shape.size - val m = this.shape.last() - val pivotsShape = IntArray(n - 1) { i -> this.shape[i] } - pivotsShape[n - 2] = m + 1 - - return IntTensor( - pivotsShape, - IntArray(pivotsShape.reduce(Int::times)) { 0 } - ) -} - -internal fun DoubleTensorAlgebra.computeLU( - tensor: DoubleTensor, - epsilon: Double -): Pair? { - - checkSquareMatrix(tensor.shape) - val luTensor = tensor.copy() - val pivotsTensor = tensor.setUpPivots() - - for ((lu, pivots) in luTensor.matrixSequence().zip(pivotsTensor.vectorSequence())) - if (luHelper(lu.as2D(), pivots.as1D(), epsilon)) - return null - - return Pair(luTensor, pivotsTensor) -} - -internal fun pivInit( - p: MutableStructure2D, - pivot: MutableStructure1D, - n: Int -) { - for (i in 0 until n) { - p[i, pivot[i]] = 1.0 - } -} - -internal fun luPivotHelper( - l: MutableStructure2D, - u: MutableStructure2D, - lu: MutableStructure2D, - n: Int -) { - for (i in 0 until n) { - for (j in 0 until n) { - if (i == j) { - l[i, j] = 1.0 - } - if (j < i) { - l[i, j] = lu[i, j] - } - if (j >= i) { - u[i, j] = lu[i, j] - } - } - } -} - -internal fun choleskyHelper( - a: MutableStructure2D, - l: MutableStructure2D, - n: Int -) { - for (i in 0 until n) { - for (j in 0 until i) { - var h = a[i, j] - for (k in 0 until j) { - h -= l[i, k] * l[j, k] - } - l[i, j] = h / l[j, j] - } - var h = a[i, i] - for (j in 0 until i) { - h -= l[i, j] * l[i, j] - } - l[i, i] = sqrt(h) - } -} - -internal fun luMatrixDet(lu: MutableStructure2D, pivots: MutableStructure1D): Double { - if (lu[0, 0] == 0.0) { - return 0.0 - } - val m = lu.shape[0] - val sign = if ((pivots[m] - m) % 2 == 0) 1.0 else -1.0 - return (0 until m).asSequence().map { lu[it, it] }.fold(sign) { left, right -> left * right } -} - -internal fun luMatrixInv( - lu: MutableStructure2D, - pivots: MutableStructure1D, - invMatrix: MutableStructure2D -) { - val m = lu.shape[0] - - for (j in 0 until m) { - for (i in 0 until m) { - if (pivots[i] == j) { - invMatrix[i, j] = 1.0 - } - - for (k in 0 until i) { - invMatrix[i, j] -= lu[i, k] * invMatrix[k, j] - } - } - - for (i in m - 1 downTo 0) { - for (k in i + 1 until m) { - invMatrix[i, j] -= lu[i, k] * invMatrix[k, j] - } - invMatrix[i, j] /= lu[i, i] - } - } -} - -internal fun DoubleTensorAlgebra.qrHelper( - matrix: DoubleTensor, - q: DoubleTensor, - r: MutableStructure2D -) { - checkSquareMatrix(matrix.shape) - val n = matrix.shape[0] - val qM = q.as2D() - val matrixT = matrix.transpose(0, 1) - val qT = q.transpose(0, 1) - - for (j in 0 until n) { - val v = matrixT[j] - val vv = v.as1D() - if (j > 0) { - for (i in 0 until j) { - r[i, j] = (qT[i] dot matrixT[j]).value() - for (k in 0 until n) { - val qTi = qT[i].as1D() - vv[k] = vv[k] - r[i, j] * qTi[k] - } - } - } - r[j, j] = DoubleTensorAlgebra { (v dot v).sqrt().value() } - for (i in 0 until n) { - qM[i, j] = vv[i] / r[j, j] - } - } -} - -internal fun DoubleTensorAlgebra.svd1d(a: DoubleTensor, epsilon: Double = 1e-10): DoubleTensor { - val (n, m) = a.shape - var v: DoubleTensor - val b: DoubleTensor - if (n > m) { - b = a.transpose(0, 1).dot(a) - v = DoubleTensor(intArrayOf(m), getRandomUnitVector(m, 0)) - } else { - b = a.dot(a.transpose(0, 1)) - v = DoubleTensor(intArrayOf(n), getRandomUnitVector(n, 0)) - } - - var lastV: DoubleTensor - while (true) { - lastV = v - v = b.dot(lastV) - val norm = DoubleTensorAlgebra { (v dot v).sqrt().value() } - v = v.times(1.0 / norm) - if (abs(v.dot(lastV).value()) > 1 - epsilon) { - return v - } - } -} - -internal fun DoubleTensorAlgebra.svdHelper( - matrix: DoubleTensor, - USV: Pair, Pair, BufferedTensor>>, - m: Int, n: Int, epsilon: Double -) { - val res = ArrayList>(0) - val (matrixU, SV) = USV - val (matrixS, matrixV) = SV - - for (k in 0 until min(n, m)) { - var a = matrix.copy() - for ((singularValue, u, v) in res.slice(0 until k)) { - val outerProduct = DoubleArray(u.shape[0] * v.shape[0]) - for (i in 0 until u.shape[0]) { - for (j in 0 until v.shape[0]) { - outerProduct[i * v.shape[0] + j] = u[i].value() * v[j].value() - } - } - a = a - singularValue.times(DoubleTensor(intArrayOf(u.shape[0], v.shape[0]), outerProduct)) - } - var v: DoubleTensor - var u: DoubleTensor - var norm: Double - if (n > m) { - v = svd1d(a, epsilon) - u = matrix.dot(v) - norm = DoubleTensorAlgebra { (u dot u).sqrt().value() } - u = u.times(1.0 / norm) - } else { - u = svd1d(a, epsilon) - v = matrix.transpose(0, 1).dot(u) - norm = DoubleTensorAlgebra { (v dot v).sqrt().value() } - v = v.times(1.0 / norm) - } - - res.add(Triple(norm, u, v)) - } - - val s = res.map { it.first }.toDoubleArray() - val uBuffer = res.map { it.second }.flatMap { it.mutableBuffer.array().toList() }.toDoubleArray() - val vBuffer = res.map { it.third }.flatMap { it.mutableBuffer.array().toList() }.toDoubleArray() - for (i in uBuffer.indices) { - matrixU.mutableBuffer.array()[matrixU.bufferStart + i] = uBuffer[i] - } - for (i in s.indices) { - matrixS.mutableBuffer.array()[matrixS.bufferStart + i] = s[i] - } - for (i in vBuffer.indices) { - matrixV.mutableBuffer.array()[matrixV.bufferStart + i] = vBuffer[i] - } -} - -internal fun cleanSymHelper(matrix: MutableStructure2D, n: Int) { - for (i in 0 until n) - for (j in 0 until n) { - if (i == j) { - matrix[i, j] = sign(matrix[i, j]) - } else { - matrix[i, j] = 0.0 - } - } -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt deleted file mode 100644 index 29aa02931..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/tensorCastsUtils.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core.internal - -import space.kscience.kmath.nd.MutableBufferND -import space.kscience.kmath.structures.asMutableBuffer -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.BufferedTensor -import space.kscience.kmath.tensors.core.DoubleTensor -import space.kscience.kmath.tensors.core.IntTensor - -internal fun BufferedTensor.asTensor(): IntTensor = - IntTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) - -internal fun BufferedTensor.asTensor(): DoubleTensor = - DoubleTensor(this.shape, this.mutableBuffer.array(), this.bufferStart) - -internal fun Tensor.copyToBufferedTensor(): BufferedTensor = - BufferedTensor( - this.shape, - TensorLinearStructure(this.shape).indices().map(this::get).toMutableList().asMutableBuffer(), 0 - ) - -internal fun Tensor.toBufferedTensor(): BufferedTensor = when (this) { - is BufferedTensor -> this - is MutableBufferND -> if (this.strides.strides contentEquals TensorLinearStructure(this.shape).strides) - BufferedTensor(this.shape, this.mutableBuffer, 0) else this.copyToBufferedTensor() - else -> this.copyToBufferedTensor() -} - -@PublishedApi -internal val Tensor.tensor: DoubleTensor - get() = when (this) { - is DoubleTensor -> this - else -> this.toBufferedTensor().asTensor() - } - -internal val Tensor.tensor: IntTensor - get() = when (this) { - is IntTensor -> this - else -> this.toBufferedTensor().asTensor() - } 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 deleted file mode 100644 index 6088c32e4..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/internal/utils.kt +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core.internal - -import space.kscience.kmath.nd.as1D -import space.kscience.kmath.samplers.GaussianSampler -import space.kscience.kmath.stat.RandomGenerator -import space.kscience.kmath.structures.* -import space.kscience.kmath.tensors.core.BufferedTensor -import space.kscience.kmath.tensors.core.DoubleTensor -import kotlin.math.* - -/** - * 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 - else -> this.toIntArray() -} - -/** - * 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() -} - -internal fun getRandomNormals(n: Int, seed: Long): DoubleArray { - val distribution = GaussianSampler(0.0, 1.0) - val generator = RandomGenerator.default(seed) - return distribution.sample(generator).nextBufferBlocking(n).toDoubleArray() -} - -internal fun getRandomUnitVector(n: Int, seed: Long): DoubleArray { - val unnorm = getRandomNormals(n, seed) - val norm = sqrt(unnorm.sumOf { it * it }) - return unnorm.map { it / norm }.toDoubleArray() -} - -internal fun minusIndexFrom(n: Int, i: Int): Int = if (i >= 0) i else { - val ii = n + i - check(ii >= 0) { - "Out of bound index $i for tensor of dim $n" - } - ii -} - -internal fun BufferedTensor.minusIndex(i: Int): Int = minusIndexFrom(this.dimension, i) - -internal fun format(value: Double, digits: Int = 4): String = buildString { - val res = buildString { - val ten = 10.0 - val approxOrder = if (value == 0.0) 0 else ceil(log10(abs(value))).toInt() - val order = if ( - ((value % ten) == 0.0) || - (value == 1.0) || - ((1 / value) % ten == 0.0) - ) approxOrder else approxOrder - 1 - val lead = value / ten.pow(order) - if (value >= 0.0) append(' ') - append(round(lead * ten.pow(digits)) / ten.pow(digits)) - when { - order == 0 -> Unit - order > 0 -> { - append("e+") - append(order) - } - else -> { - append('e') - append(order) - } - } - } - val fLength = digits + 6 - append(res) - repeat(fLength - res.length) { append(' ') } -} - -internal fun DoubleTensor.toPrettyString(): String = buildString { - var offset = 0 - val shape = this@toPrettyString.shape - val linearStructure = this@toPrettyString.linearStructure - val vectorSize = shape.last() - append("DoubleTensor(\n") - var charOffset = 3 - for (vector in vectorSequence()) { - repeat(charOffset) { append(' ') } - val index = linearStructure.index(offset) - for (ind in index.reversed()) { - if (ind != 0) { - break - } - append('[') - charOffset += 1 - } - - val values = vector.as1D().toMutableList().map(::format) - - values.joinTo(this, separator = ", ") - - append(']') - charOffset -= 1 - - index.reversed().zip(shape.reversed()).drop(1).forEach { (ind, maxInd) -> - if (ind != maxInd - 1) { - return@forEach - } - append(']') - charOffset -= 1 - } - - offset += vectorSize - if (this@toPrettyString.numElements == offset) { - break - } - - append(",\n") - } - append("\n)") -} diff --git a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt b/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt deleted file mode 100644 index 021ca539c..000000000 --- a/kmath-tensors/src/commonMain/kotlin/space/kscience/kmath/tensors/core/tensorCasts.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.tensors.api.Tensor -import space.kscience.kmath.tensors.core.internal.tensor - -/** - * Casts [Tensor] of [Double] to [DoubleTensor] - */ -public fun Tensor.toDoubleTensor(): DoubleTensor = this.tensor - -/** - * Casts [Tensor] of [Int] to [IntTensor] - */ -public fun Tensor.toIntTensor(): IntTensor = this.tensor - -/** - * Returns [DoubleArray] of tensor elements - */ -public fun DoubleTensor.toDoubleArray(): DoubleArray { - return DoubleArray(numElements) { i -> - mutableBuffer[bufferStart + i] - } -} - -/** - * Returns [IntArray] of tensor elements - */ -public fun IntTensor.toIntArray(): IntArray { - return IntArray(numElements) { i -> - mutableBuffer[bufferStart + i] - } -} diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt deleted file mode 100644 index 1171b5217..000000000 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestBroadcasting.kt +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.internal.* -import kotlin.test.Test -import kotlin.test.assertTrue - -internal class TestBroadcasting { - - @Test - fun testBroadcastShapes() = DoubleTensorAlgebra { - assertTrue( - broadcastShapes( - intArrayOf(2, 3), intArrayOf(1, 3), intArrayOf(1, 1, 1) - ) contentEquals intArrayOf(1, 2, 3) - ) - - assertTrue( - broadcastShapes( - intArrayOf(6, 7), intArrayOf(5, 6, 1), intArrayOf(7), intArrayOf(5, 1, 7) - ) contentEquals intArrayOf(5, 6, 7) - ) - } - - @Test - fun testBroadcastTo() = DoubleTensorAlgebra { - val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = fromArray(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) - - val res = broadcastTo(tensor2, tensor1.shape) - assertTrue(res.shape contentEquals intArrayOf(2, 3)) - assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0)) - } - - @Test - fun testBroadcastTensors() = DoubleTensorAlgebra { - val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = fromArray(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) - val tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) - - val res = broadcastTensors(tensor1, tensor2, tensor3) - - assertTrue(res[0].shape contentEquals intArrayOf(1, 2, 3)) - assertTrue(res[1].shape contentEquals intArrayOf(1, 2, 3)) - assertTrue(res[2].shape contentEquals intArrayOf(1, 2, 3)) - - assertTrue(res[0].mutableBuffer.array() contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - assertTrue(res[1].mutableBuffer.array() contentEquals doubleArrayOf(10.0, 20.0, 30.0, 10.0, 20.0, 30.0)) - assertTrue(res[2].mutableBuffer.array() contentEquals doubleArrayOf(500.0, 500.0, 500.0, 500.0, 500.0, 500.0)) - } - - @Test - fun testBroadcastOuterTensors() = DoubleTensorAlgebra { - val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = fromArray(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) - val tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) - - val res = broadcastOuterTensors(tensor1, tensor2, tensor3) - - assertTrue(res[0].shape contentEquals intArrayOf(1, 2, 3)) - assertTrue(res[1].shape contentEquals intArrayOf(1, 1, 3)) - assertTrue(res[2].shape contentEquals intArrayOf(1, 1, 1)) - - assertTrue(res[0].mutableBuffer.array() contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - assertTrue(res[1].mutableBuffer.array() contentEquals doubleArrayOf(10.0, 20.0, 30.0)) - assertTrue(res[2].mutableBuffer.array() contentEquals doubleArrayOf(500.0)) - } - - @Test - fun testBroadcastOuterTensorsShapes() = DoubleTensorAlgebra { - val tensor1 = fromArray(intArrayOf(2, 1, 3, 2, 3), DoubleArray(2 * 1 * 3 * 2 * 3) {0.0}) - val tensor2 = fromArray(intArrayOf(4, 2, 5, 1, 3, 3), DoubleArray(4 * 2 * 5 * 1 * 3 * 3) {0.0}) - val tensor3 = fromArray(intArrayOf(1, 1), doubleArrayOf(500.0)) - - val res = broadcastOuterTensors(tensor1, tensor2, tensor3) - - assertTrue(res[0].shape contentEquals intArrayOf(4, 2, 5, 3, 2, 3)) - assertTrue(res[1].shape contentEquals intArrayOf(4, 2, 5, 3, 3, 3)) - assertTrue(res[2].shape contentEquals intArrayOf(4, 2, 5, 3, 1, 1)) - } - - @Test - fun testMinusTensor() = BroadcastDoubleTensorAlgebra.invoke { - val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = fromArray(intArrayOf(1, 3), doubleArrayOf(10.0, 20.0, 30.0)) - val tensor3 = fromArray(intArrayOf(1, 1, 1), doubleArrayOf(500.0)) - - val tensor21 = tensor2 - tensor1 - val tensor31 = tensor3 - tensor1 - val tensor32 = tensor3 - tensor2 - - assertTrue(tensor21.shape contentEquals intArrayOf(2, 3)) - assertTrue(tensor21.mutableBuffer.array() contentEquals doubleArrayOf(9.0, 18.0, 27.0, 6.0, 15.0, 24.0)) - - assertTrue(tensor31.shape contentEquals intArrayOf(1, 2, 3)) - assertTrue( - tensor31.mutableBuffer.array() - contentEquals doubleArrayOf(499.0, 498.0, 497.0, 496.0, 495.0, 494.0) - ) - - assertTrue(tensor32.shape contentEquals intArrayOf(1, 1, 3)) - assertTrue(tensor32.mutableBuffer.array() contentEquals doubleArrayOf(490.0, 480.0, 470.0)) - } - -} diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt deleted file mode 100644 index ba8182da2..000000000 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleAnalyticTensorAlgebra.kt +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.operations.invoke -import kotlin.math.* -import kotlin.test.Test -import kotlin.test.assertTrue - -internal class TestDoubleAnalyticTensorAlgebra { - - val shape = intArrayOf(2, 1, 3, 2) - val buffer = doubleArrayOf( - 27.1, 20.0, 19.84, - 23.123, 3.0, 2.0, - - 3.23, 133.7, 25.3, - 100.3, 11.0, 12.012 - ) - val tensor = DoubleTensor(shape, buffer) - - fun DoubleArray.fmap(transform: (Double) -> Double): DoubleArray { - return this.map(transform).toDoubleArray() - } - - fun expectedTensor(transform: (Double) -> Double): DoubleTensor { - return DoubleTensor(shape, buffer.fmap(transform)) - } - - @Test - fun testExp() = DoubleTensorAlgebra { - assertTrue { tensor.exp() eq expectedTensor(::exp) } - } - - @Test - fun testLog() = DoubleTensorAlgebra { - assertTrue { tensor.ln() eq expectedTensor(::ln) } - } - - @Test - fun testSqrt() = DoubleTensorAlgebra { - assertTrue { tensor.sqrt() eq expectedTensor(::sqrt) } - } - - @Test - fun testCos() = DoubleTensorAlgebra { - assertTrue { tensor.cos() eq expectedTensor(::cos) } - } - - - @Test - fun testCosh() = DoubleTensorAlgebra { - assertTrue { tensor.cosh() eq expectedTensor(::cosh) } - } - - @Test - fun testAcosh() = DoubleTensorAlgebra { - assertTrue { tensor.acosh() eq expectedTensor(::acosh) } - } - - @Test - fun testSin() = DoubleTensorAlgebra { - assertTrue { tensor.sin() eq expectedTensor(::sin) } - } - - @Test - fun testSinh() = DoubleTensorAlgebra { - assertTrue { tensor.sinh() eq expectedTensor(::sinh) } - } - - @Test - fun testAsinh() = DoubleTensorAlgebra { - assertTrue { tensor.asinh() eq expectedTensor(::asinh) } - } - - @Test - fun testTan() = DoubleTensorAlgebra { - assertTrue { tensor.tan() eq expectedTensor(::tan) } - } - - @Test - fun testAtan() = DoubleTensorAlgebra { - assertTrue { tensor.atan() eq expectedTensor(::atan) } - } - - @Test - fun testTanh() = DoubleTensorAlgebra { - assertTrue { tensor.tanh() eq expectedTensor(::tanh) } - } - - @Test - fun testCeil() = DoubleTensorAlgebra { - assertTrue { tensor.ceil() eq expectedTensor(::ceil) } - } - - @Test - fun testFloor() = DoubleTensorAlgebra { - assertTrue { tensor.floor() eq expectedTensor(::floor) } - } - - val shape2 = intArrayOf(2, 2) - val buffer2 = doubleArrayOf( - 1.0, 2.0, - -3.0, 4.0 - ) - val tensor2 = DoubleTensor(shape2, buffer2) - - @Test - fun testMin() = DoubleTensorAlgebra { - assertTrue { tensor2.min() == -3.0 } - assertTrue { tensor2.min(0, true) eq fromArray( - intArrayOf(1, 2), - doubleArrayOf(-3.0, 2.0) - )} - assertTrue { tensor2.min(1, false) eq fromArray( - intArrayOf(2), - doubleArrayOf(1.0, -3.0) - )} - } - - @Test - fun testMax() = DoubleTensorAlgebra { - assertTrue { tensor2.max() == 4.0 } - assertTrue { tensor2.max(0, true) eq fromArray( - intArrayOf(1, 2), - doubleArrayOf(1.0, 4.0) - )} - assertTrue { tensor2.max(1, false) eq fromArray( - intArrayOf(2), - doubleArrayOf(2.0, 4.0) - )} - } - - @Test - fun testSum() = DoubleTensorAlgebra { - assertTrue { tensor2.sum() == 4.0 } - assertTrue { tensor2.sum(0, true) eq fromArray( - intArrayOf(1, 2), - doubleArrayOf(-2.0, 6.0) - )} - assertTrue { tensor2.sum(1, false) eq fromArray( - intArrayOf(2), - doubleArrayOf(3.0, 1.0) - )} - } - - @Test - fun testMean() = DoubleTensorAlgebra { - assertTrue { tensor2.mean() == 1.0 } - assertTrue { tensor2.mean(0, true) eq fromArray( - intArrayOf(1, 2), - doubleArrayOf(-1.0, 3.0) - )} - assertTrue { tensor2.mean(1, false) eq fromArray( - intArrayOf(2), - doubleArrayOf(1.5, 0.5) - )} - } - -} 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 deleted file mode 100644 index c50c99b54..000000000 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleLinearOpsAlgebra.kt +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.internal.array -import space.kscience.kmath.tensors.core.internal.svd1d -import kotlin.math.abs -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -internal class TestDoubleLinearOpsTensorAlgebra { - - @Test - fun testDetLU() = DoubleTensorAlgebra { - val tensor = fromArray( - intArrayOf(2, 2, 2), - doubleArrayOf( - 1.0, 3.0, - 1.0, 2.0, - 1.5, 1.0, - 10.0, 2.0 - ) - ) - - val expectedTensor = fromArray( - intArrayOf(2, 1), - doubleArrayOf( - -1.0, - -7.0 - ) - ) - val detTensor = tensor.detLU() - - assertTrue(detTensor.eq(expectedTensor)) - - } - - @Test - fun testDet() = DoubleTensorAlgebra { - val expectedValue = 0.019827417 - val m = fromArray( - intArrayOf(3, 3), doubleArrayOf( - 2.1843, 1.4391, -0.4845, - 1.4391, 1.7772, 0.4055, - -0.4845, 0.4055, 0.7519 - ) - ) - - assertTrue { abs(m.det().value() - expectedValue) < 1e-5 } - } - - @Test - fun testDetSingle() = DoubleTensorAlgebra { - val expectedValue = 48.151623 - val m = fromArray( - intArrayOf(1, 1), doubleArrayOf( - expectedValue - ) - ) - - assertTrue { abs(m.det().value() - expectedValue) < 1e-5 } - } - - @Test - fun testInvLU() = DoubleTensorAlgebra { - val tensor = fromArray( - intArrayOf(2, 2, 2), - doubleArrayOf( - 1.0, 0.0, - 0.0, 2.0, - 1.0, 1.0, - 1.0, 0.0 - ) - ) - - val expectedTensor = fromArray( - intArrayOf(2, 2, 2), doubleArrayOf( - 1.0, 0.0, - 0.0, 0.5, - 0.0, 1.0, - 1.0, -1.0 - ) - ) - - val invTensor = tensor.invLU() - assertTrue(invTensor.eq(expectedTensor)) - } - - @Test - fun testScalarProduct() = DoubleTensorAlgebra { - val a = fromArray(intArrayOf(3), doubleArrayOf(1.8, 2.5, 6.8)) - val b = fromArray(intArrayOf(3), doubleArrayOf(5.5, 2.6, 6.4)) - assertEquals(a.dot(b).value(), 59.92) - } - - @Test - fun testQR() = DoubleTensorAlgebra { - val shape = intArrayOf(2, 2, 2) - val buffer = doubleArrayOf( - 1.0, 3.0, - 1.0, 2.0, - 1.5, 1.0, - 10.0, 2.0 - ) - - val tensor = fromArray(shape, buffer) - - val (q, r) = tensor.qr() - - assertTrue { q.shape contentEquals shape } - assertTrue { r.shape contentEquals shape } - - assertTrue((q dot r).eq(tensor)) - - } - - @Test - fun testLU() = DoubleTensorAlgebra { - val shape = intArrayOf(2, 2, 2) - val buffer = doubleArrayOf( - 1.0, 3.0, - 1.0, 2.0, - 1.5, 1.0, - 10.0, 2.0 - ) - val tensor = fromArray(shape, buffer) - - val (p, l, u) = tensor.lu() - - assertTrue { p.shape contentEquals shape } - assertTrue { l.shape contentEquals shape } - assertTrue { u.shape contentEquals shape } - - assertTrue((p dot tensor).eq(l dot u)) - } - - @Test - fun testCholesky() = DoubleTensorAlgebra { - val tensor = randomNormal(intArrayOf(2, 5, 5), 0) - val sigma = (tensor dot tensor.transpose()) + diagonalEmbedding( - fromArray(intArrayOf(2, 5), DoubleArray(10) { 0.1 }) - ) - val low = sigma.cholesky() - val sigmChol = low dot low.transpose() - assertTrue(sigma.eq(sigmChol)) - } - - @Test - fun testSVD1D() = DoubleTensorAlgebra { - val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - - val res = svd1d(tensor2) - - assertTrue(res.shape contentEquals intArrayOf(2)) - assertTrue { abs(abs(res.mutableBuffer.array()[res.bufferStart]) - 0.386) < 0.01 } - assertTrue { abs(abs(res.mutableBuffer.array()[res.bufferStart + 1]) - 0.922) < 0.01 } - } - - @Test - fun testSVD() = DoubleTensorAlgebra{ - testSVDFor(fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0))) - testSVDFor(fromArray(intArrayOf(2, 2), doubleArrayOf(-1.0, 0.0, 239.0, 238.0))) - } - - @Test - fun testBatchedSVD() = DoubleTensorAlgebra { - val tensor = randomNormal(intArrayOf(2, 5, 3), 0) - val (tensorU, tensorS, tensorV) = tensor.svd() - val tensorSVD = tensorU dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) - assertTrue(tensor.eq(tensorSVD)) - } - - @Test - fun testBatchedSymEig() = DoubleTensorAlgebra { - val tensor = randomNormal(shape = intArrayOf(2, 3, 3), 0) - val tensorSigma = tensor + tensor.transpose() - val (tensorS, tensorV) = tensorSigma.symEig() - val tensorSigmaCalc = tensorV dot (diagonalEmbedding(tensorS) dot tensorV.transpose()) - assertTrue(tensorSigma.eq(tensorSigmaCalc)) - } - - -} - - -private fun DoubleTensorAlgebra.testSVDFor(tensor: DoubleTensor, epsilon: Double = 1e-10) { - val svd = tensor.svd() - - val tensorSVD = svd.first - .dot( - diagonalEmbedding(svd.second) - .dot(svd.third.transpose()) - ) - - assertTrue(tensor.eq(tensorSVD, epsilon)) -} diff --git a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt b/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt deleted file mode 100644 index 2686df19e..000000000 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensor.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core - -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.nd.DefaultStrides -import space.kscience.kmath.nd.MutableBufferND -import space.kscience.kmath.nd.as1D -import space.kscience.kmath.nd.as2D -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.structures.DoubleBuffer -import space.kscience.kmath.structures.toDoubleArray -import space.kscience.kmath.tensors.core.internal.array -import space.kscience.kmath.tensors.core.internal.asTensor -import space.kscience.kmath.tensors.core.internal.matrixSequence -import space.kscience.kmath.tensors.core.internal.toBufferedTensor -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -internal class TestDoubleTensor { - - @Test - fun testValue() = DoubleTensorAlgebra { - val value = 12.5 - val tensor = fromArray(intArrayOf(1), doubleArrayOf(value)) - assertEquals(tensor.value(), value) - } - - @OptIn(PerformancePitfall::class) - @Test - fun testStrides() = DoubleTensorAlgebra { - val tensor = fromArray(intArrayOf(2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4)) - assertEquals(tensor[intArrayOf(0, 1)], 5.8) - assertTrue( - tensor.elements().map { it.second }.toList().toDoubleArray() contentEquals tensor.mutableBuffer.toDoubleArray() - ) - } - - @Test - fun testGet() = DoubleTensorAlgebra { - val tensor = fromArray(intArrayOf(1, 2, 2), doubleArrayOf(3.5, 5.8, 58.4, 2.4)) - val matrix = tensor[0].as2D() - assertEquals(matrix[0, 1], 5.8) - - val vector = tensor[0][1].as1D() - assertEquals(vector[0], 58.4) - - matrix[0, 1] = 77.89 - assertEquals(tensor[intArrayOf(0, 0, 1)], 77.89) - - vector[0] = 109.56 - assertEquals(tensor[intArrayOf(0, 1, 0)], 109.56) - - tensor.matrixSequence().forEach { - val a = it.asTensor() - val secondRow = a[1].as1D() - val secondColumn = a.transpose(0, 1)[1].as1D() - assertEquals(secondColumn[0], 77.89) - assertEquals(secondRow[1], secondColumn[1]) - } - } - - @Test - fun testNoBufferProtocol() { - - // create buffer - val doubleArray = DoubleBuffer(doubleArrayOf(1.0, 2.0, 3.0)) - - // create ND buffers, no data is copied - val ndArray = MutableBufferND(DefaultStrides(intArrayOf(3)), doubleArray) - - // map to tensors - val bufferedTensorArray = ndArray.toBufferedTensor() // strides are flipped so data copied - val tensorArray = bufferedTensorArray.asTensor() // data not contiguous so copied again - - val tensorArrayPublic = ndArray.toDoubleTensor() // public API, data copied twice - val sharedTensorArray = tensorArrayPublic.toDoubleTensor() // no data copied by matching type - - assertTrue(tensorArray.mutableBuffer.array() contentEquals sharedTensorArray.mutableBuffer.array()) - - tensorArray[intArrayOf(0)] = 55.9 - assertEquals(tensorArrayPublic[intArrayOf(0)], 1.0) - - tensorArrayPublic[intArrayOf(0)] = 55.9 - assertEquals(sharedTensorArray[intArrayOf(0)], 55.9) - assertEquals(bufferedTensorArray[intArrayOf(0)], 1.0) - - bufferedTensorArray[intArrayOf(0)] = 55.9 - assertEquals(ndArray[intArrayOf(0)], 1.0) - - } -} 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 deleted file mode 100644 index 2aee03b82..000000000 --- a/kmath-tensors/src/commonTest/kotlin/space/kscience/kmath/tensors/core/TestDoubleTensorAlgebra.kt +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.tensors.core - - -import space.kscience.kmath.operations.invoke -import space.kscience.kmath.tensors.core.internal.array -import kotlin.test.Test -import kotlin.test.assertFalse -import kotlin.test.assertTrue - -internal class TestDoubleTensorAlgebra { - - @Test - fun testDoublePlus() = DoubleTensorAlgebra { - val tensor = fromArray(intArrayOf(2), doubleArrayOf(1.0, 2.0)) - val res = 10.0 + tensor - assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(11.0, 12.0)) - } - - @Test - fun testDoubleDiv() = DoubleTensorAlgebra { - val tensor = fromArray(intArrayOf(2), doubleArrayOf(2.0, 4.0)) - val res = 2.0/tensor - assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 0.5)) - } - - @Test - fun testDivDouble() = DoubleTensorAlgebra { - val tensor = fromArray(intArrayOf(2), doubleArrayOf(10.0, 5.0)) - val res = tensor / 2.5 - assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(4.0, 2.0)) - } - - @Test - fun testTranspose1x1() = DoubleTensorAlgebra { - val tensor = fromArray(intArrayOf(1), doubleArrayOf(0.0)) - val res = tensor.transpose(0, 0) - - assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(0.0)) - assertTrue(res.shape contentEquals intArrayOf(1)) - } - - @Test - fun testTranspose3x2() = DoubleTensorAlgebra { - val tensor = fromArray(intArrayOf(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val res = tensor.transpose(1, 0) - - assertTrue(res.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 3.0, 5.0, 2.0, 4.0, 6.0)) - assertTrue(res.shape contentEquals intArrayOf(2, 3)) - } - - @Test - fun testTranspose1x2x3() = DoubleTensorAlgebra { - val tensor = fromArray(intArrayOf(1, 2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val res01 = tensor.transpose(0, 1) - val res02 = tensor.transpose(-3, 2) - val res12 = tensor.transpose() - - assertTrue(res01.shape contentEquals intArrayOf(2, 1, 3)) - assertTrue(res02.shape contentEquals intArrayOf(3, 2, 1)) - assertTrue(res12.shape contentEquals intArrayOf(1, 3, 2)) - - assertTrue(res01.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - assertTrue(res02.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0)) - assertTrue(res12.mutableBuffer.array() contentEquals doubleArrayOf(1.0, 4.0, 2.0, 5.0, 3.0, 6.0)) - } - - @Test - fun testLinearStructure() = DoubleTensorAlgebra { - val shape = intArrayOf(3) - val tensorA = full(value = -4.5, shape = shape) - val tensorB = full(value = 10.9, shape = shape) - val tensorC = full(value = 789.3, shape = shape) - val tensorD = full(value = -72.9, shape = shape) - val tensorE = full(value = 553.1, shape = shape) - val result = 15.8 * tensorA - 1.5 * tensorB * (-tensorD) + 0.02 * tensorC / tensorE - 39.4 - - val expected = fromArray( - shape, - (1..3).map { - 15.8 * (-4.5) - 1.5 * 10.9 * 72.9 + 0.02 * 789.3 / 553.1 - 39.4 - }.toDoubleArray() - ) - - val assignResult = zeros(shape) - tensorA *= 15.8 - tensorB *= 1.5 - tensorB *= -tensorD - tensorC *= 0.02 - tensorC /= tensorE - assignResult += tensorA - assignResult -= tensorB - assignResult += tensorC - assignResult += -39.4 - - assertTrue(expected.mutableBuffer.array() contentEquals result.mutableBuffer.array()) - assertTrue(expected.mutableBuffer.array() contentEquals assignResult.mutableBuffer.array()) - } - - @Test - fun testDot() = DoubleTensorAlgebra { - val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor11 = fromArray(intArrayOf(3, 2), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = fromArray(intArrayOf(3), doubleArrayOf(10.0, 20.0, 30.0)) - val tensor3 = fromArray(intArrayOf(1, 1, 3), doubleArrayOf(-1.0, -2.0, -3.0)) - - val res12 = tensor1.dot(tensor2) - assertTrue(res12.mutableBuffer.array() contentEquals doubleArrayOf(140.0, 320.0)) - assertTrue(res12.shape contentEquals intArrayOf(2)) - - val res32 = tensor3.dot(tensor2) - assertTrue(res32.mutableBuffer.array() contentEquals doubleArrayOf(-140.0)) - assertTrue(res32.shape contentEquals intArrayOf(1, 1)) - - val res22 = tensor2.dot(tensor2) - assertTrue(res22.mutableBuffer.array() contentEquals doubleArrayOf(1400.0)) - assertTrue(res22.shape contentEquals intArrayOf(1)) - - val res11 = tensor1.dot(tensor11) - assertTrue(res11.mutableBuffer.array() contentEquals doubleArrayOf(22.0, 28.0, 49.0, 64.0)) - assertTrue(res11.shape contentEquals intArrayOf(2, 2)) - } - - @Test - fun testDiagonalEmbedding() = DoubleTensorAlgebra { - val tensor1 = fromArray(intArrayOf(3), doubleArrayOf(10.0, 20.0, 30.0)) - val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor3 = zeros(intArrayOf(2, 3, 4, 5)) - - assertTrue(diagonalEmbedding(tensor3, 0, 3, 4).shape contentEquals - intArrayOf(2, 3, 4, 5, 5)) - assertTrue(diagonalEmbedding(tensor3, 1, 3, 4).shape contentEquals - intArrayOf(2, 3, 4, 6, 6)) - assertTrue(diagonalEmbedding(tensor3, 2, 0, 3).shape contentEquals - intArrayOf(7, 2, 3, 7, 4)) - - val diagonal1 = diagonalEmbedding(tensor1, 0, 1, 0) - assertTrue(diagonal1.shape contentEquals intArrayOf(3, 3)) - assertTrue(diagonal1.mutableBuffer.array() contentEquals - doubleArrayOf(10.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 30.0)) - - val diagonal1Offset = diagonalEmbedding(tensor1, 1, 1, 0) - assertTrue(diagonal1Offset.shape contentEquals intArrayOf(4, 4)) - assertTrue(diagonal1Offset.mutableBuffer.array() contentEquals - doubleArrayOf(0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 30.0, 0.0)) - - val diagonal2 = diagonalEmbedding(tensor2, 1, 0, 2) - assertTrue(diagonal2.shape contentEquals intArrayOf(4, 2, 4)) - assertTrue(diagonal2.mutableBuffer.array() contentEquals - doubleArrayOf( - 0.0, 1.0, 0.0, 0.0, 0.0, 4.0, 0.0, 0.0, - 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 5.0, 0.0, - 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 6.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)) - } - - @Test - fun testEq() = DoubleTensorAlgebra { - val tensor1 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor2 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)) - val tensor3 = fromArray(intArrayOf(2, 3), doubleArrayOf(1.0, 2.0, 3.0, 4.0, 5.0, 5.0)) - - assertTrue(tensor1 eq tensor1) - assertTrue(tensor1 eq tensor2) - assertFalse(tensor1.eq(tensor3)) - - } -} diff --git a/kmath-viktor/api/kmath-viktor.api b/kmath-viktor/api/kmath-viktor.api deleted file mode 100644 index 59882627b..000000000 --- a/kmath-viktor/api/kmath-viktor.api +++ /dev/null @@ -1,83 +0,0 @@ -public final class space/kscience/kmath/viktor/ViktorBuffer : space/kscience/kmath/structures/MutableBuffer { - public fun (Lorg/jetbrains/bio/viktor/F64FlatArray;)V - public fun copy ()Lspace/kscience/kmath/structures/MutableBuffer; - public fun get (I)Ljava/lang/Double; - public synthetic fun get (I)Ljava/lang/Object; - public final fun getFlatArray ()Lorg/jetbrains/bio/viktor/F64FlatArray; - public fun getSize ()I - public fun iterator ()Ljava/util/Iterator; - public fun set (ID)V - public synthetic fun set (ILjava/lang/Object;)V -} - -public final class space/kscience/kmath/viktor/ViktorFieldND : space/kscience/kmath/nd/FieldND, space/kscience/kmath/operations/ExtendedField, space/kscience/kmath/operations/NumbersAddOperations, space/kscience/kmath/operations/ScaleOperations { - public fun ([I)V - public synthetic fun acos (Ljava/lang/Object;)Ljava/lang/Object; - public fun acos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public synthetic fun add (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; - public fun add (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun asin (Ljava/lang/Object;)Ljava/lang/Object; - public fun asin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun atan (Ljava/lang/Object;)Ljava/lang/Object; - public fun atan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun combine (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; - public fun combine (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun cos (Ljava/lang/Object;)Ljava/lang/Object; - public fun cos (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun exp (Ljava/lang/Object;)Ljava/lang/Object; - public fun exp (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun getElementContext ()Lspace/kscience/kmath/operations/Algebra; - public fun getElementContext ()Lspace/kscience/kmath/operations/DoubleField; - public final fun getF64Buffer (Lspace/kscience/kmath/nd/StructureND;)Lorg/jetbrains/bio/viktor/F64Array; - public synthetic fun getOne ()Ljava/lang/Object; - public fun getOne ()Lspace/kscience/kmath/viktor/ViktorStructureND; - public fun getShape ()[I - public synthetic fun getZero ()Ljava/lang/Object; - public fun getZero ()Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun ln (Ljava/lang/Object;)Ljava/lang/Object; - public fun ln (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; - public fun map (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/nd/StructureND; - public fun mapIndexed (Lspace/kscience/kmath/nd/StructureND;Lkotlin/jvm/functions/Function3;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun minus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun minus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun number (Ljava/lang/Number;)Ljava/lang/Object; - public fun number (Ljava/lang/Number;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun plus (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; - public fun plus (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun plus (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Object;)Lspace/kscience/kmath/nd/StructureND; - public fun plus (Lspace/kscience/kmath/nd/StructureND;Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun power (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun power (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun produce (Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/nd/StructureND; - public fun produce (Lkotlin/jvm/functions/Function2;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun scale (Ljava/lang/Object;D)Ljava/lang/Object; - public fun scale (Lspace/kscience/kmath/nd/StructureND;D)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun sin (Ljava/lang/Object;)Ljava/lang/Object; - public fun sin (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun tan (Ljava/lang/Object;)Ljava/lang/Object; - public fun tan (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun times (Ljava/lang/Object;Ljava/lang/Number;)Ljava/lang/Object; - public fun times (Lspace/kscience/kmath/nd/StructureND;Ljava/lang/Number;)Lspace/kscience/kmath/viktor/ViktorStructureND; - public synthetic fun unaryMinus (Ljava/lang/Object;)Ljava/lang/Object; - public fun unaryMinus (Lspace/kscience/kmath/nd/StructureND;)Lspace/kscience/kmath/nd/StructureND; -} - -public final class space/kscience/kmath/viktor/ViktorStructureND : space/kscience/kmath/nd/MutableStructureND { - public fun (Lorg/jetbrains/bio/viktor/F64Array;)V - public fun elements ()Lkotlin/sequences/Sequence; - public fun get ([I)Ljava/lang/Double; - public synthetic fun get ([I)Ljava/lang/Object; - public final fun getF64Buffer ()Lorg/jetbrains/bio/viktor/F64Array; - public fun getShape ()[I - public fun set ([ID)V - public synthetic fun set ([ILjava/lang/Object;)V -} - -public final class space/kscience/kmath/viktor/ViktorStructureNDKt { - public static final fun ViktorNDField ([I)Lspace/kscience/kmath/viktor/ViktorFieldND; - public static final fun asStructure (Lorg/jetbrains/bio/viktor/F64Array;)Lspace/kscience/kmath/viktor/ViktorStructureND; -} - diff --git a/kmath-viktor/build.gradle.kts b/kmath-viktor/build.gradle.kts index 2e932b441..52ee7c497 100644 --- a/kmath-viktor/build.gradle.kts +++ b/kmath-viktor/build.gradle.kts @@ -1,15 +1,10 @@ plugins { - kotlin("jvm") - id("ru.mipt.npm.gradle.common") + id("scientifik.jvm") } description = "Binding for https://github.com/JetBrains-Research/viktor" dependencies { api(project(":kmath-core")) - api("org.jetbrains.bio:viktor:1.1.0") -} - -readme { - maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT -} + api("org.jetbrains.bio:viktor:1.0.1") +} \ No newline at end of file diff --git a/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorBuffer.kt b/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorBuffer.kt new file mode 100644 index 000000000..040eee951 --- /dev/null +++ b/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorBuffer.kt @@ -0,0 +1,20 @@ +package scientifik.kmath.viktor + +import org.jetbrains.bio.viktor.F64FlatArray +import scientifik.kmath.structures.MutableBuffer + +@Suppress("NOTHING_TO_INLINE", "OVERRIDE_BY_INLINE") +inline class ViktorBuffer(val flatArray: F64FlatArray) : MutableBuffer { + override val size: Int get() = flatArray.size + + override inline fun get(index: Int): Double = flatArray[index] + override inline fun set(index: Int, value: Double) { + flatArray[index] = value + } + + override fun copy(): MutableBuffer { + return ViktorBuffer(flatArray.copy().flatten()) + } + + override fun iterator(): Iterator = flatArray.data.iterator() +} \ No newline at end of file diff --git a/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorNDStructure.kt b/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorNDStructure.kt new file mode 100644 index 000000000..84e927721 --- /dev/null +++ b/kmath-viktor/src/main/kotlin/scientifik/kmath/viktor/ViktorNDStructure.kt @@ -0,0 +1,86 @@ +package scientifik.kmath.viktor + +import org.jetbrains.bio.viktor.F64Array +import scientifik.kmath.operations.RealField +import scientifik.kmath.structures.DefaultStrides +import scientifik.kmath.structures.MutableNDStructure +import scientifik.kmath.structures.NDField + +@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +inline class ViktorNDStructure(val f64Buffer: F64Array) : MutableNDStructure { + + override val shape: IntArray get() = f64Buffer.shape + + override inline fun get(index: IntArray): Double = f64Buffer.get(*index) + + override inline fun set(index: IntArray, value: Double) { + f64Buffer.set(*index, value = value) + } + + override fun elements(): Sequence> { + return DefaultStrides(shape).indices().map { it to get(it) } + } +} + +fun F64Array.asStructure(): ViktorNDStructure = ViktorNDStructure(this) + +@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") +class ViktorNDField(override val shape: IntArray) : NDField { + override val zero: ViktorNDStructure + get() = F64Array.full(init = 0.0, shape = *shape).asStructure() + override val one: ViktorNDStructure + get() = F64Array.full(init = 1.0, shape = *shape).asStructure() + + val strides = DefaultStrides(shape) + + override val elementContext: RealField get() = RealField + + override fun produce(initializer: RealField.(IntArray) -> Double): ViktorNDStructure = F64Array(*shape).apply { + this@ViktorNDField.strides.indices().forEach { index -> + set(value = RealField.initializer(index), indices = *index) + } + }.asStructure() + + override fun map(arg: ViktorNDStructure, transform: RealField.(Double) -> Double): ViktorNDStructure = + F64Array(*shape).apply { + this@ViktorNDField.strides.indices().forEach { index -> + set(value = RealField.transform(arg[index]), indices = *index) + } + }.asStructure() + + override fun mapIndexed( + arg: ViktorNDStructure, + transform: RealField.(index: IntArray, Double) -> Double + ): ViktorNDStructure = F64Array(*shape).apply { + this@ViktorNDField.strides.indices().forEach { index -> + set(value = RealField.transform(index, arg[index]), indices = *index) + } + }.asStructure() + + override fun combine( + a: ViktorNDStructure, + b: ViktorNDStructure, + transform: RealField.(Double, Double) -> Double + ): ViktorNDStructure = F64Array(*shape).apply { + this@ViktorNDField.strides.indices().forEach { index -> + set(value = RealField.transform(a[index], b[index]), indices = *index) + } + }.asStructure() + + override fun add(a: ViktorNDStructure, b: ViktorNDStructure): ViktorNDStructure { + return (a.f64Buffer + b.f64Buffer).asStructure() + } + + override fun multiply(a: ViktorNDStructure, k: Number): ViktorNDStructure = + (a.f64Buffer * k.toDouble()).asStructure() + + override inline fun ViktorNDStructure.plus(b: ViktorNDStructure): ViktorNDStructure = + (f64Buffer + b.f64Buffer).asStructure() + + override inline fun ViktorNDStructure.minus(b: ViktorNDStructure): ViktorNDStructure = + (f64Buffer - b.f64Buffer).asStructure() + + override inline fun ViktorNDStructure.times(k: Number): ViktorNDStructure = (f64Buffer * k.toDouble()).asStructure() + + override inline fun ViktorNDStructure.plus(arg: Double): ViktorNDStructure = (f64Buffer.plus(arg)).asStructure() +} \ No newline at end of file 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 deleted file mode 100644 index caebd9783..000000000 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorBuffer.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.viktor - -import org.jetbrains.bio.viktor.F64FlatArray -import space.kscience.kmath.structures.MutableBuffer - -@Suppress("NOTHING_TO_INLINE", "OVERRIDE_BY_INLINE") -public class ViktorBuffer(public val flatArray: F64FlatArray) : MutableBuffer { - override val size: Int - get() = flatArray.size - - override inline fun get(index: Int): Double = flatArray[index] - - override inline fun set(index: Int, value: Double) { - flatArray[index] = value - } - - 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 deleted file mode 100644 index 682123ddd..000000000 --- a/kmath-viktor/src/main/kotlin/space/kscience/kmath/viktor/ViktorStructureND.kt +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2018-2021 KMath contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - */ - -package space.kscience.kmath.viktor - -import org.jetbrains.bio.viktor.F64Array -import space.kscience.kmath.misc.PerformancePitfall -import space.kscience.kmath.misc.UnstableKMathAPI -import space.kscience.kmath.nd.* -import space.kscience.kmath.operations.DoubleField -import space.kscience.kmath.operations.ExtendedField -import space.kscience.kmath.operations.NumbersAddOperations -import space.kscience.kmath.operations.ScaleOperations - -@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public class ViktorStructureND(public val f64Buffer: F64Array) : MutableStructureND { - override val shape: IntArray get() = f64Buffer.shape - - override inline fun get(index: IntArray): Double = f64Buffer.get(*index) - - override inline fun set(index: IntArray, value: Double) { - f64Buffer.set(*index, value = value) - } - - @PerformancePitfall - override fun elements(): Sequence> = - DefaultStrides(shape).indices().map { it to get(it) } -} - -public fun F64Array.asStructure(): ViktorStructureND = ViktorStructureND(this) - -@OptIn(UnstableKMathAPI::class) -@Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") -public class ViktorFieldND(override val shape: IntArray) : FieldND, - NumbersAddOperations>, ExtendedField>, - ScaleOperations> { - - public val StructureND.f64Buffer: F64Array - get() = when { - !shape.contentEquals(this@ViktorFieldND.shape) -> throw ShapeMismatchException( - this@ViktorFieldND.shape, - shape - ) - this is ViktorStructureND && this.f64Buffer.shape.contentEquals(this@ViktorFieldND.shape) -> this.f64Buffer - else -> produce { this@f64Buffer[it] }.f64Buffer - } - - override val zero: ViktorStructureND by lazy { F64Array.full(init = 0.0, shape = shape).asStructure() } - override val one: ViktorStructureND by lazy { F64Array.full(init = 1.0, shape = shape).asStructure() } - - private val strides: Strides = DefaultStrides(shape) - - override val elementContext: DoubleField get() = DoubleField - - override fun produce(initializer: DoubleField.(IntArray) -> Double): ViktorStructureND = - F64Array(*shape).apply { - this@ViktorFieldND.strides.indices().forEach { index -> - set(value = DoubleField.initializer(index), indices = index) - } - }.asStructure() - - override fun StructureND.unaryMinus(): StructureND = -1 * this - - override fun StructureND.map(transform: DoubleField.(Double) -> Double): ViktorStructureND = - F64Array(*this@ViktorFieldND.shape).apply { - this@ViktorFieldND.strides.indices().forEach { index -> - set(value = DoubleField.transform(this@map[index]), indices = index) - } - }.asStructure() - - override fun StructureND.mapIndexed( - transform: DoubleField.(index: IntArray, Double) -> Double, - ): ViktorStructureND = F64Array(*this@ViktorFieldND.shape).apply { - this@ViktorFieldND.strides.indices().forEach { index -> - set(value = DoubleField.transform(index, this@mapIndexed[index]), indices = index) - } - }.asStructure() - - override fun combine( - a: StructureND, - b: StructureND, - transform: DoubleField.(Double, Double) -> Double, - ): ViktorStructureND = F64Array(*shape).apply { - this@ViktorFieldND.strides.indices().forEach { index -> - set(value = DoubleField.transform(a[index], b[index]), indices = index) - } - }.asStructure() - - override fun add(a: StructureND, b: StructureND): ViktorStructureND = - (a.f64Buffer + b.f64Buffer).asStructure() - - override fun scale(a: StructureND, value: Double): ViktorStructureND = - (a.f64Buffer * value).asStructure() - - override inline fun StructureND.plus(b: StructureND): ViktorStructureND = - (f64Buffer + b.f64Buffer).asStructure() - - override inline fun StructureND.minus(b: StructureND): ViktorStructureND = - (f64Buffer - b.f64Buffer).asStructure() - - override inline fun StructureND.times(k: Number): ViktorStructureND = - (f64Buffer * k.toDouble()).asStructure() - - override inline fun StructureND.plus(arg: Double): ViktorStructureND = - (f64Buffer.plus(arg)).asStructure() - - override fun number(value: Number): ViktorStructureND = - F64Array.full(init = value.toDouble(), shape = shape).asStructure() - - override fun sin(arg: StructureND): ViktorStructureND = arg.map { sin(it) } - override fun cos(arg: StructureND): ViktorStructureND = arg.map { cos(it) } - override fun tan(arg: StructureND): ViktorStructureND = arg.map { tan(it) } - override fun asin(arg: StructureND): ViktorStructureND = arg.map { asin(it) } - override fun acos(arg: StructureND): ViktorStructureND = arg.map { acos(it) } - override fun atan(arg: StructureND): ViktorStructureND = arg.map { atan(it) } - - override fun power(arg: StructureND, pow: Number): ViktorStructureND = arg.map { it.pow(pow) } - - override fun exp(arg: StructureND): ViktorStructureND = arg.f64Buffer.exp().asStructure() - - override fun ln(arg: StructureND): ViktorStructureND = arg.f64Buffer.log().asStructure() -} - -public fun ViktorNDField(vararg shape: Int): ViktorFieldND = ViktorFieldND(shape) diff --git a/settings.gradle.kts b/settings.gradle.kts index f05092bb1..57173250b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,43 +1,48 @@ pluginManagement { - repositories { - maven("https://repo.kotlin.link") - mavenCentral() - gradlePluginPortal() - } - val kotlinVersion = "1.5.21" + val toolsVersion = "0.5.0" plugins { - id("org.jetbrains.kotlinx.benchmark") version "0.3.1" - id("ru.mipt.npm.gradle.project") version "0.10.2" - kotlin("multiplatform") version kotlinVersion - kotlin("plugin.allopen") version kotlinVersion + id("scientifik.mpp") version toolsVersion + id("scientifik.jvm") version toolsVersion + id("scientifik.atomic") version toolsVersion + id("scientifik.publish") version toolsVersion + } + + repositories { + mavenLocal() + jcenter() + gradlePluginPortal() + maven("https://dl.bintray.com/kotlin/kotlin-eap") + maven("https://dl.bintray.com/mipt-npm/scientifik") + maven("https://dl.bintray.com/mipt-npm/dev") + maven("https://dl.bintray.com/kotlin/kotlinx") + } + + resolutionStrategy { + eachPlugin { + when (requested.id.id) { + "scientifik.mpp", "scientifik.jvm", "scientifik.publish" -> useModule("scientifik:gradle-tools:$toolsVersion") + } + } } } rootProject.name = "kmath" - include( ":kmath-memory", - ":kmath-complex", ":kmath-core", - ":kmath-coroutines", ":kmath-functions", +// ":kmath-io", + ":kmath-coroutines", ":kmath-histograms", ":kmath-commons", ":kmath-viktor", - ":kmath-stat", - ":kmath-nd4j", + ":kmath-koma", + ":kmath-prob", + ":kmath-io", ":kmath-dimensions", ":kmath-for-real", ":kmath-geometry", - ":kmath-ast", - ":kmath-ejml", - ":kmath-kotlingrad", - ":kmath-tensors", - ":kmath-jupyter", - ":kmath-symja", - ":kmath-jafama", - ":examples", - ":benchmarks", + ":examples" )