diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 3d87335a9..98f4d2ec2 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,110 +1,42 @@
name: Gradle build
-on: [ push ]
+on:
+ push:
+ pull_request:
+ types: [opened, edited]
jobs:
- build-ubuntu:
- runs-on: ubuntu-20.04
-
+ build:
+ strategy:
+ matrix:
+ os: [ macOS-latest, windows-latest ]
+ runs-on: ${{matrix.os}}
+ timeout-minutes: 30
steps:
- - uses: actions/checkout@v2
+ - name: Checkout the repo
+ uses: actions/checkout@v2
- name: Set up JDK 11
- uses: actions/setup-java@v1
+ uses: DeLaGuardo/setup-graalvm@4.0
with:
- java-version: 11
- - name: Install build-essential
- run: |
- sudo apt install -y build-essential
- - name: Grant execute permission for gradlew
- run: chmod +x gradlew
- - name: Install Chrome
- run: |
- sudo apt install -y libappindicator1 fonts-liberation
- wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- sudo dpkg -i google-chrome*.deb
- - name: Cache gradle
- uses: actions/cache@v2
- with:
- path: |
- .gradle
- build
- ~/.gradle
- key: gradle
- restore-keys: gradle
-
- - name: Cache konan
- uses: actions/cache@v2
- with:
- path: |
- ~/.konan/dependencies
- ~/.konan/kotlin-native-prebuilt-linux-*
- key: ${{ runner.os }}-konan
- restore-keys: ${{ runner.os }}-konan
- - name: Build with Gradle
- run: ./gradlew -Dorg.gradle.daemon=false --build-cache build
-
- build-osx:
- runs-on: macos-latest
-
- steps:
- - uses: actions/checkout@v2
- - name: Set up JDK 11
- uses: actions/setup-java@v1
- with:
- java-version: 11
- - name: Grant execute permission for gradlew
- run: chmod +x gradlew
- - name: Cache gradle
- uses: actions/cache@v2
- with:
- path: |
- .gradle
- build
- ~/.gradle
- key: gradle
- restore-keys: gradle
-
- - name: Cache konan
- uses: actions/cache@v2
- with:
- path: |
- ~/.konan/dependencies
- ~/.konan/kotlin-native-prebuilt-macos-*
- key: ${{ runner.os }}-konan
- restore-keys: ${{ runner.os }}-konan
- - name: Build with Gradle
- run: sudo ./gradlew -Dorg.gradle.daemon=false --build-cache build
-
- build-windows:
- runs-on: windows-latest
-
- steps:
- - uses: actions/checkout@v2
- - name: Set up JDK 11
- uses: actions/setup-java@v1
- with:
- java-version: 11
- - name: Grant execute permission for gradlew
- run: chmod +x gradlew
+ graalvm: 21.1.0
+ java: java11
+ arch: amd64
- name: Add msys to path
+ if: matrix.os == 'windows-latest'
run: SETX PATH "%PATH%;C:\msys64\mingw64\bin"
- name: Cache gradle
uses: actions/cache@v2
with:
- path: |
- .gradle
- build
- ~/.gradle
- key: ${{ runner.os }}-gradle
- restore-keys: ${{ runner.os }}-gradle
-
+ path: ~/.gradle/caches
+ key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
- name: Cache konan
uses: actions/cache@v2
with:
- path: |
- ~/.konan/dependencies
- ~/.konan/kotlin-native-prebuilt-mingw-*
- key: ${{ runner.os }}-konan
- restore-keys: ${{ runner.os }}-konan
- - name: Build with Gradle
- run: ./gradlew --build-cache build
+ path: ~/.konan
+ key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: Build
+ run: ./gradlew build --no-daemon --stacktrace
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
new file mode 100644
index 000000000..86fdac6a6
--- /dev/null
+++ b/.github/workflows/pages.yml
@@ -0,0 +1,24 @@
+name: Dokka publication
+
+on:
+ push:
+ branches:
+ - master
+
+jobs:
+ build:
+ runs-on: ubuntu-20.04
+ steps:
+ - name: Checkout the repo
+ uses: actions/checkout@v2
+ - name: Set up JDK 11
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Build
+ run: ./gradlew dokkaHtmlMultiModule --no-daemon --no-parallel --stacktrace
+ - name: Deploy to GitHub Pages
+ uses: JamesIves/github-pages-deploy-action@4.1.0
+ with:
+ branch: gh-pages
+ folder: build/dokka/htmlMultiModule
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 000000000..c5c110e89
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,61 @@
+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.1.0
+ java: java11
+ arch: amd64
+ - name: Add msys to path
+ if: matrix.os == 'windows-latest'
+ run: SETX PATH "%PATH%;C:\msys64\mingw64\bin"
+ - name: Cache gradle
+ uses: actions/cache@v2
+ with:
+ path: ~/.gradle/caches
+ 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'
+ run: >
+ ./gradlew release --no-daemon
+ -Ppublishing.enabled=true
+ -Ppublishing.github.user=${{ secrets.PUBLISHING_GITHUB_USER }}
+ -Ppublishing.github.token=${{ secrets.PUBLISHING_GITHUB_TOKEN }}
+ -Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }}
+ -Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }}
+ - name: Publish Mac Artifacts
+ if: matrix.os == 'macOS-latest'
+ run: >
+ ./gradlew release --no-daemon
+ -Ppublishing.enabled=true
+ -Ppublishing.platform=macosX64
+ -Ppublishing.github.user=${{ secrets.PUBLISHING_GITHUB_USER }}
+ -Ppublishing.github.token=${{ secrets.PUBLISHING_GITHUB_TOKEN }}
+ -Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }}
+ -Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
deleted file mode 100644
index 743520885..000000000
--- a/.github/workflows/release.yml
+++ /dev/null
@@ -1,117 +0,0 @@
-name: Gradle release
-
-on:
- release:
- types:
- - created
-
-jobs:
- build-ubuntu:
- runs-on: ubuntu-20.04
-
- steps:
- - uses: actions/checkout@v2
- - name: Set up JDK 11
- uses: actions/setup-java@v1
- with:
- java-version: 11
- - name: Grant execute permission for gradlew
- run: chmod +x gradlew
- - name: Install Chrome
- run: |
- sudo apt install -y libappindicator1 fonts-liberation
- wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- sudo dpkg -i google-chrome*.deb
- - name: Cache gradle
- uses: actions/cache@v2
- with:
- path: |
- .gradle
- build
- ~/.gradle
- key: gradle
- restore-keys: gradle
-
- - name: Cache konan
- uses: actions/cache@v2
- with:
- path: |
- ~/.konan/dependencies
- ~/.konan/kotlin-native-prebuilt-linux-*
- key: ${{ runner.os }}-konan
- restore-keys: ${{ runner.os }}-konan
- - name: Build with Gradle
- run: ./gradlew -Dorg.gradle.daemon=false --build-cache build
- - name: Run release task
- run: ./gradlew release -PbintrayUser=${{ secrets.BINTRAY_USER }} -PbintrayApiKey=${{ secrets.BINTRAY_KEY }}
-
- build-osx:
- runs-on: macos-latest
-
- steps:
- - uses: actions/checkout@v2
- - name: Set up JDK 11
- uses: actions/setup-java@v1
- with:
- java-version: 11
- - name: Grant execute permission for gradlew
- run: chmod +x gradlew
- - name: Cache gradle
- uses: actions/cache@v2
- with:
- path: |
- .gradle
- build
- ~/.gradle
- key: gradle
- restore-keys: gradle
-
- - name: Cache konan
- uses: actions/cache@v2
- with:
- path: |
- ~/.konan/dependencies
- ~/.konan/kotlin-native-prebuilt-macos-*
- key: ${{ runner.os }}-konan
- restore-keys: ${{ runner.os }}-konan
- - name: Build with Gradle
- run: sudo ./gradlew -Dorg.gradle.daemon=false --build-cache build
- - name: Run release task
- run: ./gradlew release -PbintrayUser=${{ secrets.BINTRAY_USER }} -PbintrayApiKey=${{ secrets.BINTRAY_KEY }}
-
- build-windows:
- runs-on: windows-latest
-
- steps:
- - uses: actions/checkout@v2
- - name: Set up JDK 11
- uses: actions/setup-java@v1
- with:
- java-version: 11
- - name: Grant execute permission for gradlew
- run: chmod +x gradlew
- - name: Add msys to path
- run: SETX PATH "%PATH%;C:\msys64\mingw64\bin"
- - name: Cache gradle
- uses: actions/cache@v2
- with:
- path: |
- .gradle
- build
- ~/.gradle
- key: ${{ runner.os }}-gradle
- restore-keys: ${{ runner.os }}-gradle
-
- - name: Cache konan
- uses: actions/cache@v2
- with:
- path: |
- ~/.konan/dependencies
- ~/.konan/kotlin-native-prebuilt-mingw-*
- key: ${{ runner.os }}-konan
- restore-keys: ${{ runner.os }}-konan
- - name: Build with Gradle
- run: ./gradlew --build-cache build
- - name: Run release task
- run: ./gradlew release -PbintrayUser=${{ secrets.BINTRAY_USER }} -PbintrayApiKey=${{ secrets.BINTRAY_KEY }}
-
diff --git a/.gitignore b/.gitignore
index 07589aa00..d6c4af4e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,12 @@
.gradle
build/
out/
+
.idea/
+
+!.idea/copyright/
+!.idea/scopes/
+
.vscode/
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
diff --git a/.idea/copyright/kmath.xml b/.idea/copyright/kmath.xml
new file mode 100644
index 000000000..17e44e4d0
--- /dev/null
+++ b/.idea/copyright/kmath.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 000000000..b538bdf41
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/scopes/Apply_copyright.xml b/.idea/scopes/Apply_copyright.xml
new file mode 100644
index 000000000..0eb589133
--- /dev/null
+++ b/.idea/scopes/Apply_copyright.xml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c7033df7f..12540821e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,14 +2,55 @@
## [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
@@ -65,6 +106,7 @@
- `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)
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 261eeb9e9..000000000
--- a/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/README.md b/README.md
index e9cf64ea0..7645256d9 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,8 @@
[![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)
-
-Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
-
-Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion)
+[![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
@@ -14,6 +11,8 @@ Python's NumPy library. Later we found that kotlin is much more flexible languag
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)
@@ -41,7 +40,7 @@ KMath is a modular library. Different modules provide different features with di
* **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 genrally 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.
+* **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.
@@ -77,6 +76,12 @@ KMath is a modular library. Different modules provide different features with di
+* ### [benchmarks](benchmarks)
+>
+>
+> **Maturity**: EXPERIMENTAL
+
+
* ### [examples](examples)
>
>
@@ -86,15 +91,13 @@ KMath is a modular library. Different modules provide different features with di
* ### [kmath-ast](kmath-ast)
>
>
-> **Maturity**: PROTOTYPE
+> **Maturity**: EXPERIMENTAL
>
> **Features:**
-> - [expression-language](kmath-ast/src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
-> - [mst](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
-> - [mst-building](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
-> - [mst-interpreter](kmath-ast/src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
-> - [mst-jvm-codegen](kmath-ast/src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
-> - [mst-js-codegen](kmath-ast/src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
+> - [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
@@ -110,8 +113,8 @@ KMath is a modular library. Different modules provide different features with di
> **Maturity**: PROTOTYPE
>
> **Features:**
-> - [complex](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Complex.kt) : Complex Numbers
-> - [quaternion](kmath-complex/src/commonMain/kotlin/kscience/kmath/complex/Quaternion.kt) : Quaternions
+> - [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
@@ -121,15 +124,15 @@ KMath is a modular library. Different modules provide different features with di
> **Maturity**: DEVELOPMENT
>
> **Features:**
-> - [algebras](kmath-core/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : Algebraic structures like rings, spaces and fields.
-> - [nd](kmath-core/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Many-dimensional structures and operations on them.
-> - [linear](kmath-core/src/commonMain/kotlin/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/kscience/kmath/structures/Buffers.kt) : One-dimensional structure
-> - [expressions](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions) : By writing a single mathematical expression once, users will be able to apply different types of
+> - [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/kscience/kmath/domains) : Domains
-> - [autodif](kmath-core/src/commonMain/kotlin/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
+> - [domains](kmath-core/src/commonMain/kotlin/space/kscience/kmath/domains) : Domains
+> - [autodif](kmath-core/src/commonMain/kotlin/space/kscience/kmath/expressions/SimpleAutoDiff.kt) : Automatic differentiation
@@ -149,6 +152,12 @@ performance calculations to code generation.
>
>
> **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)
@@ -159,22 +168,23 @@ One can still use generic algebras though.
> **Maturity**: EXPERIMENTAL
>
> **Features:**
-> - [RealVector](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealVector.kt) : Numpy-like operations for Buffers/Points
-> - [RealMatrix](kmath-for-real/src/commonMain/kotlin/kscience/kmath/real/RealMatrix.kt) : Numpy-like operations for 2d real structures
-> - [grids](kmath-for-real/src/commonMain/kotlin/kscience/kmath/structures/grids.kt) : Uniform grid generators
+> - [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)
-> Functions and interpolation
+>
>
-> **Maturity**: PROTOTYPE
+> **Maturity**: EXPERIMENTAL
>
> **Features:**
-> - [piecewise](kmath-functions/Piecewise functions.) : src/commonMain/kotlin/kscience/kmath/functions/Piecewise.kt
-> - [polynomials](kmath-functions/Polynomial functions.) : src/commonMain/kotlin/kscience/kmath/functions/Polynomial.kt
-> - [linear interpolation](kmath-functions/Linear XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/LinearInterpolator.kt
-> - [spline interpolation](kmath-functions/Cubic spline XY interpolator.) : src/commonMain/kotlin/kscience/kmath/interpolation/SplineInterpolator.kt
+> - [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
@@ -190,27 +200,48 @@ One can still use generic algebras though.
> **Maturity**: PROTOTYPE
-* ### [kmath-kotlingrad](kmath-kotlingrad)
+* ### [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/DifferentiableMstExpression.kt) : MST based DifferentiableExpression.
+> - [differentiable-mst-expression](kmath-kotlingrad/src/main/kotlin/space/kscience/kmath/kotlingrad/DifferentiableMstExpression.kt) : Conversions between Kotlin∇'s SFun and MST
+
+
+
* ### [kmath-memory](kmath-memory)
-> An API and basic implementation for arranging objects in a continous memory block.
+> An API and basic implementation for arranging objects in a continuous memory block.
>
> **Maturity**: DEVELOPMENT
* ### [kmath-nd4j](kmath-nd4j)
-> ND4J NDStructure implementation and according NDAlgebra classes
+>
>
> **Maturity**: EXPERIMENTAL
>
> **Features:**
-> - [nd4jarraystructure](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/operations/Algebra.kt) : NDStructure wrapper for INDArray
-> - [nd4jarrayrings](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/NDStructure.kt) : Rings over Nd4jArrayStructure of Int and Long
-> - [nd4jarrayfields](kmath-nd4j/src/commonMain/kotlin/kscience/kmath/structures/Buffers.kt) : Fields over Nd4jArrayStructure of Float and Double
+> - [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
@@ -220,6 +251,24 @@ One can still use generic algebras though.
> **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/algebras/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)
>
>
@@ -245,6 +294,10 @@ cases. We expect the worst KMath benchmarks will perform better than native Pyth
native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
better than SciPy.
+## Requirements
+
+KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance.
+
### 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
@@ -256,8 +309,8 @@ repositories {
}
dependencies {
- api("kscience.kmath:kmath-core:() -> kotlin.Any")
- // api("kscience.kmath:kmath-core-jvm:() -> kotlin.Any") for jvm-specific version
+ api("space.kscience:kmath-core:0.3.0-dev-14")
+ // api("space.kscience:kmath-core-jvm:0.3.0-dev-14") for jvm-specific version
}
```
diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts
new file mode 100644
index 000000000..d96c5a8b6
--- /dev/null
+++ b/benchmarks/build.gradle.kts
@@ -0,0 +1,138 @@
+@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
new file mode 100644
index 000000000..ff933997f
--- /dev/null
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+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
new file mode 100644
index 000000000..749cd5e75
--- /dev/null
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BigIntBenchmark.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.benchmarks
+
+
+import kotlinx.benchmark.Blackhole
+import org.openjdk.jmh.annotations.Benchmark
+import org.openjdk.jmh.annotations.Scope
+import org.openjdk.jmh.annotations.State
+import space.kscience.kmath.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/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt
similarity index 53%
rename from examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt
rename to benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt
index 1afb4e52c..39819d407 100644
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/BufferBenchmark.kt
@@ -1,18 +1,23 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
package space.kscience.kmath.benchmarks
-import org.openjdk.jmh.annotations.Benchmark
-import org.openjdk.jmh.annotations.Scope
-import org.openjdk.jmh.annotations.State
+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
-import space.kscience.kmath.structures.RealBuffer
@State(Scope.Benchmark)
internal class BufferBenchmark {
@Benchmark
- fun genericRealBufferReadWrite() {
- val buffer = RealBuffer(size) { it.toDouble() }
+ fun genericDoubleBufferReadWrite() {
+ val buffer = DoubleBuffer(size) { it.toDouble() }
(0 until size).forEach {
buffer[it]
@@ -28,7 +33,7 @@ internal class BufferBenchmark {
}
}
- companion object {
- const val size: Int = 100
+ 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
new file mode 100644
index 000000000..2c5a03a97
--- /dev/null
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.benchmarks
+
+import kotlinx.benchmark.Benchmark
+import kotlinx.benchmark.Blackhole
+import kotlinx.benchmark.Scope
+import kotlinx.benchmark.State
+import space.kscience.kmath.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
new file mode 100644
index 000000000..0294f924b
--- /dev/null
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.benchmarks
+
+import kotlinx.benchmark.Benchmark
+import kotlinx.benchmark.Blackhole
+import kotlinx.benchmark.Scope
+import kotlinx.benchmark.State
+import space.kscience.kmath.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
new file mode 100644
index 000000000..24a730375
--- /dev/null
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/JafamaBenchmark.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+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.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) {
+ 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
new file mode 100644
index 000000000..7bb32af28
--- /dev/null
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/MatrixInverseBenchmark.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.benchmarks
+
+import kotlinx.benchmark.Benchmark
+import kotlinx.benchmark.Blackhole
+import kotlinx.benchmark.Scope
+import kotlinx.benchmark.State
+import space.kscience.kmath.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) {
+ with(CMLinearSpace) {
+ blackhole.consume(inverse(matrix))
+ }
+ }
+
+ @Benchmark
+ fun ejmlInverse(blackhole: Blackhole) {
+ with(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
new file mode 100644
index 000000000..5e0c6735f
--- /dev/null
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.benchmarks
+
+import kotlinx.benchmark.Benchmark
+import kotlinx.benchmark.Blackhole
+import kotlinx.benchmark.Scope
+import kotlinx.benchmark.State
+import space.kscience.kmath.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
new file mode 100644
index 000000000..d2359a791
--- /dev/null
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.benchmarks
+
+import kotlinx.benchmark.Benchmark
+import kotlinx.benchmark.Blackhole
+import kotlinx.benchmark.Scope
+import kotlinx.benchmark.State
+import 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
new file mode 100644
index 000000000..eac8634f5
--- /dev/null
+++ b/benchmarks/src/jvmMain/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.benchmarks
+
+import kotlinx.benchmark.Benchmark
+import kotlinx.benchmark.Blackhole
+import kotlinx.benchmark.Scope
+import kotlinx.benchmark.State
+import 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 83123765d..d0f6ced78 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,28 +1,46 @@
plugins {
id("ru.mipt.npm.gradle.project")
+ kotlin("jupyter.api") apply false
}
allprojects {
repositories {
- jcenter()
maven("https://clojars.org/repo")
- maven("https://dl.bintray.com/egor-bogomolov/astminer/")
- maven("https://dl.bintray.com/hotkeytlt/maven")
- maven("https://dl.bintray.com/kotlin/kotlin-eap")
- maven("https://dl.bintray.com/kotlin/kotlinx")
- maven("https://dl.bintray.com/mipt-npm/dev")
- maven("https://dl.bintray.com/mipt-npm/kscience")
maven("https://jitpack.io")
- maven("http://logicrunch.research.it.uu.se/maven/")
+ maven("http://logicrunch.research.it.uu.se/maven") {
+ isAllowInsecureProtocol = true
+ }
+ maven("https://oss.sonatype.org/content/repositories/snapshots")
mavenCentral()
}
group = "space.kscience"
- version = "0.2.0"
+ version = "0.3.0-dev-14"
}
subprojects {
- if (name.startsWith("kmath")) apply()
+ if (name.startsWith("kmath")) apply()
+
+ afterEvaluate {
+ tasks.withType {
+ dependsOn(tasks.getByName("assemble"))
+
+ dokkaSourceSets.all {
+ val readmeFile = File(this@subprojects.projectDir, "README.md")
+ if (readmeFile.exists()) includes.from(readmeFile.absolutePath)
+ externalDocumentationLink("https://ejml.org/javadoc/")
+ 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/")
+
+ externalDocumentationLink(
+ "https://breandan.net/kotlingrad/kotlingrad/",
+ "https://breandan.net/kotlingrad/kotlingrad/kotlingrad/package-list",
+ )
+ }
+ }
+ }
}
readme {
@@ -30,11 +48,11 @@ readme {
}
ksciencePublish {
- spaceRepo = "https://maven.pkg.jetbrains.space/mipt-npm/p/sci/maven"
- bintrayRepo = "kscience"
- githubProject = "kmath"
+ github("kmath")
+ space()
+ sonatype()
}
-apiValidation{
+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
new file mode 100644
index 000000000..fe69b05c6
--- /dev/null
+++ b/buildSrc/build.gradle.kts
@@ -0,0 +1,20 @@
+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.0")
+ api("org.jetbrains.kotlinx:kotlinx-benchmark-plugin:0.3.1")
+}
+
+kotlin.sourceSets.all {
+ languageSettings.useExperimentalAnnotation("kotlin.ExperimentalStdlibApi")
+}
diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt
new file mode 100644
index 000000000..eaa0f59d8
--- /dev/null
+++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/JmhReport.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.benchmarks
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class JmhReport(
+ val jmhVersion: String,
+ val benchmark: String,
+ val mode: String,
+ val threads: Int,
+ val forks: Int,
+ val jvm: String,
+ val jvmArgs: List,
+ val jdkVersion: String,
+ val vmName: String,
+ val vmVersion: String,
+ val warmupIterations: Int,
+ val warmupTime: String,
+ val warmupBatchSize: Int,
+ val measurementIterations: Int,
+ val measurementTime: String,
+ val measurementBatchSize: Int,
+ val params: Map = emptyMap(),
+ val primaryMetric: PrimaryMetric,
+ val secondaryMetrics: Map,
+) {
+ interface Metric {
+ val score: Double
+ val scoreError: Double
+ val scoreConfidence: List
+ val scorePercentiles: Map
+ val scoreUnit: String
+ }
+
+ @Serializable
+ data class PrimaryMetric(
+ override val score: Double,
+ override val scoreError: Double,
+ override val scoreConfidence: List,
+ override val scorePercentiles: Map,
+ override val scoreUnit: String,
+ val rawDataHistogram: List>>>? = null,
+ val rawData: List>? = null,
+ ) : Metric
+
+ @Serializable
+ data class SecondaryMetric(
+ override val score: Double,
+ override val scoreError: Double,
+ override val scoreConfidence: List,
+ override val scorePercentiles: Map,
+ override val scoreUnit: String,
+ val rawData: List>,
+ ) : Metric
+}
diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt
new file mode 100644
index 000000000..b55e1320e
--- /dev/null
+++ b/buildSrc/src/main/kotlin/space/kscience/kmath/benchmarks/addBenchmarkProperties.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.benchmarks
+
+import kotlinx.benchmark.gradle.BenchmarksExtension
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import org.gradle.api.Project
+import ru.mipt.npm.gradle.KScienceReadmeExtension
+import java.time.*
+import java.time.format.*
+import java.time.temporal.ChronoField.*
+
+private val ISO_DATE_TIME: DateTimeFormatter = DateTimeFormatterBuilder().run {
+ parseCaseInsensitive()
+ appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
+ appendLiteral('-')
+ appendValue(MONTH_OF_YEAR, 2)
+ appendLiteral('-')
+ appendValue(DAY_OF_MONTH, 2)
+ appendLiteral('T')
+ appendValue(HOUR_OF_DAY, 2)
+ appendLiteral('.')
+ appendValue(MINUTE_OF_HOUR, 2)
+ optionalStart()
+ appendLiteral('.')
+ appendValue(SECOND_OF_MINUTE, 2)
+ optionalStart()
+ appendFraction(NANO_OF_SECOND, 0, 9, true)
+ optionalStart()
+ appendOffsetId()
+ optionalStart()
+ appendLiteral('[')
+ parseCaseSensitive()
+ appendZoneRegionId()
+ appendLiteral(']')
+ toFormatter()
+}
+
+private fun noun(number: Number, singular: String, plural: String) = if (number.toLong() == 1L) singular else plural
+
+fun Project.addBenchmarkProperties() {
+ val benchmarksProject = this
+ rootProject.subprojects.forEach { p ->
+ p.extensions.findByType(KScienceReadmeExtension::class.java)?.run {
+ benchmarksProject.extensions.findByType(BenchmarksExtension::class.java)?.configurations?.forEach { cfg ->
+ property("benchmark${cfg.name.replaceFirstChar(Char::uppercase)}") {
+ val launches = benchmarksProject.buildDir.resolve("reports/benchmarks/${cfg.name}")
+
+ val resDirectory = launches.listFiles()?.maxByOrNull {
+ LocalDateTime.parse(it.name, ISO_DATE_TIME).atZone(ZoneId.systemDefault()).toInstant()
+ }
+
+ if (resDirectory == null) {
+ "> **Can't find appropriate benchmark data. Try generating readme files after running benchmarks**."
+ } else {
+ val reports =
+ Json.decodeFromString>(resDirectory.resolve("jvm.json").readText())
+
+ buildString {
+ appendLine("")
+ appendLine("")
+ appendLine("Report for benchmark configuration ${cfg.name}")
+ appendLine("")
+ appendLine()
+ val first = reports.first()
+
+ appendLine("* Run on ${first.vmName} (build ${first.vmVersion}) with Java process:")
+ appendLine()
+ appendLine("```")
+ appendLine("${first.jvm} ${
+ first.jvmArgs.joinToString(" ")
+ }")
+ appendLine("```")
+
+ appendLine("* JMH ${first.jmhVersion} was used in `${first.mode}` mode with ${first.warmupIterations} warmup ${
+ noun(first.warmupIterations, "iteration", "iterations")
+ } by ${first.warmupTime} and ${first.measurementIterations} measurement ${
+ noun(first.measurementIterations, "iteration", "iterations")
+ } by ${first.measurementTime}.")
+
+ appendLine()
+ appendLine("| Benchmark | Score |")
+ appendLine("|:---------:|:-----:|")
+
+ reports.forEach { report ->
+ appendLine("|`${report.benchmark}`|${report.primaryMetric.score} ± ${report.primaryMetric.scoreError} ${report.primaryMetric.scoreUnit}|")
+ }
+
+ appendLine("")
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt b/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt
new file mode 100644
index 000000000..5da7d0f67
--- /dev/null
+++ b/buildSrc/src/main/kotlin/space/kscience/kmath/ejml/codegen/ejmlCodegen.kt
@@ -0,0 +1,425 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+@file:Suppress("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(public override val origin: M) : EjmlVector<$type, M>(origin) {
+ init {
+ require(origin.numRows == 1) { "The origin matrix must have only one row to form a vector" }
+ }
+
+ public override operator fun get(index: Int): $type = origin[0, index]
+}"""
+ appendLine(text)
+ appendLine()
+}
+
+private fun Appendable.appendEjmlMatrix(type: String, ejmlMatrixType: String) {
+ val text = """/**
+ * [EjmlMatrix] specialization for [$type].
+ */
+public class Ejml${type}Matrix(public override val origin: M) : EjmlMatrix<$type, M>(origin) {
+ public override operator fun get(i: Int, j: Int): $type = origin[i, j]
+}"""
+ 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.
+ */
+ public override val elementAlgebra: $kmathAlgebra get() = $kmathAlgebra
+
+ @Suppress("UNCHECKED_CAST")
+ public override fun Matrix<${type}>.toEjml(): Ejml${type}Matrix<${ejmlMatrixType}> = when {
+ this is Ejml${type}Matrix<*> && origin is $ejmlMatrixType -> this as Ejml${type}Matrix<${ejmlMatrixType}>
+ else -> buildMatrix(rowNum, colNum) { i, j -> get(i, j) }
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ public override fun Point<${type}>.toEjml(): Ejml${type}Vector<${ejmlMatrixType}> = when {
+ this is Ejml${type}Vector<*> && origin is $ejmlMatrixType -> this as Ejml${type}Vector<${ejmlMatrixType}>
+ else -> Ejml${type}Vector(${ejmlMatrixType}(size, 1).also {
+ (0 until it.numRows).forEach { row -> it[row, 0] = get(row) }
+ })
+ }
+
+ public override fun buildMatrix(
+ 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()
+
+ public 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)
+
+ public override fun Matrix<${type}>.unaryMinus(): Matrix<${type}> = this * elementAlgebra { -one }
+
+ public override fun Matrix<${type}>.dot(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> {
+ val out = ${ejmlMatrixType}(1, 1)
+ CommonOps_${ops}.mult(toEjml().origin, other.toEjml().origin, out)
+ return out.wrapMatrix()
+ }
+
+ public override fun Matrix<${type}>.dot(vector: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> {
+ val out = ${ejmlMatrixType}(1, 1)
+ CommonOps_${ops}.mult(toEjml().origin, vector.toEjml().origin, out)
+ return out.wrapVector()
+ }
+
+ public override operator fun Matrix<${type}>.minus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> {
+ 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()
+ }
+
+ public override operator fun Matrix<${type}>.times(value: ${type}): Ejml${type}Matrix<${ejmlMatrixType}> {
+ val res = ${ejmlMatrixType}(1, 1)
+ CommonOps_${ops}.scale(value, toEjml().origin, res)
+ return res.wrapMatrix()
+ }
+
+ public override fun Point<${type}>.unaryMinus(): Ejml${type}Vector<${ejmlMatrixType}> {
+ val res = ${ejmlMatrixType}(1, 1)
+ CommonOps_${ops}.changeSign(toEjml().origin, res)
+ return res.wrapVector()
+ }
+
+ public override fun Matrix<${type}>.plus(other: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> {
+ 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()
+ }
+
+ public 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()
+ }
+
+ public 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()
+ }
+
+ public override fun ${type}.times(m: Matrix<${type}>): Ejml${type}Matrix<${ejmlMatrixType}> = m * this
+
+ public override fun Point<${type}>.times(value: ${type}): Ejml${type}Vector<${ejmlMatrixType}> {
+ val res = ${ejmlMatrixType}(1, 1)
+ CommonOps_${ops}.scale(value, toEjml().origin, res)
+ return res.wrapVector()
+ }
+
+ public override fun ${type}.times(v: Point<${type}>): Ejml${type}Vector<${ejmlMatrixType}> = v * this
+
+ @UnstableKMathAPI
+ public 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/LICENSE.txt 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/docs/algebra.md b/docs/algebra.md
index 6bfcde043..84693bb81 100644
--- a/docs/algebra.md
+++ b/docs/algebra.md
@@ -31,7 +31,7 @@ multiplication;
- [Ring](http://mathworld.wolfram.com/Ring.html) adds multiplication and its neutral element (i.e. 1);
- [Field](http://mathworld.wolfram.com/Field.html) adds division operation.
-A typical implementation of `Field` is the `RealField` which works on doubles, and `VectorSpace` for `Space`.
+A typical implementation of `Field` is the `DoubleField` which works on doubles, and `VectorSpace` for `Space`.
In some cases algebra context can hold additional operations like `exp` or `sin`, and then it inherits appropriate
interface. Also, contexts may have operations, which produce elements outside of the context. For example, `Matrix.dot`
diff --git a/docs/images/KM.svg b/docs/images/KM.svg
index 50126cbc5..83af21f35 100644
--- a/docs/images/KM.svg
+++ b/docs/images/KM.svg
@@ -13,27 +13,30 @@
version="1.1">image/svg+xml
+
+
+ image/svg+xml
+
+ image/svg+xml
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #### Artifact:
->
-> This module artifact: `${group}:${name}:${version}`.
->
-> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/${name}/images/download.svg) ](https://bintray.com/mipt-npm/kscience/${name}/_latestVersion)
->
-> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/${name}/images/download.svg) ](https://bintray.com/mipt-npm/dev/${name}/_latestVersion)
->
-> **Gradle:**
->
-> ```gradle
-> repositories {
-> maven { url 'https://repo.kotlin.link' }
-> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
-> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
->// Uncomment if repo.kotlin.link is unavailable
->// maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
->// maven { url 'https://dl.bintray.com/mipt-npm/dev' }
-> }
->
-> dependencies {
-> implementation '${group}:${name}:${version}'
-> }
-> ```
-> **Gradle Kotlin DSL:**
->
-> ```kotlin
-> repositories {
-> maven("https://repo.kotlin.link")
-> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
-> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
->// Uncomment if repo.kotlin.link is unavailable
->// maven("https://dl.bintray.com/mipt-npm/kscience")
->// maven("https://dl.bintray.com/mipt-npm/dev")
-> }
->
-> dependencies {
-> implementation("${group}:${name}:${version}")
-> }
-> ```
\ No newline at end of file
+## 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
index 10bc7aab1..bad11a31a 100644
--- a/docs/templates/README-TEMPLATE.md
+++ b/docs/templates/README-TEMPLATE.md
@@ -1,11 +1,8 @@
[![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)
-
-Bintray: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-core/_latestVersion)
-
-Bintray-dev: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-core/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-core/_latestVersion)
+[![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
@@ -14,6 +11,8 @@ Python's NumPy library. Later we found that kotlin is much more flexible languag
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)
@@ -41,7 +40,7 @@ KMath is a modular library. Different modules provide different features with di
* **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 genrally 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.
+* **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.
@@ -95,6 +94,10 @@ cases. We expect the worst KMath benchmarks will perform better than native Pyth
native/SciPy (mostly due to boxing operations on primitive numbers). The best performance of optimized parts could be
better than SciPy.
+## Requirements
+
+KMath currently relies on JDK 11 for compilation and execution of Kotlin-JVM part. We recommend to use GraalVM-CE 11 for execution in order to get better performance.
+
### 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
@@ -106,8 +109,8 @@ repositories {
}
dependencies {
- api("kscience.kmath:kmath-core:$version")
- // api("kscience.kmath:kmath-core-jvm:$version") for jvm-specific version
+ api("${group}:kmath-core:$version")
+ // api("${group}:kmath-core-jvm:$version") for jvm-specific version
}
```
diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts
index 77152dc0a..406b8f470 100644
--- a/examples/build.gradle.kts
+++ b/examples/build.gradle.kts
@@ -1,27 +1,16 @@
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-
plugins {
kotlin("jvm")
- kotlin("plugin.allopen")
- id("kotlinx.benchmark")
}
-allOpen.annotation("org.openjdk.jmh.annotations.State")
-sourceSets.register("benchmarks")
-
repositories {
- jcenter()
+ mavenCentral()
maven("https://repo.kotlin.link")
maven("https://clojars.org/repo")
- maven("https://dl.bintray.com/egor-bogomolov/astminer/")
- maven("https://dl.bintray.com/hotkeytlt/maven")
- maven("https://dl.bintray.com/kotlin/kotlin-eap")
- maven("https://dl.bintray.com/kotlin/kotlinx")
- maven("https://dl.bintray.com/mipt-npm/dev")
- maven("https://dl.bintray.com/mipt-npm/kscience")
maven("https://jitpack.io")
- maven("http://logicrunch.research.it.uu.se/maven/")
- mavenCentral()
+ maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-js-wrappers")
+ maven("http://logicrunch.research.it.uu.se/maven") {
+ isAllowInsecureProtocol = true
+ }
}
dependencies {
@@ -36,10 +25,10 @@ dependencies {
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.deeplearning4j:deeplearning4j-core:1.0.0-beta7")
implementation("org.nd4j:nd4j-native:1.0.0-beta7")
// uncomment if your system supports AVX2
@@ -52,59 +41,28 @@ dependencies {
// } else
implementation("org.nd4j:nd4j-native-platform:1.0.0-beta7")
- implementation("org.jetbrains.kotlinx:kotlinx-io:0.2.0-npm-dev-11")
- implementation("org.jetbrains.kotlinx:kotlinx.benchmark.runtime:0.2.0-dev-20")
implementation("org.slf4j:slf4j-simple:1.7.30")
-
// plotting
- implementation("kscience.plotlykt:plotlykt-server:0.3.1-dev")
-
- "benchmarksImplementation"("org.jetbrains.kotlinx:kotlinx.benchmark.runtime-jvm:0.2.0-dev-20")
- "benchmarksImplementation"(sourceSets.main.get().output + sourceSets.main.get().runtimeClasspath)
-}
-
-// Configure benchmark
-benchmark {
- // Setup configurations
- targets.register("benchmarks")
- // This one matches sourceSet name above
-
- configurations.register("buffer") {
- warmups = 1 // 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
- include("BufferBenchmark")
- }
-
- configurations.register("dot") {
- warmups = 1 // 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
- include("DotBenchmark")
- }
-
- configurations.register("expressions") {
- warmups = 1 // 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
- include("ExpressionsInterpretersBenchmark")
- }
+ implementation("space.kscience:plotlykt-server:0.4.0")
+ //jafama
+ implementation(project(":kmath-jafama"))
}
kotlin.sourceSets.all {
with(languageSettings) {
useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts")
useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
+ useExperimentalAnnotation("space.kscience.kmath.misc.UnstableKMathAPI")
}
}
-tasks.withType {
- kotlinOptions.jvmTarget = "11"
+tasks.withType {
+ kotlinOptions{
+ jvmTarget = "11"
+ freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all" + "-Xopt-in=kotlin.RequiresOptIn"
+ }
}
-readme{
+readme {
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt
deleted file mode 100644
index 535778844..000000000
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ArrayBenchmark.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package space.kscience.kmath.benchmarks
-
-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)
-internal class ArrayBenchmark {
- @Benchmark
- fun benchmarkArrayRead() {
- var res = 0
- for (i in 1..space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size) res += space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.array[space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size - i]
- }
-
- @Benchmark
- fun benchmarkBufferRead() {
- var res = 0
- for (i in 1..space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size) res += space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.arrayBuffer[space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size - i]
- }
-
- @Benchmark
- fun nativeBufferRead() {
- var res = 0
- for (i in 1..space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size) res += space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.nativeBuffer[space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size - i]
- }
-
- companion object {
- const val size: Int = 1000
- val array: IntArray = IntArray(space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size) { it }
- val arrayBuffer: IntBuffer = IntBuffer.wrap(space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.array)
- val nativeBuffer: IntBuffer = IntBuffer.allocate(space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size).also { for (i in 0 until space.kscience.kmath.benchmarks.ArrayBenchmark.Companion.size) it.put(i, i) }
- }
-}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt
deleted file mode 100644
index 39eeb24d3..000000000
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/DotBenchmark.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-package space.kscience.kmath.benchmarks
-
-import kotlinx.benchmark.Benchmark
-import org.openjdk.jmh.annotations.Scope
-import org.openjdk.jmh.annotations.State
-import space.kscience.kmath.commons.linear.CMMatrixContext
-import space.kscience.kmath.ejml.EjmlMatrixContext
-import space.kscience.kmath.linear.BufferMatrixContext
-import space.kscience.kmath.linear.Matrix
-import space.kscience.kmath.linear.RealMatrixContext
-import space.kscience.kmath.operations.RealField
-import space.kscience.kmath.operations.invoke
-import space.kscience.kmath.structures.Buffer
-import kotlin.random.Random
-
-@State(Scope.Benchmark)
-internal class DotBenchmark {
- companion object {
- 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 }
-
- val cmMatrix1 = CMMatrixContext { matrix1.toCM() }
- val cmMatrix2 = CMMatrixContext { matrix2.toCM() }
-
- val ejmlMatrix1 = EjmlMatrixContext { matrix1.toEjml() }
- val ejmlMatrix2 = EjmlMatrixContext { matrix2.toEjml() }
- }
-
- @Benchmark
- fun cmDot() {
- CMMatrixContext {
- cmMatrix1 dot cmMatrix2
- }
- }
-
- @Benchmark
- fun ejmlDot() {
- EjmlMatrixContext {
- ejmlMatrix1 dot ejmlMatrix2
- }
- }
-
- @Benchmark
- fun ejmlDotWithConversion() {
- EjmlMatrixContext {
- matrix1 dot matrix2
- }
- }
-
- @Benchmark
- fun bufferedDot() {
- BufferMatrixContext(RealField, Buffer.Companion::real).invoke {
- matrix1 dot matrix2
- }
- }
-
- @Benchmark
- fun realDot() {
- RealMatrixContext {
- matrix1 dot matrix2
- }
- }
-}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
deleted file mode 100644
index a9c0fe703..000000000
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ExpressionsInterpretersBenchmark.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-package space.kscience.kmath.benchmarks
-
-import org.openjdk.jmh.annotations.Benchmark
-import org.openjdk.jmh.annotations.Scope
-import org.openjdk.jmh.annotations.State
-import space.kscience.kmath.asm.compile
-import space.kscience.kmath.ast.mstInField
-import space.kscience.kmath.expressions.Expression
-import space.kscience.kmath.expressions.expressionInField
-import space.kscience.kmath.expressions.invoke
-import space.kscience.kmath.expressions.symbol
-import space.kscience.kmath.operations.Field
-import space.kscience.kmath.operations.RealField
-import space.kscience.kmath.operations.bindSymbol
-import kotlin.random.Random
-
-@State(Scope.Benchmark)
-internal class ExpressionsInterpretersBenchmark {
- private val algebra: Field = RealField
- val x by symbol
-
- @Benchmark
- fun functionalExpression() {
- val expr = algebra.expressionInField {
- val x = bindSymbol(x)
- x * const(2.0) + const(2.0) / x - const(16.0)
- }
-
- invokeAndSum(expr)
- }
-
- @Benchmark
- fun mstExpression() {
- val expr = algebra.mstInField {
- val x = bindSymbol(x)
- x * 2.0 + 2.0 / x - 16.0
- }
-
- invokeAndSum(expr)
- }
-
- @Benchmark
- fun asmExpression() {
- val expr = algebra.mstInField {
- val x = bindSymbol(x)
- x * 2.0 + 2.0 / x - 16.0
- }.compile()
-
- invokeAndSum(expr)
- }
-
- @Benchmark
- fun rawExpression() {
- val expr = Expression { args ->
- val x = args.getValue(x)
- x * 2.0 + 2.0 / x - 16.0
- }
- invokeAndSum(expr)
- }
-
- private fun invokeAndSum(expr: Expression) {
- val random = Random(0)
- var sum = 0.0
-
- repeat(1000000) {
- sum += expr(x to random.nextDouble())
- }
-
- println(sum)
- }
-}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/LinearAlgebraBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/LinearAlgebraBenchmark.kt
deleted file mode 100644
index 22e735e12..000000000
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/LinearAlgebraBenchmark.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-package space.kscience.kmath.benchmarks
-
-import kotlinx.benchmark.Benchmark
-import org.openjdk.jmh.annotations.Scope
-import org.openjdk.jmh.annotations.State
-import space.kscience.kmath.commons.linear.CMMatrixContext
-import space.kscience.kmath.commons.linear.CMMatrixContext.dot
-import space.kscience.kmath.commons.linear.inverse
-import space.kscience.kmath.ejml.EjmlMatrixContext
-import space.kscience.kmath.ejml.inverse
-import space.kscience.kmath.linear.Matrix
-import space.kscience.kmath.linear.MatrixContext
-import space.kscience.kmath.linear.inverseWithLup
-import space.kscience.kmath.linear.real
-import kotlin.random.Random
-
-@State(Scope.Benchmark)
-internal class LinearAlgebraBenchmark {
- companion object {
- 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
- }
-
- @Benchmark
- fun kmathLupInversion() {
- MatrixContext.real.inverseWithLup(matrix)
- }
-
- @Benchmark
- fun cmLUPInversion() {
- with(CMMatrixContext) {
- inverse(matrix)
- }
- }
-
- @Benchmark
- fun ejmlInverse() {
- with(EjmlMatrixContext) {
- inverse(matrix)
- }
- }
-}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt
deleted file mode 100644
index 5bcc09cdb..000000000
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/NDFieldBenchmark.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package space.kscience.kmath.benchmarks
-
-import org.openjdk.jmh.annotations.Benchmark
-import org.openjdk.jmh.annotations.Scope
-import org.openjdk.jmh.annotations.State
-import space.kscience.kmath.nd.*
-import space.kscience.kmath.operations.RealField
-import space.kscience.kmath.structures.Buffer
-
-@State(Scope.Benchmark)
-internal class NDFieldBenchmark {
- @Benchmark
- fun autoFieldAdd() {
- with(autoField) {
- var res: NDStructure = one
- repeat(n) { res += one }
- }
- }
-
- @Benchmark
- fun specializedFieldAdd() {
- with(specializedField) {
- var res: NDStructure = one
- repeat(n) { res += 1.0 }
- }
- }
-
-
- @Benchmark
- fun boxingFieldAdd() {
- with(genericField) {
- var res: NDStructure = one
- repeat(n) { res += 1.0 }
- }
- }
-
- companion object {
- const val dim: Int = 1000
- const val n: Int = 100
- val autoField = NDAlgebra.auto(RealField, dim, dim)
- val specializedField: RealNDField = NDAlgebra.real(dim, dim)
- val genericField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
- }
-}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt
deleted file mode 100644
index 370258bc6..000000000
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorBenchmark.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package space.kscience.kmath.benchmarks
-
-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 space.kscience.kmath.nd.*
-import space.kscience.kmath.operations.RealField
-import space.kscience.kmath.viktor.ViktorNDField
-
-@State(Scope.Benchmark)
-internal class ViktorBenchmark {
- final val dim: Int = 1000
- final val n: Int = 100
-
- // automatically build context most suited for given type.
- final val autoField: NDField = NDAlgebra.auto(RealField, dim, dim)
- final val realField: RealNDField = NDAlgebra.real(dim, dim)
- final val viktorField: ViktorNDField = ViktorNDField(dim, dim)
-
- @Benchmark
- fun automaticFieldAddition() {
- with(autoField) {
- var res: NDStructure = one
- repeat(n) { res += 1.0 }
- }
- }
-
- @Benchmark
- fun realFieldAddition() {
- with(realField) {
- var res: NDStructure = one
- repeat(n) { res += 1.0 }
- }
- }
-
- @Benchmark
- fun viktorFieldAddition() {
- with(viktorField) {
- var res = one
- repeat(n) { res += 1.0 }
- }
- }
-
- @Benchmark
- fun rawViktor() {
- val one = F64Array.full(init = 1.0, shape = intArrayOf(dim, dim))
- var res = one
- repeat(n) { res = res + one }
- }
-}
diff --git a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt b/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt
deleted file mode 100644
index 9f99b002a..000000000
--- a/examples/src/benchmarks/kotlin/space/kscience/kmath/benchmarks/ViktorLogBenchmark.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-package space.kscience.kmath.benchmarks
-
-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 space.kscience.kmath.nd.*
-import space.kscience.kmath.operations.RealField
-import space.kscience.kmath.viktor.ViktorNDField
-
-@State(Scope.Benchmark)
-internal class ViktorLogBenchmark {
- final val dim: Int = 1000
- final val n: Int = 100
-
- // automatically build context most suited for given type.
- final val autoField: NDField = NDAlgebra.auto(RealField, dim, dim)
- final val realField: RealNDField = NDAlgebra.real(dim, dim)
- final val viktorField: ViktorNDField = ViktorNDField(intArrayOf(dim, dim))
-
-
- @Benchmark
- fun realFieldLog() {
- with(realField) {
- val fortyTwo = produce { 42.0 }
- var res = one
- repeat(n) { res = ln(fortyTwo) }
- }
- }
-
- @Benchmark
- fun viktorFieldLog() {
- with(viktorField) {
- val fortyTwo = produce { 42.0 }
- var res = one
- repeat(n) { res = ln(fortyTwo) }
- }
- }
-
- @Benchmark
- fun rawViktorLog() {
- val fortyTwo = F64Array.full(dim, dim, init = 42.0)
- var res: F64Array
- repeat(n) {
- res = fortyTwo.log()
- }
- }
-}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt
new file mode 100644
index 000000000..e16769464
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/ast/astRendering.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.ast
+
+import space.kscience.kmath.ast.rendering.FeaturedMathRendererWithPostProcess
+import space.kscience.kmath.ast.rendering.LatexSyntaxRenderer
+import space.kscience.kmath.ast.rendering.MathMLSyntaxRenderer
+import space.kscience.kmath.ast.rendering.renderWithStringBuilder
+
+public 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
index ee0f4a492..96c9856cf 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/ast/expressions.kt
@@ -1,15 +1,22 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
package space.kscience.kmath.ast
-import space.kscience.kmath.expressions.invoke
-import space.kscience.kmath.operations.RealField
+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 = RealField.mstInField {
- val x = bindSymbol("x")
- x * 2.0 + 2.0 / x - 16.0
+ val expr = MstField {
+ x * 2.0 + number(2.0) / x - 16.0
}
- repeat(10000000){
- expr.invoke("x" to 1.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
index 16304a458..6ceaa962a 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/ast/kotlingradSupport.kt
@@ -1,24 +1,27 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
package space.kscience.kmath.ast
-import space.kscience.kmath.asm.compile
import space.kscience.kmath.expressions.derivative
import space.kscience.kmath.expressions.invoke
-import space.kscience.kmath.expressions.symbol
-import space.kscience.kmath.kotlingrad.differentiable
-import space.kscience.kmath.operations.RealField
+import space.kscience.kmath.expressions.Symbol.Companion.x
+import space.kscience.kmath.expressions.toExpression
+import space.kscience.kmath.kotlingrad.toKotlingradExpression
+import space.kscience.kmath.operations.DoubleField
/**
* In this example, x^2-4*x-44 function is differentiated with Kotlin∇, and the autodiff result is compared with
- * valid derivative.
+ * valid derivative in a certain point.
*/
fun main() {
- val x by symbol
-
- val actualDerivative = MstExpression(RealField, "x^2-4*x-44".parseMath())
- .differentiable()
+ val actualDerivative = "x^2-4*x-44"
+ .parseMath()
+ .toKotlingradExpression(DoubleField)
.derivative(x)
- .compile()
- val expectedDerivative = MstExpression(RealField, "2*x-4".parseMath()).compile()
- assert(actualDerivative("x" to 123.0) == expectedDerivative("x" to 123.0))
+ val expectedDerivative = "2*x-4".parseMath().toExpression(DoubleField)
+ check(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0))
}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt
new file mode 100644
index 000000000..a9eca0500
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/ast/symjaSupport.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.ast
+
+import space.kscience.kmath.expressions.Symbol.Companion.x
+import space.kscience.kmath.expressions.derivative
+import space.kscience.kmath.expressions.invoke
+import space.kscience.kmath.expressions.toExpression
+import space.kscience.kmath.operations.DoubleField
+import space.kscience.kmath.symja.toSymjaExpression
+
+/**
+ * In this example, x^2-4*x-44 function is differentiated with Symja, and the autodiff result is compared with
+ * valid derivative in a certain point.
+ */
+fun main() {
+ val actualDerivative = "x^2-4*x-44"
+ .parseMath()
+ .toSymjaExpression(DoubleField)
+ .derivative(x)
+
+ val expectedDerivative = "2*x-4".parseMath().toExpression(DoubleField)
+ check(actualDerivative(x to 123.0) == expectedDerivative(x to 123.0))
+}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt
index 63b819dc9..5e64235e3 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/commons/fit/fitWithAutoDiff.kt
@@ -1,19 +1,27 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
package space.kscience.kmath.commons.fit
import kotlinx.html.br
import kotlinx.html.h3
-import kscience.plotly.*
-import kscience.plotly.models.ScatterMode
-import kscience.plotly.models.TraceValues
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.real.RealVector
+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.*
+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
@@ -26,17 +34,16 @@ private val c by symbol
/**
* Shortcut to use buffers in plotly
*/
-operator fun TraceValues.invoke(vector: RealVector) {
+operator fun TraceValues.invoke(vector: DoubleVector) {
numbers = vector.asIterable()
}
/**
* Least squares fie with auto-differentiation. Uses `kmath-commons` and `kmath-for-real` modules.
*/
-fun main() {
-
+suspend fun main() {
//A generator for a normally distributed values
- val generator = Distribution.normal()
+ val generator = NormalDistribution(2.0, 7.0)
//A chain/flow of random values with the given seed
val chain = generator.sample(RandomGenerator.default(112667))
@@ -49,7 +56,7 @@ fun main() {
//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.nextDouble() * sqrt(value)
+ value + chain.next() * sqrt(value)
}
// this will also work, but less effective:
// val y = x.pow(2)+ x + 1 + chain.nextDouble()
@@ -58,10 +65,10 @@ fun main() {
val yErr = y.map { sqrt(it) }//RealVector.same(x.size, sigma)
// compute differentiable chi^2 sum for given model ax^2 + bx + c
- val chi2 = Fitting.chiSquared(x, y, yErr) { x1 ->
+ val chi2 = FunctionOptimization.chiSquared(x, y, yErr) { x1 ->
//bind variables to autodiff context
- val a = bind(a)
- val b = bind(b)
+ 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
@@ -90,13 +97,13 @@ fun main() {
}
}
br()
- h3{
+ h3 {
+"Fit result: $result"
}
- h3{
+ h3 {
+"Chi2/dof = ${result.value / (x.size - 3)}"
}
}
page.makeFile()
-}
\ No newline at end of file
+}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt
new file mode 100644
index 000000000..f60b1ab45
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/functions/integrate.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+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
new file mode 100644
index 000000000..8dbc7b7a4
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolate.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.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
new file mode 100644
index 000000000..33973c880
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/functions/interpolateSquare.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.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
new file mode 100644
index 000000000..2619d3d74
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/functions/matrixIntegration.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.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/KMathaJafamaDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/jafama/KMathaJafamaDemo.kt
new file mode 100644
index 000000000..879aab08f
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/jafama/KMathaJafamaDemo.kt
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.jafama
+
+import net.jafama.FastMath
+
+
+fun main(){
+ val a = JafamaDoubleField.number(2.0)
+ val b = StrictJafamaDoubleField.power(FastMath.E,a)
+
+ println(JafamaDoubleField.add(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
new file mode 100644
index 000000000..a01ea7fe2
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/linear/gradient.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.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
index 6d5903cae..51f439612 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/operations/BigIntDemo.kt
@@ -1,3 +1,8 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
package space.kscience.kmath.operations
fun main() {
diff --git a/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt
index 5330d9e40..f99dd8c0e 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/operations/ComplexDemo.kt
@@ -1,18 +1,23 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
package space.kscience.kmath.operations
import space.kscience.kmath.complex.Complex
import space.kscience.kmath.complex.complex
-import space.kscience.kmath.nd.NDAlgebra
+import space.kscience.kmath.nd.AlgebraND
fun main() {
// 2d element
- val element = NDAlgebra.complex(2, 2).produce { (i, j) ->
+ 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(NDAlgebra.complex(8)) {
+ val result = with(AlgebraND.complex(8)) {
val a = produce { (it) -> i * it - it.toDouble() }
val b = 3
val c = Complex(1.0, 1.0)
diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt
index 1761ed1b5..8e3cdf86f 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionBenchmark.kt
@@ -1,23 +1,29 @@
-package kscience.kmath.commons.prob
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.stat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
-import org.apache.commons.rng.sampling.distribution.ZigguratNormalizedGaussianSampler
+import org.apache.commons.rng.sampling.distribution.BoxMullerNormalizedGaussianSampler
import org.apache.commons.rng.simple.RandomSource
-import space.kscience.kmath.stat.*
+import space.kscience.kmath.samplers.GaussianSampler
import java.time.Duration
import java.time.Instant
+import org.apache.commons.rng.sampling.distribution.GaussianSampler as CMGaussianSampler
-private fun runChain(): Duration {
+private suspend fun runKMathChained(): Duration {
val generator = RandomGenerator.fromSource(RandomSource.MT, 123L)
- val normal = Distribution.normal(NormalSamplerMethod.Ziggurat)
+ val normal = GaussianSampler(7.0, 2.0)
val chain = normal.sample(generator)
val startTime = Instant.now()
var sum = 0.0
repeat(10000001) { counter ->
- sum += chain.nextDouble()
+ sum += chain.next()
if (counter % 100000 == 0) {
val duration = Duration.between(startTime, Instant.now())
@@ -29,9 +35,15 @@ private fun runChain(): Duration {
return Duration.between(startTime, Instant.now())
}
-private fun runDirect(): Duration {
- val provider = RandomSource.create(RandomSource.MT, 123L)
- val sampler = ZigguratNormalizedGaussianSampler(provider)
+private fun runApacheDirect(): Duration {
+ val rng = RandomSource.create(RandomSource.MT, 123L)
+
+ val sampler = CMGaussianSampler.of(
+ BoxMullerNormalizedGaussianSampler.of(rng),
+ 7.0,
+ 2.0
+ )
+
val startTime = Instant.now()
var sum = 0.0
@@ -51,11 +63,9 @@ private fun runDirect(): Duration {
/**
* Comparing chain sampling performance with direct sampling performance
*/
-fun main() {
- runBlocking(Dispatchers.Default) {
- val chainJob = async { runChain() }
- val directJob = async { runDirect() }
- println("Chain: ${chainJob.await()}")
- println("Direct: ${directJob.await()}")
- }
+fun main(): Unit = runBlocking(Dispatchers.Default) {
+ val directJob = async { runApacheDirect() }
+ val chainJob = async { runKMathChained() }
+ println("KMath Chained: ${chainJob.await()}")
+ println("Apache Direct: ${directJob.await()}")
}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt
index 47b8d8111..b319766e3 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/stat/DistributionDemo.kt
@@ -1,16 +1,22 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
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
/**
- * The state of distribution averager
+ * The state of distribution averager.
*/
private data class AveragingChainState(var num: Int = 0, var value: Double = 0.0)
/**
- * Averaging
+ * Averaging.
*/
private fun Chain.mean(): Chain = collectWithState(AveragingChainState(), { it.copy() }) { chain ->
val next = chain.next()
@@ -21,7 +27,7 @@ private fun Chain.mean(): Chain = collectWithState(AveragingChai
fun main() {
- val normal = Distribution.normal()
+ val normal = NormalDistribution(0.0, 2.0)
val chain = normal.sample(RandomGenerator.default).mean()
runBlocking {
@@ -32,4 +38,4 @@ fun main() {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt
index b8cbc9a57..b30165f71 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/ComplexND.kt
@@ -1,11 +1,16 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
@file:Suppress("unused")
package space.kscience.kmath.structures
import space.kscience.kmath.complex.*
import space.kscience.kmath.linear.transpose
-import space.kscience.kmath.nd.NDAlgebra
-import space.kscience.kmath.nd.NDStructure
+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
@@ -15,12 +20,12 @@ fun main() {
val dim = 1000
val n = 1000
- val realField = NDAlgebra.real(dim, dim)
- val complexField: ComplexNDField = NDAlgebra.complex(dim, dim)
+ val realField = AlgebraND.real(dim, dim)
+ val complexField: ComplexFieldND = AlgebraND.complex(dim, dim)
val realTime = measureTimeMillis {
realField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) {
res += 1.0
}
@@ -31,7 +36,7 @@ fun main() {
val complexTime = measureTimeMillis {
complexField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) {
res += 1.0
}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt
index 10fb3cb3d..501bf98db 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/NDField.kt
@@ -1,10 +1,16 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
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.RealField
+import space.kscience.kmath.operations.DoubleField
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.viktor.ViktorNDField
import kotlin.contracts.InvocationKind
@@ -17,6 +23,7 @@ internal inline fun measureAndPrint(title: String, block: () -> Unit) {
println("$title completed in $time millis")
}
+@OptIn(DelicateCoroutinesApi::class)
fun main() {
// initializing Nd4j
Nd4j.zeros(0)
@@ -24,56 +31,56 @@ fun main() {
val n = 1000
// automatically build context most suited for given type.
- val autoField = NDAlgebra.auto(RealField, dim, dim)
+ val autoField = AlgebraND.auto(DoubleField, dim, dim)
// specialized nd-field for Double. It works as generic Double field as well
- val realField = NDAlgebra.real(dim, dim)
+ val realField = AlgebraND.real(dim, dim)
//A generic boxing field. It should be used for objects, not primitives.
- val boxingField = NDAlgebra.field(RealField, Buffer.Companion::boxing, dim, dim)
+ 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)
+ val viktorField = ViktorNDField(dim, dim)
//parallel processing based on Java Streams
- val parallelField = NDAlgebra.realWithStream(dim,dim)
+ val parallelField = AlgebraND.realWithStream(dim, dim)
measureAndPrint("Boxing addition") {
boxingField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Specialized addition") {
realField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Nd4j specialized addition") {
nd4jField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Viktor addition") {
viktorField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Parallel stream addition") {
parallelField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
}
}
measureAndPrint("Automatic field addition") {
autoField {
- var res: NDStructure = one
+ var res: StructureND = one
repeat(n) { res += 1.0 }
}
}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/ParallelRealNDField.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/ParallelRealNDField.kt
deleted file mode 100644
index 111cfec80..000000000
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/ParallelRealNDField.kt
+++ /dev/null
@@ -1,103 +0,0 @@
-package space.kscience.kmath.structures
-
-import space.kscience.kmath.misc.UnstableKMathAPI
-import space.kscience.kmath.nd.*
-import space.kscience.kmath.operations.ExtendedField
-import space.kscience.kmath.operations.RealField
-import space.kscience.kmath.operations.RingWithNumbers
-import java.util.*
-import java.util.stream.IntStream
-
-/**
- * A demonstration implementation of NDField over Real using Java [DoubleStream] for parallel execution
- */
-@OptIn(UnstableKMathAPI::class)
-class StreamRealNDField(
- override val shape: IntArray,
-) : NDField,
- RingWithNumbers>,
- ExtendedField> {
-
- private val strides = DefaultStrides(shape)
- override val elementContext: RealField get() = RealField
- override val zero: NDBuffer by lazy { produce { zero } }
- override val one: NDBuffer by lazy { produce { one } }
-
- override fun number(value: Number): NDBuffer {
- val d = value.toDouble() // minimize conversions
- return produce { d }
- }
-
- private val NDStructure.buffer: RealBuffer
- get() = when {
- !shape.contentEquals(this@StreamRealNDField.shape) -> throw ShapeMismatchException(
- this@StreamRealNDField.shape,
- shape
- )
- this is NDBuffer && this.strides == this@StreamRealNDField.strides -> this.buffer as RealBuffer
- else -> RealBuffer(strides.linearSize) { offset -> get(strides.index(offset)) }
- }
-
-
- override fun produce(initializer: RealField.(IntArray) -> Double): NDBuffer {
- val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
- val index = strides.index(offset)
- RealField.initializer(index)
- }.toArray()
-
- return NDBuffer(strides, array.asBuffer())
- }
-
- override fun NDStructure.map(
- transform: RealField.(Double) -> Double,
- ): NDBuffer {
- val array = Arrays.stream(buffer.array).parallel().map { RealField.transform(it) }.toArray()
- return NDBuffer(strides, array.asBuffer())
- }
-
- override fun NDStructure.mapIndexed(
- transform: RealField.(index: IntArray, Double) -> Double,
- ): NDBuffer {
- val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
- RealField.transform(
- strides.index(offset),
- buffer.array[offset]
- )
- }.toArray()
-
- return NDBuffer(strides, array.asBuffer())
- }
-
- override fun combine(
- a: NDStructure,
- b: NDStructure,
- transform: RealField.(Double, Double) -> Double,
- ): NDBuffer {
- val array = IntStream.range(0, strides.linearSize).parallel().mapToDouble { offset ->
- RealField.transform(a.buffer.array[offset], b.buffer.array[offset])
- }.toArray()
- return NDBuffer(strides, array.asBuffer())
- }
-
- override fun power(arg: NDStructure, pow: Number): NDBuffer = arg.map() { power(it, pow) }
-
- override fun exp(arg: NDStructure): NDBuffer = arg.map() { exp(it) }
-
- override fun ln(arg: NDStructure): NDBuffer = arg.map() { ln(it) }
-
- override fun sin(arg: NDStructure): NDBuffer = arg.map() { sin(it) }
- override fun cos(arg: NDStructure): NDBuffer = arg.map() { cos(it) }
- override fun tan(arg: NDStructure): NDBuffer = arg.map() { tan(it) }
- override fun asin(arg: NDStructure): NDBuffer = arg.map() { asin(it) }
- override fun acos(arg: NDStructure): NDBuffer = arg.map() { acos(it) }
- override fun atan(arg: NDStructure): NDBuffer = arg.map() { atan(it) }
-
- override fun sinh(arg: NDStructure): NDBuffer = arg.map() { sinh(it) }
- override fun cosh(arg: NDStructure): NDBuffer = arg.map() { cosh(it) }
- override fun tanh(arg: NDStructure): NDBuffer = arg.map() { tanh(it) }
- override fun asinh(arg: NDStructure): NDBuffer = arg.map() { asinh(it) }
- override fun acosh(arg: NDStructure): NDBuffer = arg.map() { acosh(it) }
- override fun atanh(arg: NDStructure): NDBuffer = arg.map() { atanh(it) }
-}
-
-fun NDAlgebra.Companion.realWithStream(vararg shape: Int): StreamRealNDField = StreamRealNDField(shape)
\ No newline at end of file
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt
new file mode 100644
index 000000000..d53cfa9b9
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StreamDoubleFieldND.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.structures
+
+import space.kscience.kmath.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/StructureReadBenchmark.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt
index 7f6d73394..0d5358354 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureReadBenchmark.kt
@@ -1,16 +1,21 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
package space.kscience.kmath.structures
+import space.kscience.kmath.nd.BufferND
import space.kscience.kmath.nd.DefaultStrides
-import space.kscience.kmath.nd.NDBuffer
import kotlin.system.measureTimeMillis
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
fun main() {
val n = 6000
val array = DoubleArray(n * n) { 1.0 }
- val buffer = RealBuffer(array)
+ val buffer = DoubleBuffer(array)
val strides = DefaultStrides(intArrayOf(n, n))
- val structure = NDBuffer(strides, buffer)
+ val structure = BufferND(strides, buffer)
measureTimeMillis {
var res = 0.0
@@ -34,4 +39,4 @@ fun main() {
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/space/kscience/kmath/structures/StructureWriteBenchmark.kt
index 13d6f00e4..dea7095a8 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/StructureWriteBenchmark.kt
@@ -1,13 +1,18 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
package space.kscience.kmath.structures
-import space.kscience.kmath.nd.NDStructure
+import space.kscience.kmath.nd.StructureND
import space.kscience.kmath.nd.mapToBuffer
import kotlin.system.measureTimeMillis
@Suppress("UNUSED_VARIABLE")
fun main() {
val n = 6000
- val structure = NDStructure.build(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
+ val structure = StructureND.buffered(intArrayOf(n, n), Buffer.Companion::auto) { 1.0 }
structure.mapToBuffer { it + 1 } // warm-up
val time1 = measureTimeMillis { val res = structure.mapToBuffer { it + 1 } }
println("Structure mapping finished in $time1 millis")
@@ -20,10 +25,10 @@ fun main() {
println("Array mapping finished in $time2 millis")
- val buffer = RealBuffer(DoubleArray(n * n) { 1.0 })
+ val buffer = DoubleBuffer(DoubleArray(n * n) { 1.0 })
val time3 = measureTimeMillis {
- val target = RealBuffer(DoubleArray(n * n))
+ val target = DoubleBuffer(DoubleArray(n * n))
val res = array.forEachIndexed { index, value ->
target[index] = value + 1
}
diff --git a/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt b/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt
index fdd631238..955f86fa9 100644
--- a/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt
+++ b/examples/src/main/kotlin/space/kscience/kmath/structures/typeSafeDimensions.kt
@@ -1,3 +1,8 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
package space.kscience.kmath.structures
import space.kscience.kmath.dimensions.D2
@@ -5,7 +10,7 @@ import space.kscience.kmath.dimensions.D3
import space.kscience.kmath.dimensions.DMatrixContext
import space.kscience.kmath.dimensions.Dimension
-private fun DMatrixContext.simple() {
+private fun DMatrixContext.simple() {
val m1 = produce { i, j -> (i + j).toDouble() }
val m2 = produce { i, j -> (i + j).toDouble() }
@@ -17,7 +22,7 @@ private object D5 : Dimension {
override val dim: UInt = 5u
}
-private fun DMatrixContext.custom() {
+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() }
diff --git a/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt
new file mode 100644
index 000000000..74795cc68
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/DataSetNormalization.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.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) // rows 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
new file mode 100644
index 000000000..6453ca44e
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/LinearSystemSolvingWithLUP.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.tensors
+
+import 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 that 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
new file mode 100644
index 000000000..b262bee02
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/NeuralNetwork.kt
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.tensors
+
+import 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) // rows 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
new file mode 100644
index 000000000..b42602988
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/OLSWithSVD.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.tensors
+
+import 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
new file mode 100644
index 000000000..411e048d7
--- /dev/null
+++ b/examples/src/main/kotlin/space/kscience/kmath/tensors/PCA.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt 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
index 88b90f27b..3aaade368 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,8 +1,13 @@
+#
+# Copyright 2018-2021 KMath contributors.
+# Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+#
+
kotlin.code.style=official
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.mpp.stability.nowarn=true
kotlin.native.enableDependencyPropagation=false
kotlin.parallel.tasks.in.project=true
-org.gradle.jvmargs=-XX:MaxMetaspaceSize=512m
+org.gradle.configureondemand=true
+org.gradle.jvmargs=-XX:MaxMetaspaceSize=2G
org.gradle.parallel=true
-systemProp.org.gradle.internal.publish.checksums.insecure=true
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index e708b1c02..7454180f2 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 2a563242c..05679dc3c 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 4f906e0c8..744e882ed 100755
--- a/gradlew
+++ b/gradlew
@@ -72,7 +72,7 @@ case "`uname`" in
Darwin* )
darwin=true
;;
- MINGW* )
+ MSYS* | MINGW* )
msys=true
;;
NONSTOP* )
diff --git a/kmath-ast/README.md b/kmath-ast/README.md
index e52f0fa96..c3c4c38a1 100644
--- a/kmath-ast/README.md
+++ b/kmath-ast/README.md
@@ -1,75 +1,65 @@
-# Abstract Syntax Tree Expression Representation and Operations (`kmath-ast`)
+# Module kmath-ast
-This subproject implements the following features:
+Performance and visualization extensions to MST API.
- - [expression-language](src/jvmMain/kotlin/kscience/kmath/ast/parser.kt) : Expression language and its parser
- - [mst](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation
- - [mst-building](src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt) : MST building algebraic structure
- - [mst-interpreter](src/commonMain/kotlin/kscience/kmath/ast/MST.kt) : MST interpreter
- - [mst-jvm-codegen](src/jvmMain/kotlin/kscience/kmath/asm/asm.kt) : Dynamic MST to JVM bytecode compiler
- - [mst-js-codegen](src/jsMain/kotlin/kscience/kmath/estree/estree.kt) : Dynamic MST to JS compiler
+ - [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:
->
-> This module artifact: `space.kscience:kmath-ast:0.2.0`.
->
-> Bintray release version: [ ![Download](https://api.bintray.com/packages/mipt-npm/kscience/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/kscience/kmath-ast/_latestVersion)
->
-> Bintray development version: [ ![Download](https://api.bintray.com/packages/mipt-npm/dev/kmath-ast/images/download.svg) ](https://bintray.com/mipt-npm/dev/kmath-ast/_latestVersion)
->
-> **Gradle:**
->
-> ```gradle
-> repositories {
-> maven { url 'https://repo.kotlin.link' }
-> maven { url 'https://dl.bintray.com/hotkeytlt/maven' }
-> maven { url "https://dl.bintray.com/kotlin/kotlin-eap" } // include for builds based on kotlin-eap
->// Uncomment if repo.kotlin.link is unavailable
->// maven { url 'https://dl.bintray.com/mipt-npm/kscience' }
->// maven { url 'https://dl.bintray.com/mipt-npm/dev' }
-> }
->
-> dependencies {
-> implementation 'space.kscience:kmath-ast:0.2.0'
-> }
-> ```
-> **Gradle Kotlin DSL:**
->
-> ```kotlin
-> repositories {
-> maven("https://repo.kotlin.link")
-> maven("https://dl.bintray.com/kotlin/kotlin-eap") // include for builds based on kotlin-eap
-> maven("https://dl.bintray.com/hotkeytlt/maven") // required for a
->// Uncomment if repo.kotlin.link is unavailable
->// maven("https://dl.bintray.com/mipt-npm/kscience")
->// maven("https://dl.bintray.com/mipt-npm/dev")
-> }
->
-> dependencies {
-> implementation("space.kscience:kmath-ast:0.2.0")
-> }
-> ```
+## 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.
+`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
-RealField.mstInField { symbol("x") + 2 }.compile()
+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:
+... 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;
@@ -79,7 +69,7 @@ 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);
+ return (Double) ((Function2) this.constants[0]).invoke((Double) MapIntrinsics.getOrFail(arguments, "x"), 2);
}
public AsmCompiledExpression_45045_0(Object[] constants) {
@@ -89,19 +79,10 @@ public final class AsmCompiledExpression_45045_0 implements Expression {
```
-### Example Usage
-
-This API extends MST and MstExpression, so you may optimize as both of them:
-
-```kotlin
-RealField.mstInField { symbol("x") + 2 }.compile()
-RealField.expression("x+2".parseMath())
-```
-
#### Known issues
-- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid
- class loading overhead.
+- 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
@@ -109,17 +90,149 @@ RealField.expression("x+2".parseMath())
A similar feature is also available on JS.
```kotlin
-RealField.mstInField { symbol("x") + 2 }.compile()
+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);
+ return constants[1](constants[0](arguments, "x"), 2);
};
```
+JS also supports very 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
-- This feature uses `eval` which can be unavailable in several environments.
+- 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
+
+```
+
+
+
+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
index 5b764459c..9de7e9980 100644
--- a/kmath-ast/build.gradle.kts
+++ b/kmath-ast/build.gradle.kts
@@ -1,7 +1,6 @@
-import ru.mipt.npm.gradle.Maturity
-
plugins {
- id("ru.mipt.npm.gradle.mpp")
+ kotlin("multiplatform")
+ id("ru.mipt.npm.gradle.common")
}
kotlin.js {
@@ -19,8 +18,13 @@ kotlin.js {
}
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"))
}
}
@@ -33,15 +37,15 @@ kotlin.sourceSets {
jsMain {
dependencies {
- implementation(npm("astring", "1.7.0"))
+ implementation(npm("astring", "1.7.5"))
+ implementation(npm("binaryen", "101.0.0"))
+ implementation(npm("js-base64", "3.6.1"))
}
}
jvmMain {
dependencies {
- api("com.github.h0tk3y.betterParse:better-parse:0.4.1")
- implementation("org.ow2.asm:asm:9.1")
- implementation("org.ow2.asm:asm-commons:9.1")
+ implementation("org.ow2.asm:asm-commons:9.2")
}
}
}
@@ -52,42 +56,26 @@ tasks.dokkaHtml {
}
readme {
- maturity = Maturity.PROTOTYPE
+ maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
propertyByTemplate("artifact", rootProject.file("docs/templates/ARTIFACT-TEMPLATE.md"))
feature(
id = "expression-language",
- description = "Expression language and its parser",
- ref = "src/jvmMain/kotlin/kscience/kmath/ast/parser.kt"
- )
-
- feature(
- id = "mst",
- description = "MST (Mathematical Syntax Tree) as expression language's syntax intermediate representation",
- ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
- )
-
- feature(
- id = "mst-building",
- description = "MST building algebraic structure",
- ref = "src/commonMain/kotlin/kscience/kmath/ast/MstAlgebra.kt"
- )
-
- feature(
- id = "mst-interpreter",
- description = "MST interpreter",
- ref = "src/commonMain/kotlin/kscience/kmath/ast/MST.kt"
- )
+ ref = "src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt"
+ ) { "Expression language and its parser" }
feature(
id = "mst-jvm-codegen",
- description = "Dynamic MST to JVM bytecode compiler",
- ref = "src/jvmMain/kotlin/kscience/kmath/asm/asm.kt"
- )
+ ref = "src/jvmMain/kotlin/space/kscience/kmath/asm/asm.kt"
+ ) { "Dynamic MST to JVM bytecode compiler" }
feature(
id = "mst-js-codegen",
- description = "Dynamic MST to JS compiler",
- ref = "src/jsMain/kotlin/kscience/kmath/estree/estree.kt"
- )
+ 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
index 2712cba75..b90f8ff08 100644
--- a/kmath-ast/docs/README-TEMPLATE.md
+++ b/kmath-ast/docs/README-TEMPLATE.md
@@ -1,6 +1,6 @@
-# Abstract Syntax Tree Expression Representation and Operations (`kmath-ast`)
+# Module kmath-ast
-This subproject implements the following features:
+Performance and visualization extensions to MST API.
${features}
@@ -10,21 +10,27 @@ ${artifact}
### 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.
+`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
-RealField.mstInField { symbol("x") + 2 }.compile()
+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:
+... 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;
@@ -34,7 +40,7 @@ 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);
+ return (Double) ((Function2) this.constants[0]).invoke((Double) MapIntrinsics.getOrFail(arguments, "x"), 2);
}
public AsmCompiledExpression_45045_0(Object[] constants) {
@@ -44,19 +50,10 @@ public final class AsmCompiledExpression_45045_0 implements Expression {
```
-### Example Usage
-
-This API extends MST and MstExpression, so you may optimize as both of them:
-
-```kotlin
-RealField.mstInField { symbol("x") + 2 }.compile()
-RealField.expression("x+2".parseMath())
-```
-
#### Known issues
-- The same classes may be generated and loaded twice, so it is recommended to cache compiled expressions to avoid
- class loading overhead.
+- 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
@@ -64,17 +61,149 @@ RealField.expression("x+2".parseMath())
A similar feature is also available on JS.
```kotlin
-RealField.mstInField { symbol("x") + 2 }.compile()
+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);
+ return constants[1](constants[0](arguments, "x"), 2);
};
```
+JS also supports very 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
-- This feature uses `eval` which can be unavailable in several environments.
+- 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
+
+```
+
+
+
+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/src/commonMain/kotlin/space/kscience/kmath/ast/MstExpression.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstExpression.kt
deleted file mode 100644
index 412dde32c..000000000
--- a/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/MstExpression.kt
+++ /dev/null
@@ -1,136 +0,0 @@
-package space.kscience.kmath.ast
-
-import space.kscience.kmath.expressions.*
-import space.kscience.kmath.operations.*
-import kotlin.contracts.InvocationKind
-import kotlin.contracts.contract
-
-/**
- * The expression evaluates MST on-flight. Should be much faster than functional expression, but slower than
- * ASM-generated expressions.
- *
- * @property algebra the algebra that provides operations.
- * @property mst the [MST] node.
- * @author Alexander Nozik
- */
-public class MstExpression>(public val algebra: A, public val mst: MST) : Expression {
- private inner class InnerAlgebra(val arguments: Map) : NumericAlgebra {
- override fun bindSymbol(value: String): T = try {
- algebra.bindSymbol(value)
- } catch (ignored: IllegalStateException) {
- null
- } ?: arguments.getValue(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")
- }
-
- override operator fun invoke(arguments: Map): T = InnerAlgebra(arguments).evaluate(mst)
-}
-
-/**
- * Builds [MstExpression] over [Algebra].
- *
- * @author Alexander Nozik
- */
-public inline fun , E : Algebra> A.mst(
- mstAlgebra: E,
- block: E.() -> MST,
-): MstExpression = MstExpression(this, mstAlgebra.block())
-
-/**
- * Builds [MstExpression] over [Space].
- *
- * @author Alexander Nozik
- */
-public inline fun > A.mstInSpace(block: MstSpace.() -> MST): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return MstExpression(this, MstSpace.block())
-}
-
-/**
- * Builds [MstExpression] over [Ring].
- *
- * @author Alexander Nozik
- */
-public inline fun > A.mstInRing(block: MstRing.() -> MST): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return MstExpression(this, MstRing.block())
-}
-
-/**
- * Builds [MstExpression] over [Field].
- *
- * @author Alexander Nozik
- */
-public inline fun > A.mstInField(block: MstField.() -> MST): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return MstExpression(this, MstField.block())
-}
-
-/**
- * Builds [MstExpression] over [ExtendedField].
- *
- * @author Iaroslav Postovalov
- */
-public inline fun > A.mstInExtendedField(block: MstExtendedField.() -> MST): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return MstExpression(this, MstExtendedField.block())
-}
-
-/**
- * Builds [MstExpression] over [FunctionalExpressionSpace].
- *
- * @author Alexander Nozik
- */
-public inline fun > FunctionalExpressionSpace.mstInSpace(block: MstSpace.() -> MST): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return algebra.mstInSpace(block)
-}
-
-/**
- * Builds [MstExpression] over [FunctionalExpressionRing].
- *
- * @author Alexander Nozik
- */
-public inline fun > FunctionalExpressionRing.mstInRing(block: MstRing.() -> MST): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return algebra.mstInRing(block)
-}
-
-/**
- * Builds [MstExpression] over [FunctionalExpressionField].
- *
- * @author Alexander Nozik
- */
-public inline fun > FunctionalExpressionField.mstInField(block: MstField.() -> MST): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return algebra.mstInField(block)
-}
-
-/**
- * Builds [MstExpression] over [FunctionalExpressionExtendedField].
- *
- * @author Iaroslav Postovalov
- */
-public inline fun > FunctionalExpressionExtendedField.mstInExtendedField(
- block: MstExtendedField.() -> MST,
-): MstExpression {
- contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
- return algebra.mstInExtendedField(block)
-}
diff --git a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt
similarity index 85%
rename from kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt
rename to kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt
index be4aff34f..5201fec38 100644
--- a/kmath-ast/src/jvmMain/kotlin/space/kscience/kmath/ast/parser.kt
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/parser.kt
@@ -1,4 +1,7 @@
-// TODO move to common when https://github.com/h0tk3y/better-parse/pull/37 is merged
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
package space.kscience.kmath.ast
@@ -13,18 +16,20 @@ 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
-import space.kscience.kmath.operations.SpaceOperations
/**
* better-parse implementation of grammar defined in the ArithmeticsEvaluator.g4.
*
- * @author Alexander Nozik and Iaroslav Postovalov
+ * @author Alexander Nozik
+ * @author Iaroslav Postovalov
*/
public object ArithmeticsEvaluator : Grammar() {
- // TODO replace with "...".toRegex() when better-parse 0.4.1 is released
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("(")
@@ -38,7 +43,7 @@ public object ArithmeticsEvaluator : Grammar() {
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 { MST.Symbolic(text) }
+ 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) }
@@ -55,7 +60,7 @@ public object ArithmeticsEvaluator : Grammar() {
.or(binaryFunction)
.or(unaryFunction)
.or(singular)
- .or(-minus and parser(ArithmeticsEvaluator::term) map { MST.Unary(SpaceOperations.MINUS_OPERATION, it) })
+ .or(-minus and parser(ArithmeticsEvaluator::term) map { MST.Unary(GroupOperations.MINUS_OPERATION, it) })
.or(-lpar and parser(ArithmeticsEvaluator::subSumChain) and -rpar)
private val powChain: Parser by leftAssociative(term = term, operator = pow) { a, _, b ->
@@ -77,9 +82,9 @@ public object ArithmeticsEvaluator : Grammar() {
operator = plus or minus use TokenMatch::type
) { a, op, b ->
if (op == plus)
- MST.Binary(SpaceOperations.PLUS_OPERATION, a, b)
+ MST.Binary(GroupOperations.PLUS_OPERATION, a, b)
else
- MST.Binary(SpaceOperations.MINUS_OPERATION, a, b)
+ MST.Binary(GroupOperations.MINUS_OPERATION, a, b)
}
override val rootParser: Parser by subSumChain
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
new file mode 100644
index 000000000..01717b0f9
--- /dev/null
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/LatexSyntaxRenderer.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.ast.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 {
+ public 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
new file mode 100644
index 000000000..cda8e2322
--- /dev/null
+++ b/kmath-ast/src/commonMain/kotlin/space/kscience/kmath/ast/rendering/MathMLSyntaxRenderer.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2018-2021 KMath contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package space.kscience.kmath.ast.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 {
+ public override fun render(node: MathSyntax, output: Appendable) {
+ output.append("